Skip to content

Commit

Permalink
make dragons breathe fire (#26746)
Browse files Browse the repository at this point in the history
* add ActionGun system

* add RepeatingTrigger

* dragons breath projectile, repeatedly explodes

* give dragon fire breathing action, fireproof it

* oop

* oop 2

* prevent troll

* proper repeating thing

* pro

* webedit ops

* realops

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
  • Loading branch information
deltanedas authored and dvir001 committed Jun 1, 2024
1 parent 8d184dc commit 3e6ca21
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 3 deletions.
7 changes: 7 additions & 0 deletions Content.Server/Explosion/Components/ExplosiveComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ public sealed partial class ExplosiveComponent : Component
[DataField("deleteAfterExplosion")]
public bool? DeleteAfterExplosion;

/// <summary>
/// Whether to not set <see cref="Exploded"/> to true, allowing it to explode multiple times.
/// This should never be used if it is damageable.
/// </summary>
[DataField]
public bool Repeatable;

/// <summary>
/// Avoid somehow double-triggering this explosion (e.g. by damaging this entity from its own explosion.
/// </summary>
Expand Down
25 changes: 25 additions & 0 deletions Content.Server/Explosion/Components/RepeatingTriggerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Content.Server.Explosion.EntitySystems;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;

namespace Content.Server.Explosion.Components;

/// <summary>
/// Constantly triggers after being added to an entity.
/// </summary>
[RegisterComponent, Access(typeof(TriggerSystem))]
[AutoGenerateComponentPause]
public sealed partial class RepeatingTriggerComponent : Component
{
/// <summary>
/// How long to wait between triggers.
/// The first trigger starts this long after the component is added.
/// </summary>
[DataField]
public TimeSpan Delay = TimeSpan.FromSeconds(1);

/// <summary>
/// When the next trigger will be.
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
public TimeSpan NextTrigger;
}
2 changes: 1 addition & 1 deletion Content.Server/Explosion/EntitySystems/ExplosionSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null
if (explosive.Exploded)
return;

explosive.Exploded = true;
explosive.Exploded = !explosive.Repeatable;

// Override the explosion intensity if optional arguments were provided.
if (radius != null)
Expand Down
21 changes: 21 additions & 0 deletions Content.Server/Explosion/EntitySystems/TriggerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public override void Initialize()
SubscribeLocalEvent<TriggerOnStepTriggerComponent, StepTriggeredOffEvent>(OnStepTriggered);
SubscribeLocalEvent<TriggerOnSlipComponent, SlipEvent>(OnSlipTriggered);
SubscribeLocalEvent<TriggerWhenEmptyComponent, OnEmptyGunShotEvent>(OnEmptyTriggered);
SubscribeLocalEvent<RepeatingTriggerComponent, MapInitEvent>(OnRepeatInit);

SubscribeLocalEvent<SpawnOnTriggerComponent, TriggerEvent>(OnSpawnTrigger);
SubscribeLocalEvent<DeleteOnTriggerComponent, TriggerEvent>(HandleDeleteTrigger);
Expand Down Expand Up @@ -278,6 +279,11 @@ private void OnEmptyTriggered(EntityUid uid, TriggerWhenEmptyComponent component
Trigger(uid, args.EmptyGun);
}

private void OnRepeatInit(Entity<RepeatingTriggerComponent> ent, ref MapInitEvent args)
{
ent.Comp.NextTrigger = _timing.CurTime + ent.Comp.Delay;
}

public bool Trigger(EntityUid trigger, EntityUid? user = null)
{
var triggerEvent = new TriggerEvent(trigger, user);
Expand Down Expand Up @@ -360,6 +366,7 @@ public override void Update(float frameTime)
UpdateProximity();
UpdateTimer(frameTime);
UpdateTimedCollide(frameTime);
UpdateRepeat();
}

private void UpdateTimer(float frameTime)
Expand Down Expand Up @@ -394,5 +401,19 @@ private void UpdateTimer(float frameTime)
_appearance.SetData(uid, TriggerVisuals.VisualState, TriggerVisualState.Unprimed, appearance);
}
}

private void UpdateRepeat()
{
var now = _timing.CurTime;
var query = EntityQueryEnumerator<RepeatingTriggerComponent>();
while (query.MoveNext(out var uid, out var comp))
{
if (comp.NextTrigger > now)
continue;

comp.NextTrigger = now + comp.Delay;
Trigger(uid);
}
}
}
}
37 changes: 37 additions & 0 deletions Content.Shared/Weapons/Ranged/Components/ActionGunComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Content.Shared.Actions;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared.Weapons.Ranged.Components;

/// <summary>
/// Lets you shoot a gun using an action.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(ActionGunSystem))]
public sealed partial class ActionGunComponent : Component
{
/// <summary>
/// Action to create, must use <see cref="ActionGunShootEvent"/>.
/// </summary>
[DataField(required: true)]
public EntProtoId Action = string.Empty;

[DataField]
public EntityUid? ActionEntity;

/// <summary>
/// Prototype of gun entity to spawn.
/// Deleted when this component is removed.
/// </summary>
[DataField(required: true)]
public EntProtoId GunProto = string.Empty;

[DataField]
public EntityUid? Gun;
}

