public ITextureResource GetTexture(Vector2Ushort tilePosition, out DrawMode drawMode) { var textureIndex = PositionalRandom.Get( tilePosition, minInclusive: 0, maxExclusive: this.TextureResources.Count, seed: 792396596); if (this.CanFlipHorizontally) { drawMode = PositionalRandom.Get( tilePosition, minInclusive: 0, maxExclusive: 2, seed: 628275376) == 0 ? DrawMode.FlipHorizontally : DrawMode.Default; } else { drawMode = DrawMode.Default; } return(this.TextureResources[textureIndex]); }
protected override void ClientInitialize(ClientInitializeData data) { base.ClientInitialize(data); var gameObject = data.GameObject; var clientState = data.ClientState; var publicState = data.PublicState; clientState.LastGrowthStage = publicState.GrowthStage; var spriteRenderer = clientState.Renderer; spriteRenderer.TextureResource = SystemVegetation.ClientGetTexture( this, gameObject, publicState); clientState.Renderer = spriteRenderer; // flip renderer with some deterministic randomization if (this.CanFlipSprite && PositionalRandom.Get(gameObject.TilePosition, 0, 3, seed: 721886451) == 0) { spriteRenderer.DrawMode = DrawMode.FlipHorizontally; } if (this.IsAutoAddShadow) { this.ClientAddShadowRenderer(data); } }
public static void Setup( IComponentSpriteRenderer renderer, float power, float pivotY, bool canFlip = true) { var worldObject = renderer.SceneObject.AttachedWorldObject; if (worldObject == null) { // blueprint - use default rendering return; } var isRenderingFlipped = canFlip && PositionalRandom.Get(worldObject.TilePosition, 0, 3, seed: 9125835) == 0; var phaseOffset = (byte)PositionalRandom.Get(worldObject.TilePosition, 0, 8, seed: 614392664); var preset = new GrassAnimationPreset(power, pivotY, phaseOffset, isRenderingFlipped); if (!Materials.TryGetValue(preset, out var material)) { // no cached material found for the required preset - create and setup new material Materials[preset] = material = RenderingMaterial.Create(EffectResource); material.EffectParameters .Set("Flip", isRenderingFlipped ? 1 : 0) .Set("Power", power) .Set("PivotY", pivotY) .Set("PhaseOffset", phaseOffset); } renderer.RenderingMaterial = material; }
public static bool IsGroundSpriteFlipped(Vector2Ushort tilePosition) { return(PositionalRandom.Get(tilePosition, minInclusive: 0, maxExclusive: 2, seed: 218936133) == 0); }
protected override ITextureResource ClientGetTextureResource( IStaticWorldObject gameObject, StaticObjectPublicState publicState) { return(this.textures[PositionalRandom.Get(gameObject.TilePosition, minInclusive: 0, maxExclusive: this.textures.Length, seed: 791838756)]); }
// calculate a random tree scale depending on the tree position and seed private double SharedGetVisualScaleCoef(IStaticWorldObject worldObject) { const int maxDifferencePercents = 30; return(PositionalRandom.Get(worldObject.TilePosition, minInclusive: 100 - maxDifferencePercents / 2, maxExclusive: 100 + maxDifferencePercents / 2, seed: (uint)(worldObject.Id + this.ShortId.GetHashCode())) / 100.0); }
protected override void ClientInitialize(ClientInitializeData data) { base.ClientInitialize(data); // flip renderer with some deterministic randomization if (this.CanFlipSprite && PositionalRandom.Get(data.GameObject.TilePosition, 0, 2, seed: 9125835) == 0) { data.ClientState.Renderer.DrawMode = DrawMode.FlipHorizontally; } }
protected virtual ITextureResource ClientGetTextureResource( IStaticWorldObject gameObject, TPublicState publicState) { var damageStage = this.SharedCalculateDamageStage(publicState.StructurePointsCurrent); // select deterministically which sprites row in the atlas to use // (each row - different look for the same mineral) var rowIndex = (byte)PositionalRandom.Get(gameObject.TilePosition, minInclusive: 0, maxExclusive: this.TextureVariantsCount, seed: 691237523); return(this.textureAtlasResource.Chunk(damageStage, rowIndex)); }
public override byte ClientGetTextureAtlasColumn( IStaticWorldObject worldObject, VegetationPublicState publicState) { var growthStage = publicState.GrowthStage; if (growthStage == this.GrowthStagesCount) { // full grown - select one of two variants based on position return((byte)(growthStage + PositionalRandom.Get(worldObject.TilePosition, 0, 2, seed: 90139875u))); } return(growthStage); }
protected virtual void ClientApplyTreeRandomScale( IStaticWorldObject worldObject, IComponentSpriteRenderer renderer) { // if this is not a blueprint, apply random scale (depending on the tree position and seed) const int maxDifferencePercents = 30; var scaleCoef = PositionalRandom.Get(worldObject.TilePosition, minInclusive: 100 - maxDifferencePercents / 2, maxExclusive: 100 + maxDifferencePercents / 2, seed: (uint)(worldObject.Id + this.ShortId.GetHashCode())) / 100.0; renderer.Scale *= scaleCoef; renderer.DrawOrderOffsetY *= scaleCoef; }
protected override void ClientSetupRenderer(IComponentSpriteRenderer renderer) { renderer.PositionOffset = (0.5, 0.0); renderer.SpritePivotPoint = (0.5, 0); renderer.DrawOrderOffsetY = 0.38; renderer.Scale = 1.3; // making the grass choose random element of the atlas depending on world position var position = renderer.SceneObject.Position.ToVector2Ushort(); var atlasChunk = (byte)PositionalRandom.Get(position, 0, 4, seed: 12345); renderer.TextureResource = textureAtlas.Chunk(atlasChunk, 0); ClientGrassRenderingHelper.Setup(renderer, power: 0.1f, pivotY: 0.2f); }
protected override void ClientInitialize(ClientInitializeData data) { base.ClientInitialize(data); // hacking progress display Api.Client.UI.AttachControl( data.GameObject, new ObjectHackingProgressDisplayControl(data.PublicState), positionOffset: this.SharedGetObjectCenterWorldOffset(data.GameObject) + (0, 1.35), isFocusable: false); // flip renderer with some deterministic randomization if (this.CanFlipSprite && PositionalRandom.Get(data.GameObject.TilePosition, 0, 2, seed: 9125835) == 0) { data.ClientState.Renderer.DrawMode = DrawMode.FlipHorizontally; } }
protected override void ClientSetupRenderer(IComponentSpriteRenderer renderer) { base.ClientSetupRenderer(renderer); renderer.DrawOrderOffsetY = 0.5; var worldObject = renderer.SceneObject.AttachedWorldObject; if (worldObject == null) { return; } // flip renderer with some deterministic randomization if (PositionalRandom.Get(worldObject.TilePosition, 0, 2, seed: 925309274) == 0) { renderer.DrawMode = DrawMode.FlipHorizontally; } }
protected override void ClientInitialize(ClientInitializeData data) { // don't use base implementation //base.ClientInitialize(data); var renderer = Client.Rendering.CreateSpriteRenderer( data.GameObject, textureResource: this.DefaultTexture); data.ClientState.Renderer = renderer; // flip renderer with some deterministic randomization if (this.CanFlipSprite && PositionalRandom.Get(data.GameObject.TilePosition, 0, 3, seed: 721886451) == 0) { renderer.DrawMode = DrawMode.FlipHorizontally; } this.ClientSetupRenderer(renderer); }
public string Execute() { var world = Server.World; var changesDone = 0; var tempCheckQueue = new Queue <Tile>(); var tempNeighborTiles = new HashSet <Tile>(); Process(world.GetStaticWorldObjectsOfProto <ObjectPropRoadHorizontal>(), protoBroken1: Api.GetProtoEntity <ObjectPropRoadHorizontal2>(), protoBroken2: Api.GetProtoEntity <ObjectPropRoadHorizontal3>(), protoBroken3: Api.GetProtoEntity <ObjectPropRoadHorizontal4>(), seed: 696159212); Process(world.GetStaticWorldObjectsOfProto <ObjectPropRoadVertical>(), protoBroken1: Api.GetProtoEntity <ObjectPropRoadVertical2>(), protoBroken2: Api.GetProtoEntity <ObjectPropRoadVertical3>(), protoBroken3: Api.GetProtoEntity <ObjectPropRoadVertical4>(), seed: 918246523); return($"Replaced {changesDone} roads"); void Process( IEnumerable <IStaticWorldObject> enumerationAllRoads, IProtoStaticWorldObject protoBroken1, IProtoStaticWorldObject protoBroken2, IProtoStaticWorldObject protoBroken3, uint seed) { var listAllRoads = enumerationAllRoads.ToList(); listAllRoads.Shuffle(); foreach (var worldObject in listAllRoads) { switch (PositionalRandom.Get(worldObject.TilePosition, minInclusive: 0, maxExclusive: 16, seed)) { // normal road default: continue; // a little damaged road case 10: case 11: case 12: TryReplace(worldObject, protoBroken1); continue; // damaged road case 13: case 14: TryReplace(worldObject, protoBroken2); continue; // severe damaged road case 15: TryReplace(worldObject, protoBroken3); continue; } } // helper method to replace the object void TryReplace(IStaticWorldObject worldObject, IProtoStaticWorldObject replacementProto) { tempCheckQueue.Clear(); tempNeighborTiles.Clear(); foreach (var tile in worldObject.OccupiedTiles) { tempCheckQueue.Enqueue(tile); } CollectNeighborTilesRecursive(tempCheckQueue, tempNeighborTiles, depthRemains: 12); foreach (var neighborTile in tempNeighborTiles) { foreach (var neighborTileStaticObject in neighborTile.StaticObjects) { if (neighborTileStaticObject.ProtoStaticWorldObject == replacementProto) { // found same proto type in a neighbor tile, don't allow replacement return; } } } world.DestroyObject(worldObject); world.CreateStaticWorldObject(replacementProto, worldObject.TilePosition); changesDone++; } } }
public string Execute() { var world = Server.World; var changesDone = 0; var tempCheckQueue = new Queue <Tile>(); var tempNeighborTiles = new HashSet <Tile>(); Process(world.GetStaticWorldObjectsOfProto <ObjectPropRuinsWallHorizontal01>(), protoBroken1: Api.GetProtoEntity <ObjectPropRuinsWallHorizontal02>(), protoBroken2: Api.GetProtoEntity <ObjectPropRuinsWallHorizontal03>(), protoBroken3: Api.GetProtoEntity <ObjectPropRuinsWallHorizontal04>(), seed: 823731251, defaultVariantRateIncrease: 4); Process(world.GetStaticWorldObjectsOfProto <ObjectPropRuinsWallVertical01>(), protoBroken1: Api.GetProtoEntity <ObjectPropRuinsWallVertical01>(), protoBroken2: Api.GetProtoEntity <ObjectPropRuinsWallVertical02>(), protoBroken3: Api.GetProtoEntity <ObjectPropRuinsWallVertical02>(), seed: 155436192, defaultVariantRateIncrease: 2); return($"Replaced {changesDone} walls"); void Process( IEnumerable <IStaticWorldObject> enumerationAllObjects, IProtoStaticWorldObject protoBroken1, IProtoStaticWorldObject protoBroken2, IProtoStaticWorldObject protoBroken3, uint seed, byte defaultVariantRateIncrease) { var listAllObjects = enumerationAllObjects.ToList(); listAllObjects.Shuffle(); foreach (var worldObject in listAllObjects) { bool isOk; var attempt = 0; do { var randomNumber = PositionalRandom.Get(worldObject.TilePosition, minInclusive: 0, maxExclusive: 4 + defaultVariantRateIncrease, seed); isOk = randomNumber switch { 0 => TryReplace(worldObject, protoBroken1), 1 => TryReplace(worldObject, protoBroken2), 2 => TryReplace(worldObject, protoBroken3), _ => true }; }while (!isOk && ++attempt < 8); } // helper method to replace the object bool TryReplace(IStaticWorldObject worldObject, IProtoStaticWorldObject replacementProto) { if (ReferenceEquals(worldObject.ProtoGameObject, replacementProto)) { // no replacement necessary return(true); } tempCheckQueue.Clear(); tempNeighborTiles.Clear(); foreach (var tile in worldObject.OccupiedTiles) { tempCheckQueue.Enqueue(tile); } CollectNeighborTilesRecursive(tempCheckQueue, tempNeighborTiles, // will process only up to 4 neighbors // by distance from the occupied tiles depthRemains: 5); foreach (var neighborTile in tempNeighborTiles) { foreach (var neighborTileStaticObject in neighborTile.StaticObjects) { if (ReferenceEquals(neighborTileStaticObject.ProtoStaticWorldObject, replacementProto)) { // found the same proto type in a neighbor tile, don't allow replacement return(false); } } } world.DestroyObject(worldObject); world.CreateStaticWorldObject(replacementProto, worldObject.TilePosition); changesDone++; return(true); } } }
private static bool SharedIsAlternativeVariant(Vector2Ushort tilePosition) { return(PositionalRandom.Get(tilePosition, 0, 2, seed: 9125835) == 0); }
public static void ClientExplode( Vector2D position, ExplosionPreset explosionPreset, float volume = 1.0f) { // add screen shakes ClientComponentCameraScreenShakes.AddRandomShakes( duration: explosionPreset.ScreenShakesDuration, worldDistanceMin: explosionPreset.ScreenShakesWorldDistanceMin, worldDistanceMax: explosionPreset.ScreenShakesWorldDistanceMax); // play sound var explosionSoundEmitter = Client.Audio.PlayOneShot(explosionPreset.SoundSet.GetSound(), worldPosition: position, volume: volume, pitch: RandomHelper.Range(0.95f, 1.05f)); // extend explosion sound distance explosionSoundEmitter.CustomMinDistance = (float)explosionPreset.LightWorldSize / 3; explosionSoundEmitter.CustomMaxDistance = (float)explosionPreset.LightWorldSize; // create explosion renderer var explosionSpriteAnimationDuration = explosionPreset.SpriteAnimationDuration; var explosionSceneObject = Client.Scene.CreateSceneObject("Temp explosion", position); explosionSceneObject.Destroy(delay: explosionSpriteAnimationDuration); var explosionSpriteRenderer = Client.Rendering.CreateSpriteRenderer( explosionSceneObject, TextureResource.NoTexture, drawOrder: DrawOrder.Explosion, spritePivotPoint: (0.5, 0.5)); explosionSpriteRenderer.Color = explosionPreset.SpriteColorMultiplicative; explosionSpriteRenderer.Size = explosionPreset.SpriteSize; if (explosionPreset.SpriteColorAdditive.HasValue // ReSharper disable once CompareOfFloatsByEqualityOperator || explosionPreset.SpriteBrightness != 1) { var renderingMaterial = RenderingMaterial.Create(EffectResourceAdditiveColorEffect); renderingMaterial.EffectParameters .Set("ColorAdditive", explosionPreset.SpriteColorAdditive ?? Colors.Black) .Set("Brightness", explosionPreset.SpriteBrightness); explosionSpriteRenderer.RenderingMaterial = renderingMaterial; } var isFlipped = 0 == PositionalRandom.Get(position.ToVector2Ushort(), minInclusive: 0, maxExclusive: 2, seed: 893243289); if (isFlipped) { explosionSpriteRenderer.DrawMode = DrawMode.FlipHorizontally; } ClientComponentOneShotSpriteSheetAnimationHelper.Setup( explosionSpriteRenderer, explosionPreset.SpriteAtlasResources.TakeByRandom(), explosionSpriteAnimationDuration); // add light source for the explosion var explosionLight = ClientLighting.CreateLightSourceSpot( explosionSceneObject, explosionPreset.LightColor, size: explosionPreset.LightWorldSize, positionOffset: (0, 0), spritePivotPoint: (0.5, 0.5)); ClientComponentOneShotLightAnimation.Setup( explosionLight, explosionPreset.LightDuration); // add blast wave var blastAnimationDuration = explosionPreset.BlastwaveAnimationDuration; if (blastAnimationDuration > 0) { ClientTimersSystem.AddAction( explosionPreset.BlastwaveDelay, () => { var blastSceneObject = Client.Scene.CreateSceneObject("Temp explosion", position); blastSceneObject.Destroy(delay: blastAnimationDuration); var blastSpriteRenderer = Client.Rendering.CreateSpriteRenderer( blastSceneObject, new TextureResource("FX/ExplosionBlast"), drawOrder: DrawOrder.Explosion - 1, spritePivotPoint: (0.5, 0.5)); // animate blast wave ClientComponentGenericAnimationHelper.Setup( blastSceneObject, blastAnimationDuration, updateCallback: alpha => { var blastwaveAlpha = (byte)(byte.MaxValue * (1 - alpha)); blastSpriteRenderer.Color = explosionPreset.BlastWaveColor .WithAlpha(blastwaveAlpha); var sizeX = MathHelper.Lerp(explosionPreset.BlastwaveSizeFrom.X, explosionPreset.BlastwaveSizeTo.X, alpha); var sizeY = MathHelper.Lerp(explosionPreset.BlastwaveSizeFrom.Y, explosionPreset.BlastwaveSizeTo.Y, alpha); blastSpriteRenderer.Size = new Size2F(sizeX, sizeY); }); }); } ClientGroundExplosionAnimationHelper.OnExplode( delaySeconds: explosionSpriteAnimationDuration / 2, position: position); }