diff --git a/Content.Client/ADT/Salvage/MegafaunaVisualsSystem.cs b/Content.Client/ADT/Salvage/MegafaunaVisualsSystem.cs new file mode 100644 index 00000000000..f966151fb46 --- /dev/null +++ b/Content.Client/ADT/Salvage/MegafaunaVisualsSystem.cs @@ -0,0 +1,57 @@ +using Content.Client.DamageState; +using Content.Client.Humanoid; +using Content.Shared.ADT.Salvage; +using Content.Shared.ADT.Salvage.Components; +using Content.Shared.Mobs.Components; +using Robust.Client.GameObjects; +using Robust.Client.Player; +using Robust.Client.UserInterface; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Client.ADT.Salvage; + +public sealed class MegafaunaVisualsSystem : EntitySystem +{ + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; + [Dependency] private readonly IPlayerManager _playerMan = default!; + [Dependency] private readonly SpriteSystem _spriteSystem = default!; + [Dependency] private readonly HumanoidAppearanceSystem _appearanceSystem = default!; + [Dependency] private readonly IEntityManager _entManager = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAppearanceChange); + } + + private void OnAppearanceChange(EntityUid uid, MegafaunaComponent comp, ref AppearanceChangeEvent args) + { + if (!TryComp(uid, out var sprite)) + return; + if (!TryComp(uid, out var state)) + return; + if (!TryComp(uid, out var mob)) + return; + if (!state.States.TryGetValue(mob.CurrentState, out var layers)) + return; + + if (_appearance.TryGetData(uid, AshdrakeVisuals.Swoop, out var swoop)) + { + if (!sprite.LayerMapTryGet("drake_swoop", out var index)) + index = sprite.LayerMapReserveBlank("drake_swoop"); + sprite.LayerSetState(index, "swoop"); + sprite.LayerSetVisible(index, swoop); + + foreach (var (key, _) in layers) + { + if (!sprite.LayerMapTryGet(key, out var layer)) continue; + sprite.LayerSetVisible(layer, !swoop); + } + } + } +} diff --git a/Content.Server/ADT/Salvage/Systems/Megafauna/MegafaunaSystem.Drake.cs b/Content.Server/ADT/Salvage/Systems/Megafauna/MegafaunaSystem.Drake.cs new file mode 100644 index 00000000000..6dd4762012d --- /dev/null +++ b/Content.Server/ADT/Salvage/Systems/Megafauna/MegafaunaSystem.Drake.cs @@ -0,0 +1,112 @@ +using System.Numerics; +using Content.Server.Actions; +using Content.Server.ADT.Language; +using Content.Server.ADT.Salvage.Components; +using Content.Server.Body.Components; +using Content.Server.Body.Systems; +using Content.Server.Interaction; +using Content.Server.Polymorph.Systems; +using Content.Server.Popups; +using Content.Server.Stunnable; +using Content.Server.Weapons.Ranged.Systems; +using Content.Shared.Access.Systems; +using Content.Shared.ADT.Language; +using Content.Shared.ADT.Salvage; +using Content.Shared.ADT.Salvage.Components; +using Content.Shared.Chasm; +using Content.Shared.Damage; +using Content.Shared.Damage.Prototypes; +using Content.Shared.Interaction.Events; +using Content.Shared.Inventory; +using Content.Shared.Lathe; +using Content.Shared.Mobs.Systems; +using Content.Shared.Popups; +using Content.Shared.Weapons.Ranged.Components; +using Robust.Server.Audio; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Server.ADT.Salvage.Systems; + +public sealed partial class MegafaunaSystem +{ + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly StunSystem _stun = default!; + [Dependency] private readonly AppearanceSystem _appearance = default!; + [Dependency] private readonly PolymorphSystem _polymorph = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly GunSystem _gun = default!; + [Dependency] private readonly TransformSystem _transform = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnSwoop); + SubscribeLocalEvent(OnMeteors); + SubscribeLocalEvent(OnFire); + SubscribeLocalEvent(OnBreath); + } + + private void OnSwoop(AshDrakeSwoopActionEvent args) + { + var uid = args.Performer; + + _appearance.SetData(uid, AshdrakeVisuals.Swoop, true); + + _stun.TryStun(uid, TimeSpan.FromSeconds(0.5f), false); + Timer.Spawn(TimeSpan.FromSeconds(0.5f), () => Swoop(uid)); + } + + private void OnMeteors(AshDrakeMeteoritesActionEvent args) + { + var uid = args.Performer; + + var randVector = _random.NextVector2(6); + + var pseudoGun = Spawn("WeaponDragonMeteorites", Transform(uid).Coordinates); + _gun.AttemptShoot(uid, pseudoGun, Comp(pseudoGun), new(Transform(uid).ParentUid, randVector.X, randVector.Y)); + QueueDel(pseudoGun); + _stun.TryStun(uid, TimeSpan.FromSeconds(0.5f), false); + } + + private void OnFire(AshDrakeFireActionEvent args) + { + var uid = args.Performer; + if (!args.Coords.HasValue) + return; + + var coords = args.Coords.Value; + + var pseudoGun = Spawn("WeaponDragonFire", Transform(uid).Coordinates); + _gun.AttemptShoot(uid, pseudoGun, Comp(pseudoGun), coords); + QueueDel(pseudoGun); + _stun.TryStun(uid, TimeSpan.FromSeconds(0.5f), false); + } + + private void OnBreath(AshDrakeBreathActionEvent args) + { + var uid = args.Performer; + if (!args.Coords.HasValue) + return; + + var coords = args.Coords.Value; + + var pseudoGun = Spawn("WeaponDragonBreath", Transform(uid).Coordinates); + _gun.AttemptShoot(uid, pseudoGun, Comp(pseudoGun), coords); + QueueDel(pseudoGun); + _stun.TryStun(uid, TimeSpan.FromSeconds(0.5f), false); + } + + private void Swoop(EntityUid uid) + { + _appearance.SetData(uid, AshdrakeVisuals.Swoop, false); + _polymorph.PolymorphEntity(uid, "SwoopDrake"); + } +} diff --git a/Content.Server/ADT/Salvage/Systems/Megafauna/MegafaunaSystem.cs b/Content.Server/ADT/Salvage/Systems/Megafauna/MegafaunaSystem.cs new file mode 100644 index 00000000000..d3f2993cd35 --- /dev/null +++ b/Content.Server/ADT/Salvage/Systems/Megafauna/MegafaunaSystem.cs @@ -0,0 +1,5 @@ +namespace Content.Server.ADT.Salvage.Systems; + +public sealed partial class MegafaunaSystem : EntitySystem +{ +} diff --git a/Content.Server/Administration/Managers/AdminManager.cs b/Content.Server/Administration/Managers/AdminManager.cs index c0cb1ca83ac..a57237eb20c 100644 --- a/Content.Server/Administration/Managers/AdminManager.cs +++ b/Content.Server/Administration/Managers/AdminManager.cs @@ -111,7 +111,7 @@ public async void DeAdmin(ICommonSession session) // ADT-tweak: add "async" return; var payload = new WebhookPayload { - Content = $"**Снял права**: **{session.Name}**" + Content = $"**Снял права**: `{session.Name}`" }; var identifier = webhookData.ToIdentifier(); await _discord.CreateMessage(identifier, payload); @@ -198,7 +198,7 @@ public async void ReAdmin(ICommonSession session) // ADT-tweak: add "async" return; var payload = new WebhookPayload { - Content = $"**Вернул права**: **{session.Name}**" + Content = $"**Вернул права**: `{session.Name}`" }; var identifier = webhookData.ToIdentifier(); await _discord.CreateMessage(identifier, payload); @@ -407,7 +407,7 @@ private async void DisconnectedAdminMaybe(ICommonSession session) return; var payload = new WebhookPayload { - Content = $"**Оповещение: Админ ВЫШЕЛ {senderName}**" + Content = $"**Оповещение: Админ ВЫШЕЛ** `{senderName}`" }; var identifier = webhookData.ToIdentifier(); await _discord.CreateMessage(identifier, payload); @@ -459,14 +459,11 @@ private async void LoginAdminMaybe(ICommonSession session) var senderAdmin = GetAdminData(session); if (senderAdmin == null) return; - var senderName = session.Name; - if (!string.IsNullOrEmpty(senderAdmin.Title)) - senderName += $"\\[{senderAdmin.Title}\\]"; if (await _discord.GetWebhook(webhookUrl) is not { } webhookData) return; var payload = new WebhookPayload { - Content = $"**Оповещение: Админ зашёл {senderName}**" + Content = $"**Оповещение: Админ ЗАШЁЛ** `{session.Name}`[{senderAdmin.Title}]" }; var identifier = webhookData.ToIdentifier(); await _discord.CreateMessage(identifier, payload); diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs index e21ff29c9db..ddb9738d54b 100644 --- a/Content.Server/Chat/Managers/ChatManager.cs +++ b/Content.Server/Chat/Managers/ChatManager.cs @@ -331,7 +331,7 @@ private async void SendAdminChat(ICommonSession player, string message) return; var payload = new WebhookPayload { - Content = $"***AdminChat***: **{senderName}**: {message}" + Content = $"***AdminChat***: `{player.Name}`[{senderAdmin.Title}]: {message}" }; var identifier = webhookData.ToIdentifier(); await _discord.CreateMessage(identifier, payload); diff --git a/Content.Server/NPC/Components/NPCUseActionOnTargetComponent.cs b/Content.Server/NPC/Components/NPCUseActionOnTargetComponent.cs index f022a45eccb..f9498ffd079 100644 --- a/Content.Server/NPC/Components/NPCUseActionOnTargetComponent.cs +++ b/Content.Server/NPC/Components/NPCUseActionOnTargetComponent.cs @@ -1,9 +1,12 @@ using Content.Server.NPC.Systems; using Content.Shared.Actions; +using Content.Shared.Random; using Robust.Shared.Prototypes; namespace Content.Server.NPC.Components; +// ADT: Компонент был полностью переписан, заменяйте при апстриме на нашу версию. + /// /// This is used for an NPC that constantly tries to use an action on a given target. /// @@ -16,12 +19,24 @@ public sealed partial class NPCUseActionOnTargetComponent : Component [DataField] public string TargetKey = "Target"; - /// - /// Action that's going to attempt to be used. - /// + // /// + // /// Action that's going to attempt to be used. + // /// + // [DataField(required: true)] + // public EntProtoId ActionId; + + // [DataField] + // public EntityUid? ActionEnt; + [DataField(required: true)] - public EntProtoId ActionId; + public ProtoId Actions = "GoliathActions"; + + [ViewVariables] + public Dictionary ActionEntities = new(); [DataField] - public EntityUid? ActionEnt; + public float Delay = 7f; + + [ViewVariables] + public TimeSpan LastAction = TimeSpan.Zero; } diff --git a/Content.Server/NPC/Systems/NPCUseActionOnTargetSystem.cs b/Content.Server/NPC/Systems/NPCUseActionOnTargetSystem.cs index 33bc8f9074c..c793eedd8c1 100644 --- a/Content.Server/NPC/Systems/NPCUseActionOnTargetSystem.cs +++ b/Content.Server/NPC/Systems/NPCUseActionOnTargetSystem.cs @@ -1,14 +1,20 @@ +using System.Linq; using Content.Server.NPC.Components; using Content.Server.NPC.HTN; using Content.Shared.Actions; +using Content.Shared.Random.Helpers; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Server.NPC.Systems; +// ADT: Система была полностью переписан, заменяйте при апстриме на нашу версию. + public sealed class NPCUseActionOnTargetSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; /// public override void Initialize() @@ -20,32 +26,56 @@ public override void Initialize() private void OnMapInit(Entity ent, ref MapInitEvent args) { - ent.Comp.ActionEnt = _actions.AddAction(ent, ent.Comp.ActionId); + var weights = _proto.Index(ent.Comp.Actions); + foreach (var item in weights.Weights) + { + var actionEnt = _actions.AddAction(ent, item.Key); + if (actionEnt.HasValue) + ent.Comp.ActionEntities.Add(actionEnt.Value, item.Value); + } } - public bool TryUseTentacleAttack(Entity user, EntityUid target) + public bool TryUseAction(Entity user, EntityUid target) { if (!Resolve(user, ref user.Comp, false)) return false; - if (!TryComp(user.Comp.ActionEnt, out var action)) + var weights = _proto.Index(user.Comp.Actions); + var act = weights.Pick(); + var actionEntity = user.Comp.ActionEntities.Keys.Where(x => Prototype(x)?.ID == act).First(); + + if (!_actions.TryGetActionData(actionEntity, out var action)) return false; if (!_actions.ValidAction(action)) return false; - if (action.Event != null) + switch (action.BaseEvent) { - action.Event.Coords = Transform(target).Coordinates; + case InstantActionEvent instant: + break; + case EntityTargetActionEvent entityTarget: + entityTarget.Target = target; + break; + case EntityWorldTargetActionEvent entityWorldTarget: + entityWorldTarget.Entity = target; + entityWorldTarget.Coords = Transform(target).Coordinates; + break; + case WorldTargetActionEvent worldTarget: + worldTarget.Target = Transform(target).Coordinates; + break; } _actions.PerformAction(user, null, - user.Comp.ActionEnt.Value, + actionEntity, action, action.BaseEvent, _timing.CurTime, false); + + user.Comp.LastAction = _timing.CurTime; + return true; } @@ -57,10 +87,13 @@ public override void Update(float frameTime) var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var comp, out var htn)) { + if (_timing.CurTime < comp.LastAction + TimeSpan.FromSeconds(comp.Delay)) + continue; + if (!htn.Blackboard.TryGetValue(comp.TargetKey, out var target, EntityManager)) continue; - TryUseTentacleAttack((uid, comp), target); + TryUseAction((uid, comp), target); } } } diff --git a/Content.Server/Procedural/DungeonSystem.Rooms.cs b/Content.Server/Procedural/DungeonSystem.Rooms.cs index 43c7e225bda..83c243e71c7 100644 --- a/Content.Server/Procedural/DungeonSystem.Rooms.cs +++ b/Content.Server/Procedural/DungeonSystem.Rooms.cs @@ -186,7 +186,9 @@ public void SpawnRoom( _transform.SetLocalRotation(ent, childRot, childXform); // ADT - чиним тестер - if (grid == null || gridUid == childXform.GridUid) + _transform.AttachToGridOrMap(ent); + + if (grid == null || gridUid != childXform.GridUid) { Log.Debug("Спавнер данжа находится в космосе?"); return; diff --git a/Content.Shared/ADT/Salvage/Components/MegafaunaComponent.cs b/Content.Shared/ADT/Salvage/Components/MegafaunaComponent.cs new file mode 100644 index 00000000000..4554003910c --- /dev/null +++ b/Content.Shared/ADT/Salvage/Components/MegafaunaComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.ADT.Salvage.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class MegafaunaComponent : Component +{ + [DataField] + public bool Hardmode = false; +} diff --git a/Content.Shared/ADT/Salvage/Events/ActionEvents.cs b/Content.Shared/ADT/Salvage/Events/ActionEvents.cs new file mode 100644 index 00000000000..5e04b729000 --- /dev/null +++ b/Content.Shared/ADT/Salvage/Events/ActionEvents.cs @@ -0,0 +1,26 @@ +using Content.Shared.Actions; +using Robust.Shared.Serialization; + +namespace Content.Shared.ADT.Salvage; + +public sealed partial class AshDrakeSwoopActionEvent : InstantActionEvent +{ +} + +public sealed partial class AshDrakeMeteoritesActionEvent : InstantActionEvent +{ +} + +public sealed partial class AshDrakeFireActionEvent : EntityWorldTargetActionEvent +{ +} + +public sealed partial class AshDrakeBreathActionEvent : EntityWorldTargetActionEvent +{ +} + +[Serializable, NetSerializable] +public enum AshdrakeVisuals : byte +{ + Swoop, +} diff --git a/Content.Shared/Projectiles/ProjectileEmbedEvent.cs b/Content.Shared/Projectiles/ProjectileEmbedEvent.cs index e7dd6df8e29..675549c9d08 100644 --- a/Content.Shared/Projectiles/ProjectileEmbedEvent.cs +++ b/Content.Shared/Projectiles/ProjectileEmbedEvent.cs @@ -4,4 +4,4 @@ namespace Content.Shared.Projectiles; /// Raised directed on an entity when it embeds into something. /// [ByRefEvent] -public readonly record struct ProjectileEmbedEvent(EntityUid? Shooter, EntityUid Weapon, EntityUid Embedded); +public readonly record struct ProjectileEmbedEvent(EntityUid? Shooter, EntityUid? Weapon, EntityUid Embedded); diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index 85e75d6d291..4d7bf7a7f6c 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -106,7 +106,7 @@ private void OnEmbedProjectileHit(EntityUid uid, EmbeddableProjectileComponent c // Raise a specific event for projectiles. if (TryComp(uid, out ProjectileComponent? projectile)) { - var ev = new ProjectileEmbedEvent(projectile.Shooter!.Value, projectile.Weapon!.Value, args.Target); + var ev = new ProjectileEmbedEvent(projectile.Shooter, projectile.Weapon, args.Target); // ADT fix RaiseLocalEvent(uid, ref ev); } } diff --git a/Content.Shared/Weapons/Misc/SharedGrapplingGunSystem.cs b/Content.Shared/Weapons/Misc/SharedGrapplingGunSystem.cs index e790973538f..4f7a4d663e5 100644 --- a/Content.Shared/Weapons/Misc/SharedGrapplingGunSystem.cs +++ b/Content.Shared/Weapons/Misc/SharedGrapplingGunSystem.cs @@ -204,9 +204,13 @@ private void OnGrappleCollide(EntityUid uid, GrapplingProjectileComponent compon { if (!Timing.IsFirstTimePredicted) return; + // ADT fix start + if (!args.Shooter.HasValue || !args.Weapon.HasValue) + return; + // ADT fix end var jointComp = EnsureComp(uid); - var joint = _joints.CreateDistanceJoint(uid, args.Weapon, anchorA: new Vector2(0f, 0.5f), id: GrapplingJoint); + var joint = _joints.CreateDistanceJoint(uid, args.Weapon.Value, anchorA: new Vector2(0f, 0.5f), id: GrapplingJoint); joint.MaxLength = joint.Length + 0.2f; joint.Stiffness = 1f; joint.MinLength = 0.35f; diff --git a/Resources/Prototypes/ADT/Actions/lava.yml b/Resources/Prototypes/ADT/Actions/lava.yml index 79cee49e00c..89ee4a4480e 100644 --- a/Resources/Prototypes/ADT/Actions/lava.yml +++ b/Resources/Prototypes/ADT/Actions/lava.yml @@ -1,3 +1,4 @@ +# Игроки - type: entity id: ActionPumpCursedHeart name: action-pump-heart @@ -12,6 +13,7 @@ event: !type:PumpHeartActionEvent useDelay: 1 +# Фауна - type: entity id: ActionAncientGoliathTentacle name: "[color=red]Tentacle Slam[/color]" @@ -30,3 +32,66 @@ event: !type:GoliathSummonRandomTentacleAction useDelay: 1 range: 10 + +# Мегафауна +- type: entity + id: ActionDrakeFire + name: "[color=red]Dragon Fire[/color]" + description: fshhhhh + components: + - type: EntityWorldTargetAction + raiseOnUser: true + icon: + sprite: Mobs/Aliens/Asteroid/goliath.rsi + state: goliath_tentacle_spawn + iconOn: + sprite: Mobs/Aliens/Asteroid/goliath.rsi + state: goliath_tentacle_wiggle + event: !type:AshDrakeFireActionEvent + useDelay: 10 + range: 15 + +- type: entity + id: ActionDrakeBreath + name: "[color=red]Dragon Breath[/color]" + description: fshhhhh + components: + - type: EntityWorldTargetAction + raiseOnUser: true + icon: + sprite: Mobs/Aliens/Asteroid/goliath.rsi + state: goliath_tentacle_spawn + iconOn: + sprite: Mobs/Aliens/Asteroid/goliath.rsi + state: goliath_tentacle_wiggle + event: !type:AshDrakeBreathActionEvent + useDelay: 9 + range: 15 + +- type: entity + id: ActionDrakeMeteors + name: "[color=red]Meteorites![/color]" + description: fshhhhh + components: + - type: InstantAction + raiseOnUser: true + icon: + sprite: ADT/Objects/Specific/Lavaland/loot.rsi + state: cursed_heart + itemIconStyle: BigAction + event: !type:AshDrakeMeteoritesActionEvent + useDelay: 10 + +- type: entity + id: ActionDrakeSwoop + name: "[color=red]Fly[/color]" + description: fshhhhh + components: + - type: InstantAction + raiseOnUser: true + icon: + sprite: ADT/Objects/Specific/Lavaland/loot.rsi + state: cursed_heart + itemIconStyle: BigAction + event: !type:AshDrakeSwoopActionEvent + useDelay: 60 diff --git a/Resources/Prototypes/ADT/Entities/Mobs/NPCs/Megafauna/Drake.yml b/Resources/Prototypes/ADT/Entities/Mobs/NPCs/Megafauna/Drake.yml new file mode 100644 index 00000000000..0b5fdc3c6dd --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Mobs/NPCs/Megafauna/Drake.yml @@ -0,0 +1,596 @@ +#### Containers #### +- type: damageContainer + id: Drake + supportedGroups: + - Brute + - Toxin + - Airloss + - Genetic +#### Fire #### + +- type: entity + id: NazFire + name: огонь + placement: + mode: SnapgridCenter + snap: + - Wall + components: + - type: TileEntityEffect + effects: + - !type:FlammableReaction + multiplier: 0.5 + multiplierOnExisting: 0.75 + - !type:Ignite + - type: Sprite + sprite: Effects/fire.rsi + drawdepth: BelowFloor + layers: + - state: 1 + shader: unshaded + - type: Icon + sprite: Effects/fire.rsi + state: 1 + - type: TimedDespawn + lifetime: 1 + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,0.5" + layer: + - SlipLayer + mask: + - ItemMask + density: 1000 + hard: false + - type: Transform + anchored: true + - type: StepTrigger + requiredTriggeredSpeed: 0 + intersectRatio: 0.1 + blacklist: + tags: + - Catwalk + +#### Drake Projectiles #### + +- type: entity + id: BulletPistolHot + parent: BaseBulletIncendiary + name: bullet (.35 auto incendiary) + components: + - type: Projectile + damage: + types: + Heat: 15 + deleteOnCollide: false + - type: Timer + - type: TimedSpawner + prototypes: + - NazFire + chance: 1 + intervalSeconds: 0 + minimumEntitiesSpawned: 1 + maximumEntitiesSpawned: 1 + - type: TimedDespawn + lifetime: 2 + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/magic.rsi + layers: + - state: fireball + shader: unshaded + +- type: entity + id: BulletPistolMeteorites + parent: BaseBullet + name: bullet (.35 auto incendiary) + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/magic.rsi + layers: + - state: fireball + shader: unshaded + - type: Projectile + damage: + types: + Heat: 0 + deleteOnCollide: false + - type: TimedDespawn + lifetime: 1 + - type: Timer + - type: TimedSpawner + prototypes: + - FireballSignal + chance: 0.25 + intervalSeconds: 0 + minimumEntitiesSpawned: 1 + maximumEntitiesSpawned: 1 + +- type: entity + id: BulletFirethrow + parent: BaseBulletIncendiary + name: firethrow + components: + - type: Projectile + damage: + types: + Heat: 2 + Structural: 10 + deleteOnCollide: true + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/magic.rsi + layers: + - state: fireball + shader: unshaded + - type: TimedDespawn + lifetime: 0.68 + +- type: entity + id: FireballSignal + parent: BaseEffectGoliathTentacleSpawn + name: сигнал + components: + - type: SpawnOnDespawn + prototype: MeteorInstaExplosion + - type: Transform + anchored: True + - type: Physics + bodyType: Static + canCollide: false + - type: Sprite + drawdepth: Overdoors + sprite: ADT/Effects/target_circle.rsi + state: icon + - type: InteractionOutline + - type: TimedDespawn + lifetime: 2 + - type: PointLight + energy: 0.3 + radius: 1 + color: "#ff0000" + +- type: entity + name: drake fire barrage + id: LavalandDrakeFireBarrage + categories: [ HideSpawnMenu ] + parent: BulletPistolHot + components: + - type: ProjectileSpread + proto: BulletPistolHot + count: 3 #52 heat damage if you hit all your shots, but narrower spread + spread: 65 + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/magic.rsi + layers: + - state: fireball + shader: unshaded + +- type: entity + name: drake meteorites + id: LavalandDrakeMeteorBarrage + categories: [ HideSpawnMenu ] + parent: BulletPistolMeteorites + components: + - type: ProjectileSpread + proto: BulletPistolMeteorites + count: 36 #52 heat damage if you hit all your shots, but narrower spread + spread: 360 + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/magic.rsi + layers: + - state: fireball + shader: unshaded + +#### Drake itself №№№№ + +- type: entity + id: BaseMobDrake + parent: BaseMobAsteroid + name: пепельный дракон + abstract: true + description: + components: + - type: Destructible + thresholds: + - trigger: + !type:DamageTypeTrigger + damageType: Blunt + damage: 9000 + behaviors: + - !type:GibBehavior { } + - trigger: + !type:DamageTypeTrigger + damageType: Heat + damage: 100000 + behaviors: + - !type:SpawnEntitiesBehavior + spawnInContainer: true + spawn: + Ash: + min: 1 + max: 1 + - !type:BurnBodyBehavior { } + - !type:PlaySoundBehavior + sound: + collection: MeatLaserImpact + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 1 + density: 80 + mask: + - MobMask + layer: + - MobLayer + - type: Sprite + sprite: ADT/Mobs/Aliens/Lavaland/drake.rsi + layers: + - map: ["enum.DamageStateVisualLayers.Base"] + state: dragon + - type: DamageStateVisuals + states: + Alive: + Base: dragon + Dead: + Base: dragon_dead + - type: MovementSpeedModifier + baseWalkSpeed : 1 + baseSprintSpeed : 2.5 + - type: MobThresholds + thresholds: + 0: Alive + 1350: Dead + - type: MeleeWeapon + soundHit: + path: "/Audio/Weapons/smash.ogg" + angle: 0 + attackRate: 1 + animation: WeaponArcPunch + damage: + types: + Blunt: 45 + Structural: 150 + range: 2 + - type: NpcFactionMember + factions: + - SimpleHostile + - type: Tag + tags: + - CannotSuicide + - DoorBumpOpener + - type: NoSlip + - type: Damageable + damageContainer: Drake + - type: ExplosionResistance + damageCoefficient: 0 + - type: NPCUseActionOnTarget + actions: DrakeActions + delay: 5 + - type: HTN + rootTask: + task: GoliathCompound + blackboard: + VisionRadius: !type:Single + 6 + AggroVisionRadius: !type:Single + 25 + - type: Fauna + - type: Megafauna + +- type: entity + id: MobDrake + parent: [ BaseMobDrake, BaseMobAsteroid ] + name: пепельный дракон + +#### Drake polymorphs + +- type: polymorph + id: SwoopDrake + configuration: + entity: MobDrakeSwoop #Not angry so ghosts can't just take over the wizard + transferName: true + inventory: None + revertOnDeath: true + revertOnCrit: true + duration: 4 + +- type: entity + id: MobDrakeSwoop + parent: BaseMobDrake + name: "Полёт" + description: + components: + - type: Sprite + sprite: ADT/Mobs/Aliens/Lavaland/drake.rsi + scale: 0.5, 0.5 + color: "#FFFFFF77" + layers: + - map: ["enum.DamageStateVisualLayers.Base"] + state: shadow + - type: DamageStateVisuals + states: + Alive: + Base: shadow + Dead: + Base: dragon_dead + - type: MovementSpeedModifier + baseWalkSpeed : 4 + baseSprintSpeed : 8 + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.35 + density: 15 + layer: + - GhostImpassable + - type: MovementIgnoreGravity + - type: RepeatingTrigger + delay: 3.9 + - type: SpawnOnTrigger + proto: IgniteRuneDrake + - type: Timer + - type: TimedSpawner + prototypes: + - FireballSignalFlight + chance: 0.15 + intervalSeconds: 0 + minimumEntitiesSpawned: 1 + maximumEntitiesSpawned: 1 + - type: MeleeWeapon + soundHit: + path: "/Audio/Weapons/smash.ogg" + angle: 0 + attackRate: 0.01 + animation: WeaponArcPunch + damage: + types: + Blunt: 0 + range: 1 + +### Drake rune ### + +- type: entity + parent: CollideRune + id: IgniteRuneDrake + name: "руна" + components: + - type: Sprite + sprite: Structures/Magic/Cult/trap.rsi + scale: 3, 3 + layers: + - state: trap + color: '#FF000055' + - type: SpawnOnDespawn + prototype: DrakeRuneInstaExplosion + - type: TimedDespawn + lifetime: 0.5 + +#### Explosions #### + +- type: entity + name: Meteorite Instant Explosion + parent: BasePlasticExplosive + id: MeteorInstaExplosion + components: + - type: TriggerOnSpawn + - type: Sprite + sprite: ADT/Mobs/Phantom/phantom.rsi + drawdepth: Effects + layers: + - state: haunt + map: ["base"] + - type: Explosive + explosionType: FireBomb + totalIntensity: 2 + intensitySlope: 100 + maxIntensity: 2 + canCreateVacuum: false + deleteAfterExplosion: false + - type: ExplodeOnTrigger + - type: TimedDespawn + lifetime: 0.1 + +- type: entity + name: Drake Rune Instant Explosion + parent: BasePlasticExplosive + id: DrakeRuneInstaExplosion + components: + - type: TriggerOnSpawn + - type: Sprite + sprite: ADT/Mobs/Phantom/phantom.rsi + drawdepth: Effects + layers: + - state: haunt + map: ["base"] + - type: Explosive + explosionType: FireBomb + totalIntensity: 50 + intensitySlope: 5 + maxIntensity: 25 + canCreateVacuum: false + deleteAfterExplosion: false + - type: ExplodeOnTrigger + - type: TimedDespawn + lifetime: 0.1 + +### Signals ### + +- type: entity + id: FireballSignalPeriodic + parent: BaseEffectGoliathTentacleSpawn + name: сигнал + components: + - type: SpawnOnDespawn + prototype: MeteorInstaExplosion + - type: Transform + anchored: True + - type: Physics + bodyType: Static + canCollide: false + - type: Sprite + drawdepth: Overdoors + sprite: ADT/Effects/target_circle.rsi + state: icon + - type: InteractionOutline + - type: TimedDespawn + lifetime: 2.0 + - type: PointLight + energy: 0.3 + radius: 1 + color: "#ff0000" + - type: SpawnOnTrigger + proto: FirefallMeteors + - type: RepeatingTrigger + delay: 1.55 + + +- type: entity + id: FireballSignalFlight + parent: BaseEffectGoliathTentacleSpawn + name: сигнал + components: + - type: SpawnOnDespawn + prototype: MeteorInstaExplosion + - type: Transform + anchored: True + - type: Physics + bodyType: Static + canCollide: false + - type: Sprite + drawdepth: Overdoors + sprite: ADT/Effects/target_circle.rsi + state: icon + - type: InteractionOutline + - type: TimedDespawn + lifetime: 1.3 + - type: PointLight + energy: 0.3 + radius: 1 + color: "#ff0000" + + +#### Firefall #### + +- type: entity + id: FirefallMeteors + parent: BaseEffectGoliathTentacleSpawn + name: сигнал + components: + - type: Transform + anchored: True + - type: Physics + bodyType: Static + canCollide: false + - type: Sprite + drawdepth: Overdoors + sprite: Objects/Weapons/Guns/Projectiles/magic.rsi + layers: + - state: fireball + shader: unshaded + offset: 0, 1.7 + - type: InteractionOutline + - type: TimedDespawn + lifetime: 0.60 + +#### Random Actions #### + +- type: weightedRandomEntity + id: DrakeActions + weights: + ActionDrakeFire: 0.4 + ActionDrakeBreath: 0.2 + ActionDrakeSwoop: 0.2 + ActionDrakeMeteors: 0.2 + +#### Pseudo-guns #### +- type: entity + id: WeaponDragonFire + parent: BaseWeaponHeavyMachineGun + name: огненный плевок + description: + components: + - type: Gun + fireRate: 1 + projectileSpeed: 10 + soundGunshot: + path: /Audio/Magic/fireball.ogg + params: + volume: -10 + - type: BasicEntityAmmoProvider + proto: LavalandDrakeFireBarrage + capacity: 1 + count: 1 + - type: RechargeBasicEntityAmmo + rechargeCooldown: 4 + - type: Unremoveable + - type: Sprite + sprite: ADT/Mobs/Phantom/phantom.rsi + drawdepth: Effects + layers: + - state: haunt + +- type: entity + id: WeaponDragonMeteorites + parent: BaseWeaponHeavyMachineGun + name: метеоритный дождь + description: Горящие пламенем космические обьекты подчиняются вашей воли, разрушая все в округе + components: + - type: Gun + fireRate: 1 + projectileSpeed: 25 + soundGunshot: + path: /Audio/Magic/fireball.ogg + params: + volume: -10 + - type: BasicEntityAmmoProvider + proto: LavalandDrakeMeteorBarrage + capacity: 1 + count: 1 + - type: RechargeBasicEntityAmmo + rechargeCooldown: 25 + - type: Unremoveable + - type: Sprite + sprite: ADT/Mobs/Phantom/phantom.rsi + drawdepth: Effects + layers: + - state: haunt + +- type: entity + name: дыхание дракона + id: WeaponDragonBreath + parent: BaseWeaponHeavyMachineGun + description: Выпускает горячее пламя из вашей пасти, сжигая всё на своём пути. + components: + - type: Gun + fireRate: 10 + projectileSpeed: 8 + soundGunshot: + path: /Audio/Magic/fireball.ogg + params: + volume: -10 + - type: BallisticAmmoProvider + proto: BulletFirethrow + capacity: 69000 + - type: MagazineVisuals + magState: mag + steps: 4 + zeroVisible: true + - type: Appearance + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] + - type: Unremoveable + - type: Sprite + sprite: ADT/Mobs/Phantom/phantom.rsi + drawdepth: Effects + layers: + - state: haunt diff --git a/Resources/Prototypes/ADT/Entities/Mobs/NPCs/lavaland.yml b/Resources/Prototypes/ADT/Entities/Mobs/NPCs/lavaland.yml index 7944778c61c..2a1b8cc3341 100644 --- a/Resources/Prototypes/ADT/Entities/Mobs/NPCs/lavaland.yml +++ b/Resources/Prototypes/ADT/Entities/Mobs/NPCs/lavaland.yml @@ -163,4 +163,11 @@ Slash: 20 Piercing: 5 - type: NPCUseActionOnTarget - actionId: ActionAncientGoliathTentacle + actions: AncientGoliathActions + delay: 3 + +- type: weightedRandomEntity + id: AncientGoliathActions + weights: + ActionAncientGoliathTentacle: 0.5 + ActionGoliathTentacle: 0.5 diff --git a/Resources/Prototypes/ADT/Procedural/biome_templates.yml b/Resources/Prototypes/ADT/Procedural/biome_templates.yml index b7ccc0e49bd..70fdffabf11 100644 --- a/Resources/Prototypes/ADT/Procedural/biome_templates.yml +++ b/Resources/Prototypes/ADT/Procedural/biome_templates.yml @@ -55,11 +55,11 @@ entities: - ADTSpawnMobPRandomLavaland - !type:BiomeEntityLayer - threshold: 0.997 + threshold: 0.995 noise: seed: 0 noiseType: OpenSimplex2 - frequency: 0.4 + frequency: 0.6 lacunarity: 0.6 allowedTiles: - FloorBasalt diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/asteroid.yml b/Resources/Prototypes/Entities/Mobs/NPCs/asteroid.yml index 3d3a4a02868..6a998caaccd 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/asteroid.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/asteroid.yml @@ -78,7 +78,7 @@ AggroVisionRadius: !type:Single 10 - type: NPCUseActionOnTarget - actionId: ActionGoliathTentacle + actions: GoliathActions - type: Tag tags: - CannotSuicide @@ -336,3 +336,8 @@ size: Normal - type: StaticPrice price: 500 + +- type: weightedRandomEntity + id: GoliathActions + weights: + ActionGoliathTentacle: 1 diff --git a/Resources/Textures/ADT/Effects/target_circle.rsi/icon.png b/Resources/Textures/ADT/Effects/target_circle.rsi/icon.png new file mode 100644 index 00000000000..dc1ee4cdbc8 Binary files /dev/null and b/Resources/Textures/ADT/Effects/target_circle.rsi/icon.png differ diff --git a/Resources/Textures/ADT/Effects/target_circle.rsi/meta.json b/Resources/Textures/ADT/Effects/target_circle.rsi/meta.json new file mode 100644 index 00000000000..a7bfd0ec23d --- /dev/null +++ b/Resources/Textures/ADT/Effects/target_circle.rsi/meta.json @@ -0,0 +1,23 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at icons/mob/telegraphing/telegraph.dmi", + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +} diff --git a/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/dragon.png b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/dragon.png new file mode 100644 index 00000000000..b2d616fda95 Binary files /dev/null and b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/dragon.png differ diff --git a/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/dragon_dead.png b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/dragon_dead.png new file mode 100644 index 00000000000..8fcfed241ba Binary files /dev/null and b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/dragon_dead.png differ diff --git a/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/meta.json b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/meta.json new file mode 100644 index 00000000000..2e3cd70d351 --- /dev/null +++ b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at https://scrubby.melonmesa.com/dmi/icons/mob/simple/lavaland/96x96megafauna.dmi?codebase=tgstation", + "size": { + "x": 96, + "y": 96 + }, + "states": [ + { + "name": "dragon", + "directions": 4 + }, + { + "name": "dragon_dead" + }, + { + "name": "swoop", + "delays": [ + [ + 0.1, + 0.2, + 500 + ] + ] + }, + { + "name": "shadow" + } + ] +} diff --git a/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/shadow.png b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/shadow.png new file mode 100644 index 00000000000..3a8262de048 Binary files /dev/null and b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/shadow.png differ diff --git a/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/swoop.png b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/swoop.png new file mode 100644 index 00000000000..f3c4122a117 Binary files /dev/null and b/Resources/Textures/ADT/Mobs/Aliens/Lavaland/drake.rsi/swoop.png differ