/// <summary>
/// Action event for <see cref="ActionGunComponent"/> to shoot at a position.
/// </summary>
public sealed partial class ActionGunShootEvent : WorldTargetActionEvent;
41 changes: 41 additions & 0 deletions Content.Shared/Weapons/Ranged/Systems/ActionGunSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Content.Shared.Actions;
using Content.Shared.Weapons.Ranged.Components;

namespace Content.Shared.Weapons.Ranged.Systems;

public sealed class ActionGunSystem : EntitySystem
{
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly SharedGunSystem _gun = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<ActionGunComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<ActionGunComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<ActionGunComponent, ActionGunShootEvent>(OnShoot);
}

private void OnMapInit(Entity<ActionGunComponent> ent, ref MapInitEvent args)
{
if (string.IsNullOrEmpty(ent.Comp.Action))
return;

_actions.AddAction(ent, ref ent.Comp.ActionEntity, ent.Comp.Action);
ent.Comp.Gun = Spawn(ent.Comp.GunProto);
}

private void OnShutdown(Entity<ActionGunComponent> ent, ref ComponentShutdown args)
{
if (ent.Comp.Gun is {} gun)
QueueDel(gun);
}

private void OnShoot(Entity<ActionGunComponent> ent, ref ActionGunShootEvent args)
{
if (TryComp<GunComponent>(ent.Comp.Gun, out var gun))
_gun.AttemptShoot(ent, ent.Comp.Gun.Value, gun, args.Target);
}
}

48 changes: 46 additions & 2 deletions Resources/Prototypes/Entities/Mobs/Player/dragon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@
speedModifierThresholds:
250: 0.7
400: 0.5
# disable taking damage from fire, since its a fire breathing dragon
- type: Flammable
damage:
types: {}
- type: Temperature
heatDamageThreshold: 800
- type: Metabolizer
solutionOnBody: false
updateInterval: 0.25
Expand Down Expand Up @@ -134,15 +140,37 @@
- type: entity
parent: BaseMobDragon
id: MobDragon
suffix: No role or objectives
components:
- type: Dragon
spawnRiftAction: ActionSpawnRift
# - type: GenericAntag
# rule: Dragon
- type: ActionGun
action: ActionDragonsBreath
gunProto: DragonsBreathGun
- type: GuideHelp
guides:
- MinorAntagonists

- type: entity
noSpawn: true
id: DragonsBreathGun
name: dragon's lung
description: For dragon's breathing
components:
- type: RechargeBasicEntityAmmo
rechargeCooldown: 5
rechargeSound:
path: /Audio/Animals/space_dragon_roar.ogg
- type: BasicEntityAmmoProvider
proto: ProjectileDragonsBreath
capacity: 1
count: 1
- type: Gun
soundGunshot:
path: /Audio/Animals/space_dragon_roar.ogg
soundEmpty: null
projectileSpeed: 5

- type: entity
parent: BaseMobDragon
id: MobDragonDungeon
Expand Down Expand Up @@ -181,6 +209,7 @@
state: icon
event: !type:DragonSpawnRiftActionEvent
useDelay: 1
priority: 3

- type: entity
id: ActionDevour
Expand All @@ -192,3 +221,18 @@
icon: { sprite : Interface/Actions/devour.rsi, state: icon }
iconOn: { sprite : Interface/Actions/devour.rsi, state: icon-on }
event: !type:DevourActionEvent
priority: 1

- type: entity
noSpawn: true
id: ActionDragonsBreath
name: "[color=orange]Dragon's Breath[/color]"
description: Spew out flames at anyone foolish enough to attack you!
components:
- type: WorldTargetAction
# TODO: actual sprite
icon: { sprite : Objects/Weapons/Guns/Projectiles/magic.rsi, state: fireball }
event: !type:ActionGunShootEvent
priority: 2
checkCanAccess: false
range: 0
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,39 @@
- type: IgniteOnCollide
fireStacks: 0.35

- type: entity
noSpawn: true
parent: BaseBulletTrigger
id: ProjectileDragonsBreath
name: dragon's breath
description: Try not to get toasted.
components:
- type: PointLight
color: "#E25822"
radius: 3.0
energy: 5.0
- type: Sprite
sprite: Objects/Weapons/Guns/Projectiles/magic.rsi
layers:
- state: fireball
shader: unshaded
- type: IgnitionSource
temperature: 1000
ignited: true
- type: RepeatingTrigger
delay: 0.5 # line of fire as well as if it hits something
- type: ExplodeOnTrigger
- type: Explosive
explosionType: FireBomb
totalIntensity: 5 # low intensity, the point is to burn attackers not to break open walls, dragons can just eat them
intensitySlope: 1
maxIntensity: 3
canCreateVacuum: false
deleteAfterExplosion: false
repeatable: true
- type: TimedDespawn
lifetime: 5

- type: entity
id: ProjectileAnomalyFireball
name: fireball
Expand Down

0 comments on commit 3e6ca21

Please sign in to comment.