/// <see cref="ITerrainObjectType.CheckConstraints"/> public RCSet <RCIntVector> CheckConstraints(IMapAccess map, RCIntVector position) { if (map == null) { throw new ArgumentNullException("map"); } if (position == RCIntVector.Undefined) { throw new ArgumentNullException("position"); } /// Check against the constraints defined by this terrain object type. RCSet <RCIntVector> retList = new RCSet <RCIntVector>(); foreach (ITerrainObjectConstraint contraint in this.constraints) { retList.UnionWith(contraint.Check(map, position)); } for (int quadX = 0; quadX < this.quadraticSize.X; quadX++) { for (int quadY = 0; quadY < this.quadraticSize.Y; quadY++) { RCIntVector relQuadCoords = new RCIntVector(quadX, quadY); RCIntVector absQuadCoords = position + relQuadCoords; if (absQuadCoords.X < 0 || absQuadCoords.X >= map.Size.X || absQuadCoords.Y < 0 || absQuadCoords.Y >= map.Size.Y) { /// Intersection with the boundaries of the map. retList.Add(relQuadCoords); } } } return(retList); }
/// <summary> /// Adds the given map object and all of its cutting quadratic tiles into the update lists. /// </summary> /// <param name="mapObj">The map object to add.</param> /// <param name="mapObjectUpdateList">The map object update list.</param> /// <param name="quadTileUpdateList">The quadratic update list.</param> private void AddMapObjectToUpdate(MapObject mapObj, RCSet <MapObject> mapObjectUpdateList, RCSet <IQuadTile> quadTileUpdateList) { if (mapObj != null && mapObjectUpdateList.Add(mapObj)) { for (int col = mapObj.QuadraticPosition.Left; col < mapObj.QuadraticPosition.Right; col++) { for (int row = mapObj.QuadraticPosition.Top; row < mapObj.QuadraticPosition.Bottom; row++) { IQuadTile quadTileToUpdate = this.ActiveScenario.Map.GetQuadTile(new RCIntVector(col, row)); if (quadTileToUpdate != null && (this.fowCacheMatrix.GetFullFowFlagsAtQuadTile(quadTileToUpdate.MapCoords) != FOWTileFlagsEnum.None || this.fowCacheMatrix.GetPartialFowFlagsAtQuadTile(quadTileToUpdate.MapCoords) != FOWTileFlagsEnum.None)) { quadTileUpdateList.Add(quadTileToUpdate); } } } if (mapObj.QuadraticShadowPosition != RCIntRectangle.Undefined) { for (int col = mapObj.QuadraticShadowPosition.Left; col < mapObj.QuadraticShadowPosition.Right; col++) { for (int row = mapObj.QuadraticShadowPosition.Top; row < mapObj.QuadraticShadowPosition.Bottom; row++) { IQuadTile quadTileToUpdate = this.ActiveScenario.Map.GetQuadTile(new RCIntVector(col, row)); if (quadTileToUpdate != null && (this.fowCacheMatrix.GetFullFowFlagsAtQuadTile(quadTileToUpdate.MapCoords) != FOWTileFlagsEnum.None || this.fowCacheMatrix.GetPartialFowFlagsAtQuadTile(quadTileToUpdate.MapCoords) != FOWTileFlagsEnum.None)) { quadTileUpdateList.Add(quadTileToUpdate); } } } } } }
/// <summary> /// Calculates the velocity graph. /// </summary> private static Dictionary <RCNumVector, RCSet <RCNumVector> > CalculateVelocityGraph(List <RCNumVector> basisVectors, RCNumber maxSpeed, int accelerationDuration) { if (basisVectors == null) { throw new ArgumentNullException("basisVectors"); } if (basisVectors.Count == 0) { throw new ArgumentException("Empty basis vector list!", "basisVectors"); } if (maxSpeed < 0) { throw new ArgumentOutOfRangeException("maxSpeed", "Maximum speed cannot be negative!"); } if (accelerationDuration < 1) { throw new ArgumentOutOfRangeException("accelerationDuration", "Acceleration duration must be at least 1!"); } if (maxSpeed == 0) { /// Trivial case. return(new Dictionary <RCNumVector, RCSet <RCNumVector> > { { new RCNumVector(0, 0), new RCSet <RCNumVector>() } }); } /// First we calculate every possible velocity vectors and put them into a 2D array where the first coordinate /// is the index of the corresponding speed and the second coordinate is the index of the corresponding /// basis vector. In parallel we put the calculated vectors into the velocity graph with empty reachability /// lists. Those lists will be filled in a second step. Dictionary <RCNumVector, RCSet <RCNumVector> > velocityGraph = new Dictionary <RCNumVector, RCSet <RCNumVector> >(); RCNumVector[,] velocityVectors = new RCNumVector[accelerationDuration + 1, basisVectors.Count]; velocityVectors[0, 0] = new RCNumVector(0, 0); velocityGraph.Add(new RCNumVector(0, 0), new RCSet <RCNumVector>()); RCNumber speedIncrement = maxSpeed / accelerationDuration; for (int spdIdx = 1; spdIdx <= accelerationDuration; spdIdx++) { RCNumber speed = speedIncrement * spdIdx; for (int basisVectIdx = 0; basisVectIdx < basisVectors.Count; basisVectIdx++) { RCNumVector velocityVector = basisVectors[basisVectIdx] * speed; velocityVectors[spdIdx, basisVectIdx] = velocityVector; velocityGraph.Add(velocityVector, new RCSet <RCNumVector>()); } } /// Collect the velocities reachable from the (0, 0) vector. velocityGraph[velocityVectors[0, 0]].Add(velocityVectors[0, 0]); for (int basisVectIdx = 0; basisVectIdx < basisVectors.Count; basisVectIdx++) { velocityGraph[velocityVectors[0, 0]].Add(velocityVectors[1, basisVectIdx]); } /// Collect the velocities reachable from the longest velocities. for (int basisVectIdx = 0; basisVectIdx < basisVectors.Count; basisVectIdx++) { RCSet <RCNumVector> reachableVelocityList = velocityGraph[velocityVectors[accelerationDuration, basisVectIdx]]; reachableVelocityList.Add(velocityVectors[accelerationDuration, basisVectIdx]); reachableVelocityList.Add(velocityVectors[accelerationDuration, (basisVectIdx + 1) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[accelerationDuration, (basisVectIdx - 1 + basisVectors.Count) % basisVectors.Count]); if (accelerationDuration == 1) { reachableVelocityList.Add(velocityVectors[0, 0]); } else { reachableVelocityList.Add(velocityVectors[accelerationDuration - 1, basisVectIdx]); reachableVelocityList.Add(velocityVectors[accelerationDuration - 1, (basisVectIdx + 1) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[accelerationDuration - 1, (basisVectIdx - 1 + basisVectors.Count) % basisVectors.Count]); } } if (accelerationDuration > 1) { /// Collect the velocities reachable from the shortest velocities. for (int basisVectIdx = 0; basisVectIdx < basisVectors.Count; basisVectIdx++) { RCSet <RCNumVector> reachableVelocityList = velocityGraph[velocityVectors[1, basisVectIdx]]; reachableVelocityList.Add(velocityVectors[0, 0]); reachableVelocityList.Add(velocityVectors[1, basisVectIdx]); reachableVelocityList.Add(velocityVectors[1, (basisVectIdx + 1) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[1, (basisVectIdx - 1 + basisVectors.Count) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[2, basisVectIdx]); reachableVelocityList.Add(velocityVectors[2, (basisVectIdx + 1) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[2, (basisVectIdx - 1 + basisVectors.Count) % basisVectors.Count]); } /// Collect the velocities reachable from any other velocities. for (int spdIdx = 2; spdIdx < accelerationDuration; spdIdx++) { for (int basisVectIdx = 0; basisVectIdx < basisVectors.Count; basisVectIdx++) { RCSet <RCNumVector> reachableVelocityList = velocityGraph[velocityVectors[spdIdx, basisVectIdx]]; reachableVelocityList.Add(velocityVectors[spdIdx - 1, basisVectIdx]); reachableVelocityList.Add(velocityVectors[spdIdx - 1, (basisVectIdx + 1) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[spdIdx - 1, (basisVectIdx - 1 + basisVectors.Count) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[spdIdx, basisVectIdx]); reachableVelocityList.Add(velocityVectors[spdIdx, (basisVectIdx + 1) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[spdIdx, (basisVectIdx - 1 + basisVectors.Count) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[spdIdx + 1, basisVectIdx]); reachableVelocityList.Add(velocityVectors[spdIdx + 1, (basisVectIdx + 1) % basisVectors.Count]); reachableVelocityList.Add(velocityVectors[spdIdx + 1, (basisVectIdx - 1 + basisVectors.Count) % basisVectors.Count]); } } } return(velocityGraph); }
/// <see cref="CommandInputListener.TryComplete"/> public override CommandInputListener.CompletionResultEnum TryComplete() { if (this.CommandBuilder.TargetPosition == RCNumVector.Undefined) { /// No target position selected -> completion failed! return(CompletionResultEnum.FailedAndCancel); } if (this.placeSelectedBuilding) { /// Target position selected for the selected building -> validate the selected position. int[] currentSelection = this.selectionManagerBC.CurrentSelection.ToArray(); if (currentSelection.Length != 1) { throw new InvalidOperationException("The number of the currently selected entities must be 1!"); } Building selectedBuilding = this.scenarioManagerBC.ActiveScenario.GetElement <Building>(currentSelection[0]); if (selectedBuilding == null) { throw new InvalidOperationException("The currently selected entity doesn't exist or is not a building!"); } if (this.addonTypeName == null) { /// There is no additional addon type. if (this.fogOfWarBC.CheckPlacementConstraints(selectedBuilding, (RCIntVector)this.CommandBuilder.TargetPosition, new RCSet <Entity>()).Count == 0) { /// Selected position is OK. return(CommandInputListener.CompletionResultEnum.Succeeded); } else { /// Selected position is invalid -> completion failed! this.CommandBuilder.TargetPosition = RCNumVector.Undefined; return(CommandInputListener.CompletionResultEnum.FailedButContinue); } } else { /// Additional addon type has to be checked as well. IAddonType addonType = this.scenarioManagerBC.Metadata.GetAddonType(this.addonTypeName); if (addonType == null) { throw new InvalidOperationException(string.Format("Addon type '{0}' is not defined in the metadata!", this.addonTypeName)); } if (this.fogOfWarBC.CheckPlacementConstraints(selectedBuilding, (RCIntVector)this.CommandBuilder.TargetPosition, addonType, new RCSet <Entity>()).Count == 0) { /// Selected position is OK. return(CommandInputListener.CompletionResultEnum.Succeeded); } else { /// Selected position is invalid -> completion failed! this.CommandBuilder.TargetPosition = RCNumVector.Undefined; return(CommandInputListener.CompletionResultEnum.FailedButContinue); } } } else if (this.buildingTypeName != null) { /// Target position selected for a given building type -> validate the selected position. IBuildingType buildingType = this.scenarioManagerBC.Metadata.GetBuildingType(this.buildingTypeName); if (buildingType == null) { throw new InvalidOperationException(string.Format("Building type '{0}' is not defined in the metadata!", this.buildingTypeName)); } RCSet <Entity> currentSelection = new RCSet <Entity>(); foreach (int selectedEntityID in this.selectionManagerBC.CurrentSelection) { currentSelection.Add(this.scenarioManagerBC.ActiveScenario.GetElement <Entity>(selectedEntityID)); } if (this.addonTypeName == null) { if (this.fogOfWarBC.CheckPlacementConstraints(buildingType, (RCIntVector)this.CommandBuilder.TargetPosition, currentSelection).Count == 0) { /// Selected position is OK. return(CompletionResultEnum.Succeeded); } else { /// Selected position is invalid -> completion failed! this.CommandBuilder.TargetPosition = RCNumVector.Undefined; return(CompletionResultEnum.FailedButContinue); } } else { /// Additional addon type has to be checked as well. IAddonType addonType = this.scenarioManagerBC.Metadata.GetAddonType(this.addonTypeName); if (addonType == null) { throw new InvalidOperationException(string.Format("Addon type '{0}' is not defined in the metadata!", this.addonTypeName)); } if (this.fogOfWarBC.CheckPlacementConstraints(buildingType, (RCIntVector)this.CommandBuilder.TargetPosition, addonType, currentSelection).Count == 0) { /// Selected position is OK. return(CommandInputListener.CompletionResultEnum.Succeeded); } else { /// Selected position is invalid -> completion failed! this.CommandBuilder.TargetPosition = RCNumVector.Undefined; return(CommandInputListener.CompletionResultEnum.FailedButContinue); } } } else { /// A point selected on the map -> validate the selected position. return(CommandInputListener.CompletionResultEnum.Succeeded); } }
/// <see cref="IObjectPlacementView.GetObjectPlacementBox"/> public ObjectPlacementBox GetObjectPlacementBox(RCIntVector position) { /// Calculate the top-left quadratic coordinates based on the retrieved object rectangles relative to the quadratic tile at the incoming position. RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> > objRectsRelativeToQuadTileAtPos = this.GetObjectRelativeQuadRectangles(); if (objRectsRelativeToQuadTileAtPos.Count == 0) { return(new ObjectPlacementBox { Sprites = new List <SpriteRenderInfo>(), IllegalParts = new List <RCIntRectangle>(), LegalParts = new List <RCIntRectangle>() }); } RCIntVector navCellCoords = this.MapWindowBC.AttachedWindow.WindowToMapCoords(position).Round(); IQuadTile quadTileAtPos = this.Map.GetCell(navCellCoords).ParentQuadTile; RCIntVector topLeftQuadCoords = quadTileAtPos.MapCoords; foreach (Tuple <RCIntRectangle, SpriteRenderInfo[]> relativeRect in objRectsRelativeToQuadTileAtPos) { RCIntVector rectTopLeftQuadCoords = topLeftQuadCoords + relativeRect.Item1.Location; if (rectTopLeftQuadCoords.X < topLeftQuadCoords.X && rectTopLeftQuadCoords.Y < topLeftQuadCoords.Y || rectTopLeftQuadCoords.X < topLeftQuadCoords.X && rectTopLeftQuadCoords.Y == topLeftQuadCoords.Y || rectTopLeftQuadCoords.X == topLeftQuadCoords.X && rectTopLeftQuadCoords.Y < topLeftQuadCoords.Y) { topLeftQuadCoords = rectTopLeftQuadCoords; } } /// Calculate the object rectangles relative to the calculated top-left quadratic coordinates. RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> > objRectsRelativeToTopLeftQuadTile = new RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> >(); foreach (Tuple <RCIntRectangle, SpriteRenderInfo[]> relativeRect in objRectsRelativeToQuadTileAtPos) { objRectsRelativeToTopLeftQuadTile.Add(Tuple.Create( new RCIntRectangle( relativeRect.Item1.Location + quadTileAtPos.MapCoords - topLeftQuadCoords, relativeRect.Item1.Size), relativeRect.Item2)); } /// Get the sprites to be displayed, translate their DisplayCoordinates accordingly from the top-left quadratic tile, /// and collect the violating quadratic coordinates. ObjectPlacementBox placementBox = new ObjectPlacementBox { Sprites = new List <SpriteRenderInfo>(), IllegalParts = new List <RCIntRectangle>(), LegalParts = new List <RCIntRectangle>() }; RCSet <RCIntVector> violatingQuadCoords = this.CheckObjectConstraints(topLeftQuadCoords); foreach (Tuple <RCIntRectangle, SpriteRenderInfo[]> relativeRect in objRectsRelativeToTopLeftQuadTile) { RCIntVector topLeftDisplayCoords = this.MapWindowBC.AttachedWindow.QuadToWindowRect(new RCIntRectangle(topLeftQuadCoords + relativeRect.Item1.Location, new RCIntVector(1, 1))).Location; for (int i = 0; i < relativeRect.Item2.Length; i++) { relativeRect.Item2[i].DisplayCoords += topLeftDisplayCoords; placementBox.Sprites.Add(relativeRect.Item2[i]); } for (int x = relativeRect.Item1.Left; x < relativeRect.Item1.Right; x++) { for (int y = relativeRect.Item1.Top; y < relativeRect.Item1.Bottom; y++) { RCIntVector relativeQuadCoords = new RCIntVector(x, y); RCIntVector absQuadCoords = topLeftQuadCoords + relativeQuadCoords; RCIntRectangle partRect = this.MapWindowBC.AttachedWindow.QuadToWindowRect(new RCIntRectangle(absQuadCoords, new RCIntVector(1, 1))); if (violatingQuadCoords.Contains(relativeQuadCoords)) { placementBox.IllegalParts.Add(partRect); } else { placementBox.LegalParts.Add(partRect); } } } } return(placementBox); }
/// <summary> /// Call this function from a thread to attach that thread to the Petri-network. The Petri-network will automatically /// synchronize the attached threads depending on it's structure. /// </summary> /// <param name="externalTransitions"> /// List of the external transitions that the thread wants to fire. The thread will be blocked until at least one /// of these transitions becomes fireable. /// </param> /// <param name="callbackFunctions"> /// This map has to assign a callback function for each callback transitions. /// </param> /// <remarks> /// The caller thread will be blocked until at least one of the given external transitions becomes fireable. Then /// the Petri-network will synchronize the thread while a callback transition becomes fireable. Then this transition /// will be fired, the assigned callback function will be called, and the thread will be detached from the /// Petri-network. /// </remarks> public void AttachThread(int[] externalTransitions, Dictionary <int, PNCallback> callbackFunctions) { lock (this.disposeLock) { if (this.pnDisposed) { throw new ObjectDisposedException("PetriNet"); } } if (!this.buildFinished) { throw new PetriNetException("Petri-network is under construction!"); } if (externalTransitions == null || externalTransitions.Length == 0) { throw new ArgumentNullException("externalTransitions"); } if (callbackFunctions == null || callbackFunctions.Count == 0) { throw new ArgumentNullException("callbackFunctions"); } RCSet <PNTransition> extTransitions = new RCSet <PNTransition>(); Dictionary <PNTransition, PNCallback> callbacks = new Dictionary <PNTransition, PNCallback>(); PNTransition firstExt = null; for (int i = 0; i < externalTransitions.Length; ++i) { int trIdx = externalTransitions[i]; if (trIdx >= 0 && trIdx < this.transitions.Length) { if (!callbackFunctions.ContainsKey(trIdx)) { extTransitions.Add(this.transitions[trIdx]); if (firstExt == null) { firstExt = this.transitions[trIdx]; } } else { throw new ArgumentException("Transition " + trIdx + " already exists in externalTransitions[" + i + "]!", "callbackFunctions"); } } else { throw new ArgumentException("Transition " + trIdx + " doesn't exist!", "externalTransitions[" + i + "]"); } } foreach (KeyValuePair <int, PNCallback> item in callbackFunctions) { int trIdx = item.Key; if (trIdx >= 0 && trIdx < this.transitions.Length) { callbacks.Add(this.transitions[trIdx], item.Value); } else { throw new ArgumentException("Transition " + trIdx + " doesn't exist!", "callbackFunctions"); } } firstExt.Group.AttachThread(extTransitions, callbacks); }
/// <summary> /// Processes the channel events and incoming answers arrived from the guests. /// </summary> private void ProcessGuestChannels(IDssGuestChannel[] channelsToGuests) { RCSet <int> newGuests = new RCSet <int>(); /// First collect the new guests for (int i = 0; i < this.previousChannelStates.Length; i++) { if (this.previousChannelStates[i] != channelsToGuests[i].ChannelState) { /// The state of a channel has changed this.previousChannelStates[i] = channelsToGuests[i].ChannelState; if (channelsToGuests[i].ChannelState == DssChannelState.CHANNEL_OPENED) { this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideOpened); } else if (channelsToGuests[i].ChannelState == DssChannelState.CHANNEL_CLOSED) { this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideClosed); } else if (channelsToGuests[i].ChannelState == DssChannelState.GUEST_CONNECTED) { this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideEngaged); this.simulator.GetPlayer(i + 1).Activate(); newGuests.Add(i); } } } /// Then process the answers of any other guests. for (int i = 0; i < this.previousChannelStates.Length; i++) { if (!newGuests.Contains(i) && channelsToGuests[i].ChannelState == DssChannelState.GUEST_CONNECTED) { /// If a guest is connected to this channel, process it's answer. RCPackage[] answerFromGuest = channelsToGuests[i].AnswerFromGuest; for (int j = 0; j < answerFromGuest.Length; j++) { if (answerFromGuest[j].PackageFormat.ID == TestClientMessages.COLOR_CHANGE_REQUEST) { /// Color change request arrived from the guest. PlayerColor newColor = (PlayerColor)answerFromGuest[j].ReadByte(0); this.simulator.GetPlayer(i + 1).Color = newColor; /// Notify the other connected guests. for (int k = 0; k < channelsToGuests.Length; k++) { if (!newGuests.Contains(k) && i != k && channelsToGuests[k].ChannelState == DssChannelState.GUEST_CONNECTED) { RCPackage colorChgNotif = RCPackage.CreateNetworkControlPackage(TestClientMessages.COLOR_CHANGE_NOTIFICATION); colorChgNotif.WriteInt(0, i + 1); colorChgNotif.WriteByte(1, (byte)newColor); this.rqs[k].Add(colorChgNotif); } } /// Notify the UI this.uiCallMarshal.SelectNewGuestColor(i, newColor); break; /// Ignore the remaining messages } } } } /// Send a reset message to the new guests foreach (int newGuestIdx in newGuests) { byte[] colors = new byte[this.simulator.MaxNumOfPlayers]; int[] xCoords = new int[this.simulator.MaxNumOfPlayers]; int[] yCoords = new int[this.simulator.MaxNumOfPlayers]; for (int j = 0; j < colors.Length; j++) { colors[j] = (byte)this.simulator.GetPlayer(j).Color; xCoords[j] = this.simulator.GetPlayer(j).Position.X; yCoords[j] = this.simulator.GetPlayer(j).Position.Y; } RCPackage reset = RCPackage.CreateNetworkControlPackage(TestClientMessages.RESET); reset.WriteByteArray(0, colors); reset.WriteIntArray(1, xCoords); reset.WriteIntArray(2, yCoords); this.rqs[newGuestIdx].Add(reset); } }
/// <summary> /// Constructs a ColorPalette object. /// </summary> /// <param name="palette">See ColorPalette.palette for more informations.</param> /// <param name="paletteMask">See ColorPalette.paletteMask for more informations.</param> /// <param name="specialColors">See ColorPalette.specialColors for more informations.</param> /// <remarks> /// Only the first parameter is mandatory. You can give null references for the others. /// </remarks> public ColorPalette(Color[] palette, Color[] paletteMask, Color[] specialColors) { this.palette = null; this.paletteMask = null; this.specialColors = null; /// Checking arguments. if (null == palette || 0 == palette.Length) { throw new ArgumentException("You must define at least 1 color in the palette.", "palette"); } if (null != paletteMask && palette.Length != paletteMask.Length) { throw new ArgumentException("The arrays palette and paletteMask must have the same length."); } /// Saving the color palette. RCSet <Color> paletteSet = new RCSet <Color>(); foreach (Color c in palette) { if (!paletteSet.Contains(c)) { paletteSet.Add(c); } else { throw new ArgumentException("All colors in the array palette must be unique.", "palette"); } } this.palette = palette; /// Saving the paletteMask. this.paletteMask = new Dictionary <Color, int>(); if (null != paletteMask) { int idx = 0; foreach (Color c in paletteMask) { if (!this.paletteMask.ContainsKey(c)) { this.paletteMask.Add(c, idx); idx++; } else { throw new ArgumentException("All colors in the array paletteMask must be unique.", "paletteMask"); } } } else { /// If no palette mask defined, we simply create the inverse of this.palette for (int idx = 0; idx < this.palette.Length; ++idx) { this.paletteMask.Add(this.palette[idx], idx); } } /// Saving the special colors. if (null != specialColors) { RCSet <Color> specColorSet = new RCSet <Color>(); foreach (Color c in specialColors) { if (!specColorSet.Contains(c)) { if (!paletteSet.Contains(c) && !this.paletteMask.ContainsKey(c)) { specColorSet.Add(c); } else { throw new ArgumentException("A color defined in the array specialColors has already been defined in the array palette or paletteMask.", "specialColors"); } } else { throw new ArgumentException("All colors in the array specialColors must be unique.", "specialColors"); } } this.specialColors = specialColors; } }
/// <see cref="ObjectPlacementView.GetObjectRelativeQuadRectangles"/> protected override RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> > GetObjectRelativeQuadRectangles() { this.UpdatePlacementData(); RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> > retList = new RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> >(); IBuildingType buildingType = this.buildingToBePlaced != null ? this.buildingToBePlaced.BuildingType : this.buildingTypeToBePlaced; if (buildingType == null) { return(retList); } /// Calculate the building rectangle and get sprites from the building preview animation if exists. RCIntVector buildingQuadSize = this.Scenario.Map.CellToQuadSize(buildingType.Area.Read().Size); RCIntRectangle buildingRelativeRect = new RCIntRectangle((-1) * buildingQuadSize / 2, buildingQuadSize); SpriteRenderInfo[] buildingSprites = new SpriteRenderInfo[0]; if (this.buildingPreviewAnimation != null) { buildingSprites = new SpriteRenderInfo[this.buildingPreviewAnimation.CurrentFrame.Length]; for (int i = 0; i < this.buildingPreviewAnimation.CurrentFrame.Length; i++) { buildingSprites[i] = new SpriteRenderInfo() { SpriteGroup = SpriteGroupEnum.MapObjectSpriteGroup, Index = buildingType.SpritePalette.Index, DisplayCoords = buildingType.SpritePalette.GetOffset(this.buildingPreviewAnimation.CurrentFrame[i]), Section = buildingType.SpritePalette.GetSection(this.buildingPreviewAnimation.CurrentFrame[i]) }; } } retList.Add(Tuple.Create(buildingRelativeRect, buildingSprites)); if (this.addonTypeToBePlaced != null) { /// Calculate the addon rectangle and get sprites from the addon preview animation if exists. RCIntVector addonQuadSize = this.Scenario.Map.CellToQuadSize(this.addonTypeToBePlaced.Area.Read().Size); RCIntRectangle addonRelativeRect = new RCIntRectangle( buildingRelativeRect.Location + buildingType.GetRelativeAddonPosition(this.Scenario.Map, this.addonTypeToBePlaced), addonQuadSize); SpriteRenderInfo[] addonSprites = new SpriteRenderInfo[0]; if (this.addonPreviewAnimation != null) { addonSprites = new SpriteRenderInfo[this.addonPreviewAnimation.CurrentFrame.Length]; for (int i = 0; i < this.addonPreviewAnimation.CurrentFrame.Length; i++) { addonSprites[i] = new SpriteRenderInfo() { SpriteGroup = SpriteGroupEnum.MapObjectSpriteGroup, Index = this.addonTypeToBePlaced.SpritePalette.Index, DisplayCoords = this.addonTypeToBePlaced.SpritePalette.GetOffset(this.addonPreviewAnimation.CurrentFrame[i]), Section = this.addonTypeToBePlaced.SpritePalette.GetSection(this.addonPreviewAnimation.CurrentFrame[i]) }; } } retList.Add(Tuple.Create(addonRelativeRect, addonSprites)); } return(retList); }