// for cliffs hit public WeaponHitData(Vector2D hitPosition) { this.WorldObject = null; this.IsCliffsHit = true; this.FallbackProtoWorldObject = null; this.FallbackTilePosition = (Vector2Ushort)hitPosition; this.HitPoint = (hitPosition - this.FallbackTilePosition.ToVector2D()).ToVector2F(); this.FallbackObjectMaterial = ObjectMaterial.Stone; }
// Optimized to minimize GC allocations. public bool Contains(IProtoWorldObject protoWorldObject) { foreach (var entry in this) { if (ReferenceEquals(entry, protoWorldObject)) { return(true); } } return(false); }
private static IWorldObject ServerTrySpawn(IProtoWorldObject protoObjectToSpawn, Vector2Ushort spawnPosition) { switch (protoObjectToSpawn) { case IProtoCharacterMob protoCharacterMob: return(Server.Characters.SpawnCharacter(protoCharacterMob, spawnPosition.ToVector2D())); case IProtoStaticWorldObject protoStaticWorldObject: return(Server.World.CreateStaticWorldObject(protoStaticWorldObject, spawnPosition)); default: throw new Exception("Unknown object type to spawn: " + protoObjectToSpawn); } }
private static bool ServerCheckCanSpawn(IProtoWorldObject protoObjectToSpawn, Vector2Ushort spawnPosition) { switch (protoObjectToSpawn) { case IProtoCharacterMob _: return(ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn(spawnPosition.ToVector2D(), isPlayer: false)); case IProtoStaticWorldObject protoStaticWorldObject: return(protoStaticWorldObject.CheckTileRequirements(spawnPosition, character: null, logErrors: false)); default: throw new Exception("Unknown object type to spawn: " + protoObjectToSpawn); } }
public static Vector2D SharedOffsetHitWorldPositionCloserToObjectCenter( IWorldObject worldObject, IProtoWorldObject protoWorldObject, Vector2D hitPoint, bool isRangedWeapon) { var objectCenterPosition = worldObject?.PhysicsBody?.CalculateCenterOffsetForCollisionGroup( isRangedWeapon ? CollisionGroups.HitboxRanged : CollisionGroups.HitboxMelee) ?? protoWorldObject.SharedGetObjectCenterWorldOffset(worldObject); var coef = isRangedWeapon ? 0.2 : 0.5; var offset = coef * (objectCenterPosition - hitPoint); offset = offset.ClampMagnitude(0.5); // don't offset more than 0.5 tiles hitPoint += offset; return(hitPoint); }
private static bool ServerCheckCanSpawn(IProtoWorldObject protoObjectToSpawn, Vector2Ushort spawnPosition) { return(protoObjectToSpawn switch { IProtoCharacterMob => ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn( spawnPosition.ToVector2D(), isPlayer: false) && !LandClaimSystem.SharedIsLandClaimedByAnyone(spawnPosition), IProtoStaticWorldObject protoStaticWorldObject // Please note: land claim check must be integrated in the object tile requirements => protoStaticWorldObject.CheckTileRequirements( spawnPosition, character: null, logErrors: false), _ => throw new ArgumentOutOfRangeException("Unknown object type to spawn: " + protoObjectToSpawn) });
public static ReadOnlySoundPreset <ObjectSound> SharedGetObjectSoundPreset( this IProtoWorldObject protoWorldObject) { if (protoWorldObject == null) { throw new ArgumentNullException(nameof(protoWorldObject)); } if (protoWorldObject is IProtoWorldObjectWithSoundPresets protoWorldObjectWithSoundPresets) { return(protoWorldObjectWithSoundPresets.SoundPresetObject); } Api.Logger.Error( protoWorldObject + " type is not inherited from " + nameof(IProtoWorldObjectWithSoundPresets) + " - cannot get object sound preset. Using default (generic) sound preset instead."); return(ObjectsSoundsPresets.ObjectGeneric); }
public WeaponHitData(IWorldObject worldObject, Vector2F hitPoint) { this.WorldObject = worldObject; this.IsCliffsHit = false; this.FallbackProtoWorldObject = worldObject.ProtoWorldObject; this.FallbackTilePosition = worldObject.TilePosition; this.HitPoint = hitPoint; if (worldObject is ICharacter character) { this.FallbackObjectMaterial = ((IProtoCharacterCore)character.ProtoCharacter) .SharedGetObjectMaterialForCharacter(character); } else if (worldObject.ProtoWorldObject is IProtoWorldObjectWithSoundPresets protoWorldObjectWithSoundPresets) { this.FallbackObjectMaterial = protoWorldObjectWithSoundPresets .ObjectMaterial; } else { this.FallbackObjectMaterial = ObjectMaterial.HardTissues; } }
public static void ClientAddHitSparks( IReadOnlyWeaponHitSparksPreset hitSparksPreset, WeaponHitData hitData, IWorldObject hitWorldObject, IProtoWorldObject protoWorldObject, Vector2D worldObjectPosition, int projectilesCount, ObjectMaterial objectMaterial, bool randomizeHitPointOffset, bool randomRotation, DrawOrder drawOrder, double scale = 1.0, double animationFrameDuration = 2 / 60.0) { var sceneObject = Api.Client.Scene.CreateSceneObject("Temp_HitSparks"); sceneObject.Position = worldObjectPosition; var hitPoint = hitData.HitPoint.ToVector2D(); if (!hitData.IsCliffsHit) { // move hitpoint a bit closer to the center of the object hitPoint = WeaponSystem.SharedOffsetHitWorldPositionCloserToObjectCenter( hitWorldObject, protoWorldObject, hitPoint, isRangedWeapon: randomizeHitPointOffset); } var sparksEntry = hitSparksPreset.GetForMaterial(objectMaterial); if (projectilesCount == 1 && randomizeHitPointOffset && sparksEntry.AllowRandomizedHitPointOffset) { // randomize hitpoint a bit by adding a little random offset var maxOffsetDistance = 0.2; var range = maxOffsetDistance * RandomHelper.NextDouble(); var angleRad = 2 * Math.PI * RandomHelper.NextDouble(); var randomOffset = new Vector2D(range * Math.Cos(angleRad), range * Math.Sin(angleRad)); hitPoint += randomOffset; } var componentSpriteRender = Api.Client.Rendering.CreateSpriteRenderer( sceneObject, positionOffset: hitPoint, spritePivotPoint: (0.5, sparksEntry.PivotY), drawOrder: drawOrder); componentSpriteRender.DrawOrderOffsetY = -hitPoint.Y; componentSpriteRender.Scale = (float)scale * Math.Pow(1.0 / projectilesCount, 0.35); if (sparksEntry.UseScreenBlending) { componentSpriteRender.BlendMode = BlendMode.Screen; } if (randomRotation) { componentSpriteRender.RotationAngleRad = (float)(RandomHelper.NextDouble() * 2 * Math.PI); } var componentAnimator = sceneObject.AddComponent <ClientComponentSpriteSheetAnimator>(); var hitSparksEntry = sparksEntry; componentAnimator.Setup( componentSpriteRender, hitSparksEntry.SpriteSheetAnimationFrames, frameDurationSeconds: animationFrameDuration, isLooped: false); var totalAnimationDuration = animationFrameDuration * componentAnimator.FramesCount; var totalDurationWithLight = 0.15 + totalAnimationDuration; if (hitSparksEntry.LightColor.HasValue) { // create light spot (even for melee weapons) var lightSource = ClientLighting.CreateLightSourceSpot( sceneObject, color: hitSparksEntry.LightColor.Value, spritePivotPoint: (0.5, 0.5), size: 7, // we don't want to display nickname/healthbar for the firing character, it's too quick anyway logicalSize: 0, positionOffset: hitPoint); ClientComponentOneShotLightAnimation.Setup(lightSource, totalDurationWithLight); } componentSpriteRender.Destroy(totalAnimationDuration); componentAnimator.Destroy(totalAnimationDuration); sceneObject.Destroy(totalDurationWithLight); }
public static ObjectMaterial SharedGetObjectMaterial(this IProtoWorldObject protoWorldObject) { return(((IProtoWorldObjectWithSoundPresets)protoWorldObject).ObjectMaterial); }
public WeaponHitData(IWorldObject worldObject) { this.WorldObject = worldObject; this.FallbackProtoWorldObject = worldObject.ProtoWorldObject; this.FallbackTilePosition = worldObject.TilePosition; }