diff --git a/Content.Client/_Goobstation/Bingle/BingleFallingVisualsSystem.cs b/Content.Client/_Goobstation/Bingle/BingleFallingVisualsSystem.cs new file mode 100644 index 0000000000..c310b308b2 --- /dev/null +++ b/Content.Client/_Goobstation/Bingle/BingleFallingVisualsSystem.cs @@ -0,0 +1,80 @@ +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Shared.Animations; +using Content.Shared._Goobstation.Bingle; + +namespace Content.Client._Goobstation.Bingle; + +/// +/// Handles the falling animation for entities that fall into a Binglepit. shamlesly copied from chasm +/// +public sealed class BingleFallingVisualsSystem : EntitySystem +{ + [Dependency] private readonly AnimationPlayerSystem _anim = default!; + + private readonly string _chasmFallAnimationKey = "chasm_fall"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnComponentRemove); + } + + private void OnComponentInit(EntityUid uid, BinglePitFallingComponent component, ComponentInit args) + { + if (!TryComp(uid, out var sprite) || + TerminatingOrDeleted(uid)) + { + return; + } + + component.OriginalScale = sprite.Scale; + + var player = EnsureComp(uid); + if (_anim.HasRunningAnimation(player, _chasmFallAnimationKey)) + return; + + _anim.Play((uid, player), GetFallingAnimation(component), _chasmFallAnimationKey); + } + + private void OnComponentRemove(EntityUid uid, BinglePitFallingComponent component, ComponentRemove args) + { + if (!TryComp(uid, out var sprite) || TerminatingOrDeleted(uid)) + return; + + if (!TryComp(uid, out var player)) + return; + + //var player = EnsureComp(uid); + if (_anim.HasRunningAnimation(player, _chasmFallAnimationKey)) + _anim.Stop(player, _chasmFallAnimationKey); + + sprite.Scale = component.OriginalScale; + } + + private Animation GetFallingAnimation(BinglePitFallingComponent component) + { + var length = component.AnimationTime; + + return new Animation() + { + Length = length, + AnimationTracks = + { + new AnimationTrackComponentProperty() + { + ComponentType = typeof(SpriteComponent), + Property = nameof(SpriteComponent.Scale), + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(component.OriginalScale, 0.0f), + new AnimationTrackProperty.KeyFrame(component.AnimationScale, length.Seconds), + }, + InterpolationMode = AnimationInterpolationMode.Cubic + } + } + }; + } +} diff --git a/Content.Client/_Goobstation/Bingle/BingleSystem.cs b/Content.Client/_Goobstation/Bingle/BingleSystem.cs new file mode 100644 index 0000000000..48364e049d --- /dev/null +++ b/Content.Client/_Goobstation/Bingle/BingleSystem.cs @@ -0,0 +1,43 @@ +using Robust.Client.GameObjects; +using Content.Shared._Goobstation.Bingle; +using Content.Shared.CombatMode; + +namespace Content.Client._Goobstation.Bingle; + +/// +/// handles the upgrade apperance from normal bingle to upgraded bingle +/// +public sealed class BingleSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + SubscribeNetworkEvent(OnUpgradeChange); + SubscribeLocalEvent(OnCombatToggle); + } + + //make eyse glow red when combat mode engaged. + private void OnCombatToggle(EntityUid uid, BingleComponent component, ToggleCombatActionEvent args) + { + if (!TryComp(uid, out var sprite)) + return; + if (!TryComp(uid, out var combat)) + return; + if (!sprite.LayerMapTryGet(BingleVisual.Combat, out var layer)) + return; + + sprite.LayerSetVisible(layer, combat.IsInCombatMode); + } + + private void OnUpgradeChange(BingleUpgradeEntityMessage args) + { + var uid = GetEntity(args.Bingle); + + if (!TryComp(uid, out var sprite)) + return; + if (!sprite.LayerMapTryGet(BingleVisual.Upgraded, out var layer)) + return; + + sprite.LayerSetVisible(layer, true); + } +} diff --git a/Content.Server/_Goobstation/Bingle/BinglePitSystem.cs b/Content.Server/_Goobstation/Bingle/BinglePitSystem.cs new file mode 100644 index 0000000000..cea0ac3199 --- /dev/null +++ b/Content.Server/_Goobstation/Bingle/BinglePitSystem.cs @@ -0,0 +1,177 @@ +using System.Numerics; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Timing; +using Robust.Server.GameObjects; +using Content.Server.Stunnable; +using Content.Shared.Ghost.Roles.Components; +using Content.Shared.StepTrigger.Systems; +using Content.Shared.Mobs.Components; +using Content.Shared.Destructible; +using Content.Shared.Stunnable; +using Content.Shared.Humanoid; +using Content.Shared.Weapons.Melee.Events; +using Content.Shared.Movement.Events; +using Content.Shared._Goobstation.Bingle; +using Content.Shared.Popups; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; + +namespace Content.Server._Goobstation.Bingle; + +public sealed class BinglePitSystem : EntitySystem +{ + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly BingleSystem _bingleSystem = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly StunSystem _stun = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly PullingSystem _pulling = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnStepTriggered); + SubscribeLocalEvent(OnStepTriggerAttempt); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnDestruction); + SubscribeLocalEvent(OnAttacked); + SubscribeLocalEvent(OnUpdateCanMove); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var falling)) + { + if (_timing.CurTime < falling.NextDeletionTime) + continue; + + _containerSystem.Insert(uid, falling.Pit.Pit); + EnsureComp(uid); // used stuned to prevent any funny being done inside the pit + RemCompDeferred(uid, falling); + } + } + + private void OnInit(EntityUid uid, BinglePitComponent component, MapInitEvent args) + { + if (!Transform(uid).Coordinates.IsValid(EntityManager)) + QueueDel(uid); + component.Pit = _containerSystem.EnsureContainer(uid, "pit"); + } + + private void OnStepTriggered(EntityUid uid, BinglePitComponent component, ref StepTriggeredOffEvent args) + { + // dont swallow bingles + if (HasComp(args.Tripper)) + return; + // need to be at levl 2 or above to swallow anything alive + if (HasComp(args.Tripper) && component.Level < 2) + return; + if (HasComp(args.Tripper)) + return; + + StartFalling(uid, component, args.Tripper); + + if (component.BinglePoints >= component.SpawnNewAt) + { + SpawnBingle(uid, component); + component.BinglePoints -= component.SpawnNewAt; + } + } + + public void StartFalling(EntityUid uid, BinglePitComponent component, EntityUid tripper, bool playSound = true) + { + component.BinglePoints += HasComp(tripper) + ? component.PointsForAlive + (HasComp(tripper) + ? component.AdditionalPointsForHuman : 0) : 1; + + if (TryComp(tripper, out var pullable) && pullable.BeingPulled) + _pulling.TryStopPull(tripper, pullable); + + var fall = EnsureComp(tripper); + fall.Pit = component; + fall.NextDeletionTime = _timing.CurTime + fall.DeletionTime; + _stun.TryKnockdown(tripper, fall.DeletionTime, false); + + if (playSound) + _audio.PlayPvs(component.FallingSound, uid); + + } + + private void OnStepTriggerAttempt(EntityUid uid, BinglePitComponent component, ref StepTriggerAttemptEvent args) + => args.Continue = true; + + public void SpawnBingle(EntityUid uid, BinglePitComponent component) + { + Spawn(component.GhostRoleToSpawn, Transform(uid).Coordinates); + + component.MinionsMade++; + if (component.MinionsMade >= component.UpgradeMinionsAfter) + { + component.MinionsMade = 0; + component.Level++; + UpgradeBingles(uid, component); + } + } + + public void UpgradeBingles(EntityUid uid, BinglePitComponent component) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var queryUid, out var queryBingleComp)) + if (queryBingleComp.MyPit != null && queryBingleComp.MyPit.Value == uid) + _bingleSystem.UpgradeBingle(queryUid, queryBingleComp); + if (component.Level <= component.MaxSize) + ScaleUpPit(uid, component); + + _popup.PopupEntity(Loc.GetString("bingle-pit-grow"), uid); + } + + private void OnDestruction(EntityUid uid, BinglePitComponent component, DestructionEventArgs args) + { + if (component.Pit != null) + foreach (var pitUid in _containerSystem.EmptyContainer(component.Pit)) + { + RemComp(pitUid); + _stun.TryKnockdown(pitUid, TimeSpan.FromSeconds(2), false); + } + + RemoveAllBingleGhostRoles(uid, component);//remove all unclaimed ghostroles when pit is destroyed + + //Remove all falling when pit is destroyed, in the small chance somone is inbetween start and insert + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var fallingUid, out var fallingComp)) + RemCompDeferred(fallingUid, fallingComp); + } + + public void RemoveAllBingleGhostRoles(EntityUid uid, BinglePitComponent component) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var queryGRMSUid, out var queryGRMScomp)) + if (queryGRMScomp.Prototype == "MobBingle") + if (Transform(uid).Coordinates == Transform(queryGRMSUid).Coordinates) + QueueDel(queryGRMSUid); // remove any unspawned bngle when pit is destroyed + } + private void OnAttacked(EntityUid uid, BinglePitComponent component, AttackedEvent args) + { + if (_containerSystem.ContainsEntity(uid, args.User)) + EnsureComp(args.User); + } + + private void OnUpdateCanMove(EntityUid uid, BinglePitFallingComponent component, UpdateCanMoveEvent args) + => args.Cancel(); + + private void ScaleUpPit(EntityUid uid, BinglePitComponent component) + { + if (!TryComp(uid, out var appearanceComponent)) + appearanceComponent = _entityManager.EnsureComponent(uid); + var appearance = _entityManager.System(); + _entityManager.EnsureComponent(uid); + + appearance.SetData(uid, ScaleVisuals.Scale, Vector2.One * component.Level, appearanceComponent); + } +} diff --git a/Content.Server/_Goobstation/Bingle/BingleSystem.cs b/Content.Server/_Goobstation/Bingle/BingleSystem.cs new file mode 100644 index 0000000000..c272529934 --- /dev/null +++ b/Content.Server/_Goobstation/Bingle/BingleSystem.cs @@ -0,0 +1,64 @@ +using Content.Shared.Weapons.Melee; +using Content.Shared.Interaction.Events; +using Content.Shared.Popups; +using Content.Shared._Goobstation.Bingle; +using Robust.Shared.Map; +using System.Numerics; + +namespace Content.Server._Goobstation.Bingle; + +public sealed class BingleSystem : EntitySystem +{ + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnAttackAttempt); + } + + private void OnMapInit(EntityUid uid, BingleComponent component, MapInitEvent args) + { + var cords = Transform(uid).Coordinates; + if (!cords.IsValid(EntityManager) || cords.Position == Vector2.Zero) + return; + if (MapId.Nullspace == Transform(uid).MapID) + return; + + if (component.Prime) + component.MyPit = Spawn("BinglePit", cords); + else + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var queryUid, out var _)) + if (cords == Transform(queryUid).Coordinates) + component.MyPit = queryUid; + } + } + + //ran by the pit to upgrade bingle damage + public void UpgradeBingle(EntityUid uid, BingleComponent component) + { + if (component.Upgraded) + return; + if (!TryComp(uid, out var weponComp)) + return; + + weponComp.Damage = component.UpgradeDamage; + component.Upgraded = true; + Dirty(uid, weponComp); + + _popup.PopupEntity(Loc.GetString("bingle-upgrade-success"), uid, uid); + + RaiseNetworkEvent(new BingleUpgradeEntityMessage(GetNetEntity(uid))); + } + + private void OnAttackAttempt(EntityUid uid, BingleComponent component, AttackAttemptEvent args) + { + //Prevent Friendly Bingle fire + if (HasComp(args.Target) || HasComp(args.Target)) + args.Cancel(); + } +} + diff --git a/Content.Shared/_Goobstation/Bingle/BingleComponent.cs b/Content.Shared/_Goobstation/Bingle/BingleComponent.cs new file mode 100644 index 0000000000..903bb7e265 --- /dev/null +++ b/Content.Shared/_Goobstation/Bingle/BingleComponent.cs @@ -0,0 +1,31 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; +using Content.Shared.Damage; +using Robust.Shared.Network; + +namespace Content.Shared._Goobstation.Bingle; + +[RegisterComponent, NetworkedComponent] +public sealed partial class BingleComponent : Component +{ + [DataField] + public bool Upgraded = false; + [DataField] + public DamageSpecifier UpgradeDamage = default!; + [DataField] + public bool Prime = false; + + public EntityUid? MyPit; +} +[Serializable, NetSerializable] +public sealed class BingleUpgradeEntityMessage(NetEntity bingle) : EntityEventArgs +{ + public NetEntity Bingle = bingle; +} + +[Serializable, NetSerializable] +public enum BingleVisual : byte +{ + Upgraded, + Combat +} diff --git a/Content.Shared/_Goobstation/Bingle/BinglePitComponent.cs b/Content.Shared/_Goobstation/Bingle/BinglePitComponent.cs new file mode 100644 index 0000000000..6e99b0ae5a --- /dev/null +++ b/Content.Shared/_Goobstation/Bingle/BinglePitComponent.cs @@ -0,0 +1,45 @@ +using Robust.Shared.Containers; +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; + +namespace Content.Shared._Goobstation.Bingle; + +[RegisterComponent] +public sealed partial class BinglePitComponent : Component +{ + /// + /// ammount of stored + /// + [DataField] + public float BinglePoints = 0f; + public float PointsForAlive = 5f; + public float AdditionalPointsForHuman = 5f; + /// + /// amount of Bingle Points needed for a new bingle + /// + [DataField] + public float SpawnNewAt = 10f; + + /// + /// amount bingles needed to evolve / gain a level / expand the ... THE FACTORY MUST GROW + /// + [DataField] + public float MinionsMade = 0f; + + [DataField] + public float UpgradeMinionsAfter = 12f; + + /// + /// the Bingle pit's level + /// + [DataField] + public float Level = 1f; + /// + /// Where the entities go when it falls into the pit, empties when it is destroyed. + /// + public Container Pit = default!; + [DataField] + public float MaxSize = 3f; + public SoundSpecifier FallingSound = new SoundPathSpecifier("/Audio/Effects/falling.ogg"); + public EntProtoId GhostRoleToSpawn = "SpawnPointGhostBingle"; +} diff --git a/Content.Shared/_Goobstation/Bingle/BinglePitFallingComponent.cs b/Content.Shared/_Goobstation/Bingle/BinglePitFallingComponent.cs new file mode 100644 index 0000000000..f0a96b01fc --- /dev/null +++ b/Content.Shared/_Goobstation/Bingle/BinglePitFallingComponent.cs @@ -0,0 +1,40 @@ +using System.Numerics; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared._Goobstation.Bingle; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] +public sealed partial class BinglePitFallingComponent : Component +{ + /// + /// Time it should take for the falling animation (scaling down) to complete. + /// + [DataField("animationTime")] + public TimeSpan AnimationTime = TimeSpan.FromSeconds(1.5f); + + /// + /// Time it should take in seconds for the entity to actually delete + /// + [DataField("deletionTime")] + public TimeSpan DeletionTime = TimeSpan.FromSeconds(1.8f); + + [DataField("nextDeletionTime", customTypeSerializer:typeof(TimeOffsetSerializer))] + [AutoPausedField] + public TimeSpan NextDeletionTime = TimeSpan.Zero; + + /// + /// Original scale of the object so it can be restored if the component is removed in the middle of the animation + /// + public Vector2 OriginalScale = Vector2.Zero; + + /// + /// Scale that the animation should bring entities to. + /// + public Vector2 AnimationScale = new Vector2(0.01f, 0.01f); + + /// + /// the pit your about to fall into + /// + public BinglePitComponent Pit = new BinglePitComponent(); +} diff --git a/Resources/Locale/en-US/_Goobstation/bingle/bingle.ftl b/Resources/Locale/en-US/_Goobstation/bingle/bingle.ftl new file mode 100644 index 0000000000..b0595e478c --- /dev/null +++ b/Resources/Locale/en-US/_Goobstation/bingle/bingle.ftl @@ -0,0 +1,20 @@ + +bingle-accent-1 = Bingle +bingle-accent-2 = Bing +bingle-accent-3 = Bongle +bingle-accent-4 = Bong +bingle-accent-5 = BINGLE + +chat-speech-verb-name-bingle = Bingle +bingle-verb-1 = Croaks +bingle-verb-2 = Mumbles +bingle-verb-3 = Harks +bingle-verb-4 = Grumbles + +bingle-station-announcement = Bingle Bingle Bingle + +ghost-role-information-bingle-name = Bingle +ghost-role-information-bingle-description = The Pit is love. The Pit is life. The Pit must grow + +bingle-upgrade-success = You feel stronger +bingle-pit-grow = The pit grows larger diff --git a/Resources/Prototypes/Entities/Structures/Specific/Binglepit.yml b/Resources/Prototypes/Entities/Structures/Specific/Binglepit.yml new file mode 100644 index 0000000000..e7adc03a2e --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Specific/Binglepit.yml @@ -0,0 +1,62 @@ +- type: entity + id: BinglePit + name: binglepit + description: Looks Hungry + placement: + mode: SnapgridCenter + components: + - type: BinglePit + - type: StepTrigger + requiredTriggeredSpeed: 0 + intersectRatio: 0.4 + blacklist: + tags: + - Catwalk + triggerGroups: + types: + - Chasm + - type: Transform + anchored: true + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,0.5" + layer: + - WallLayer + mask: + - ItemMask + density: 1000 + hard: false + - type: Sprite + drawdepth: FloorTiles + layers: + - sprite: _Goobstation/Mobs/Bingle/bingle.rsi + state: pit + - type: InteractionOutline + - type: Clickable + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Metallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 256 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: EmitSoundOnSpawn + sound: + path: /Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg + - type: RequireProjectileTarget + - type: SolutionContainerManager + solutions: + drainBuffer: + maxVol: 1000 + - type: Drain + unitsPerSecond: 10 + unitsDestroyedPerSecond: 10 diff --git a/Resources/Prototypes/_Goobstation/Accents/full_replacements.yml b/Resources/Prototypes/_Goobstation/Accents/full_replacements.yml new file mode 100644 index 0000000000..e8e46d0d01 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/Accents/full_replacements.yml @@ -0,0 +1,21 @@ +# Accents that work off of full replacements rather than word replacements. + +- type: accent + id: gondola + fullReplacements: + - accent-words-gondola-1 + +- type: accent + id: bingle + fullReplacements: + - bingle-accent-1 # for the odds + - bingle-accent-1 + - bingle-accent-1 + - bingle-accent-1 + - bingle-accent-1 + - bingle-accent-1 + - bingle-accent-1 + - bingle-accent-2 + - bingle-accent-3 + - bingle-accent-4 + - bingle-accent-5 diff --git a/Resources/Prototypes/_Goobstation/Entities/Markers/Spawners/bingle.yml b/Resources/Prototypes/_Goobstation/Entities/Markers/Spawners/bingle.yml new file mode 100644 index 0000000000..72195d1b5f --- /dev/null +++ b/Resources/Prototypes/_Goobstation/Entities/Markers/Spawners/bingle.yml @@ -0,0 +1,28 @@ +- type: entity + id: SpawnPointGhostBingle + name: ghost role spawn point + suffix: Bingle + parent: MarkerBase + components: + - type: GhostRole + name: ghost-role-information-bingle-name + description: ghost-role-information-bingle-description + rules: ghost-role-information-freeagent-rules + raffle: + settings: short + - type: GhostRoleMobSpawner + prototype: MobBingle + - type: Sprite + sprite: Markers/jobs.rsi + layers: + - state: green + - sprite: _Goobstation/Mobs/Bingle/bingle.rsi + state: icon + +- type: entity + id: SpawnPointGhostBinglePrime + parent: SpawnPointGhostBingle + suffix: Prime + components: + - type: GhostRoleMobSpawner + prototype: MobBinglePrime diff --git a/Resources/Prototypes/_Goobstation/Entities/Mobs/Player/bingle.yml b/Resources/Prototypes/_Goobstation/Entities/Mobs/Player/bingle.yml new file mode 100644 index 0000000000..7153c49a5f --- /dev/null +++ b/Resources/Prototypes/_Goobstation/Entities/Mobs/Player/bingle.yml @@ -0,0 +1,104 @@ +- type: entity + name: bingle + id: MobBingle + parent: MobSpaceBasic + description: bingle + components: + - type: Bingle + upgradeDamage: + types: + Blunt: 14 + Structural: 28 + - type: GhostTakeoverAvailable + - type: GhostRole + name: ghost-role-information-bingle-name + description: ghost-role-information-bingle-description + rules: ghost-role-information-freeagent-rules + raffle: + settings: short + - type: Sprite + drawdepth: Mobs + sprite: _Goobstation/Mobs/Bingle/bingle.rsi + layers: + - map: ["enum.DamageStateVisualLayers.Base", "movement"] + state: alive + - map: ["enum.BingleVisual.Upgraded"] + state: Upgraded + visible: false + - map: ["enum.BingleVisual.Combat"] + state: combat + visible: false + - type: MobThresholds + thresholds: + 0: Alive + 140: Dead # by request + - type: MobState + allowedStates: + - Alive + - Dead + - type: DamageStateVisuals + rotate: true + states: + Alive: + Base: alive + Dead: + Base: dead + - type: Bloodstream + bloodMaxVolume: 100 + bloodReagent: Nitrogen # by request + - type: MeleeWeapon + soundHit: + path: /Audio/Weapons/Xeno/alien_claw_flesh3.ogg + angle: 0 + wideAnimationRotation: 0 + animation: WeaponArcSlash + damage: + types: + Blunt: 7 + Structural: 14 # breaks down the walls and airlocks in 10 hits + bluntStaminaDamageFactor: 2.0 + - type: MovementSpeedModifier + baseWalkSpeed : 2 # same as slime + baseSprintSpeed : 4 + - type: Stamina + critThreshold: 120 + - type: StaminaDamageOnHit # from stunbaton + damage: 15 + overtime: 40 + sound: /Audio/Weapons/egloves.ogg + - type: Damageable + damageContainer: OrganicPart # unsure if this is the right type + damageModifierSet: Bingle + - type: FootstepModifier + footstepSoundCollection: + path: /Audio/Effects/Footsteps/slime1.ogg + params: + volume: 3 + - type: TypingIndicator + proto: alien + - type: Speech + speechVerb: Bingle + speechSounds: Slime + - type: ReplacementAccent # prevent talking + accent: bingle + - type: PassiveDamage #passive Healing + allowedStates: + - Alive + damage: + types: + Poison: -0.1 + groups: + Brute: -0.1 + Burn: -0.1 + - type: NightVision + color: "#008080" + activateSound: null + deactivateSound: null + +- type: entity + id: MobBinglePrime + parent: MobBingle + suffix: Prime + components: + - type: Bingle + prime: true diff --git a/Resources/Prototypes/_Goobstation/GameRules/bingleEvent.yml b/Resources/Prototypes/_Goobstation/GameRules/bingleEvent.yml new file mode 100644 index 0000000000..087cba6897 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/GameRules/bingleEvent.yml @@ -0,0 +1,14 @@ +- type: entity + id: BingleSpawn + parent: BaseStationEventShortDelay + components: + - type: StationEvent + startAnnouncement: bingle-station-announcement + startAudio: + path: /Audio/Announcements/attention.ogg + earliestStart: 20 + weight: 6 + duration: 50 + minimumPlayers: 15 + - type: RandomSpawnRule + prototype: SpawnPointGhostBinglePrime diff --git a/Resources/Prototypes/_Goobstation/Voice/speech_verbs.yml b/Resources/Prototypes/_Goobstation/Voice/speech_verbs.yml index 52a8d0d40e..ebce1c50be 100644 --- a/Resources/Prototypes/_Goobstation/Voice/speech_verbs.yml +++ b/Resources/Prototypes/_Goobstation/Voice/speech_verbs.yml @@ -6,3 +6,36 @@ path: /Audio/Machines/beep.ogg exclaimSound: path: /Audio/Machines/beep.ogg + +- type: speechVerb + id: Dead + name: chat-speech-verb-name-dead + speechVerbStrings: + - chat-speech-verb-dead-1 + - chat-speech-verb-dead-2 + - chat-speech-verb-dead-3 + - chat-speech-verb-dead-4 + - chat-speech-verb-dead-5 + - chat-speech-verb-dead-6 + - chat-speech-verb-dead-7 + - chat-speech-verb-dead-8 + - chat-speech-verb-dead-9 + +- type: speechVerb + id: VoiceModulator + name: chat-speech-verb-VoiceModulator-name + speechVerbStrings: + - chat-speech-verb-VoiceModulator-1 + - chat-speech-verb-VoiceModulator-2 + - chat-speech-verb-VoiceModulator-3 + - chat-speech-verb-VoiceModulator-4 + - chat-speech-verb-VoiceModulator-5 + +- type: speechVerb + id: Bingle + name: chat-speech-verb-name-bingle + speechVerbStrings: + - bingle-verb-1 + - bingle-verb-2 + - bingle-verb-3 + - bingle-verb-4 diff --git a/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/Upgraded.png b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/Upgraded.png new file mode 100644 index 0000000000..6877c80670 Binary files /dev/null and b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/Upgraded.png differ diff --git a/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/alive.png b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/alive.png new file mode 100644 index 0000000000..8684a63cee Binary files /dev/null and b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/alive.png differ diff --git a/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/combat.png b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/combat.png new file mode 100644 index 0000000000..df53764118 Binary files /dev/null and b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/combat.png differ diff --git a/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/dead.png b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/dead.png new file mode 100644 index 0000000000..82d1c47d3f Binary files /dev/null and b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/dead.png differ diff --git a/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/icon.png b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/icon.png new file mode 100644 index 0000000000..a551757224 Binary files /dev/null and b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/icon.png differ diff --git a/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/meta.json b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/meta.json new file mode 100644 index 0000000000..f9b9f4472d --- /dev/null +++ b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/meta.json @@ -0,0 +1,39 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Brainrot HQ", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "alive", + "directions": 4 + }, + { + "name": "pit", + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "icon" + }, + { + "name": "dead" + }, + { + "name": "Upgraded", + "directions": 4 + }, + { + "name": "combat", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/pit.png b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/pit.png new file mode 100644 index 0000000000..8c9e88cc44 Binary files /dev/null and b/Resources/Textures/_Goobstation/Mobs/Bingle/bingle.rsi/pit.png differ