Xenoborg Nanite Gun + ComplexProjectileComponent (#43120)

* Xenoborg Nanite Gun

* Fix Sprite

* All the C# + Bullet Impact

* Muzzle flash + module

* Audio + Mag Sprites + Broken Crystals

* Fix fails + description

* fix

* Requested Changes Thanks B-krill :)

* Change healing values to 8

* Fix fails mayhaps

* Tweak Balancing two

* Balance changes final

* Requested chnages

* Cartridge Resprite

* New sounds by Sadie :D

* unrelated test

* Forgot to make module sprites

* Beck Changes

* Fix?

* New sprites :/

* Thanks Samuka :)

* Fix failure thanks orks :)

* Muzzle flash

* FURTHERgit add -A

* offset change

* Requested changes

* oops

* add whiteline

* make it for all borgs

* revert to whatever

* old sprites yay

* Fix heisentest

* oops

* new sprites

* fix

* description change

* ammo sprites

* attributions

* fifty commits yaygit add -A

* wtf

* MACROBALANCE RAHH

---------

Co-authored-by: beck-thompson <beck314159@hotmail.com>
Co-authored-by: Samuel-C <samuelcamilo8@gmail.com>
This commit is contained in:
Rami 2026-08-03 09:40:13 -07:00 • committed by GitHub
parent c89c01afc0
commit bcf6324781
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 359 additions and 5 deletions

View file

@ -46,7 +46,9 @@ public sealed partial class ProjectileSystem : SharedProjectileSystem
return;
}
var ev = new ProjectileHitEvent(component.Damage * _damageableSystem.UniversalProjectileDamageModifier, target, component.Shooter);
var damageEv = new BeforeProjectileHitEvent(component.Damage, target, component.Shooter);
RaiseLocalEvent(uid, ref damageEv);
var ev = new ProjectileHitEvent(damageEv.Damage * _damageableSystem.UniversalProjectileDamageModifier, target, component.Shooter);
RaiseLocalEvent(uid, ref ev);
var otherName = ToPrettyString(target);

View file

@ -0,0 +1,52 @@
using Content.Shared.Damage;
using Content.Shared.Whitelist;
using Robust.Shared.GameStates;
namespace Content.Shared.Projectiles;
/// <summary>
/// A projectile with this component will not deal <see cref="ProjectileComponent.Damage"/>.
/// Instead, it will do damage based on the target if
/// said target passes the whitelist and blacklist of the options
/// </summary>
/// <remarks>
/// If the target doesn't match any option, the projectile will deal <see cref="ProjectileComponent.Damage"/>.
/// </remarks>
[RegisterComponent, NetworkedComponent]
public sealed partial class ComplexProjectileDamageComponent : Component
{
/// <summary>
/// Array of options of damage for specific entities.
/// </summary>
/// <remarks>
/// Only one option will choosen, if a target fits 2 options,
/// it will receive damage only from the first option that matches.
/// </remarks>
[DataField]
public DamageOption[] DamageOptions = [];
}
/// <summary>
/// Specifies a amount of damage to deal to entities that fit the whitelist and are not blacklisted.
/// </summary>
[DataDefinition]
public partial struct DamageOption
{
/// <summary>
/// The damage to deal to certain entities.
/// </summary>
[DataField]
public DamageSpecifier Damage;
/// <summary>
/// The whitelist of entities to deal the damage to.
/// </summary>
[DataField]
public EntityWhitelist? Whitelist;
/// <summary>
/// The blacklist of entities to not deal the damage to.
/// </summary>
[DataField]
public EntityWhitelist? Blacklist;
}

View file

@ -5,6 +5,7 @@ using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Throwing;
using Content.Shared.Whitelist;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Network;
@ -26,6 +27,7 @@ public abstract partial class SharedProjectileSystem : EntitySystem
[Dependency] private SharedHandsSystem _hands = default!;
[Dependency] private SharedPhysicsSystem _physics = default!;
[Dependency] private SharedTransformSystem _transform = default!;
[Dependency] private EntityWhitelistSystem _whitelist = null!;
public override void Initialize()
{
@ -39,6 +41,7 @@ public abstract partial class SharedProjectileSystem : EntitySystem
SubscribeLocalEvent<EmbeddableProjectileComponent, ComponentShutdown>(OnEmbeddableCompShutdown);
SubscribeLocalEvent<EmbeddedContainerComponent, EntityTerminatingEvent>(OnEmbeddableTermination);
SubscribeLocalEvent<ComplexProjectileDamageComponent, BeforeProjectileHitEvent>(OnBeforeComplexProjectileHit);
}
private void OnEmbedActivate(Entity<EmbeddableProjectileComponent> embeddable, ref ActivateInWorldEvent args)
@ -188,6 +191,17 @@ public abstract partial class SharedProjectileSystem : EntitySystem
DetachAllEmbedded(container);
}
private void OnBeforeComplexProjectileHit(Entity<ComplexProjectileDamageComponent> ent, ref BeforeProjectileHitEvent args)
{
foreach (var option in ent.Comp.DamageOptions)
{
if (!_whitelist.CheckBoth(args.Target, option.Blacklist, option.Whitelist))
continue;
args.Damage = option.Damage;
return;
}
}
public void DetachAllEmbedded(Entity<EmbeddedContainerComponent> container)
{
foreach (var embedded in container.Comp.EmbeddedObjects)
@ -250,3 +264,9 @@ public record struct ProjectileReflectAttemptEvent(EntityUid ProjUid, Projectile
/// </summary>
[ByRefEvent]
public record struct ProjectileHitEvent(DamageSpecifier Damage, EntityUid Target, EntityUid? Shooter = null);
/// <summary>
/// Raised before a projectile hits an entity
/// </summary>
[ByRefEvent]
public record struct BeforeProjectileHitEvent(DamageSpecifier Damage, EntityUid Target, EntityUid? Shooter = null);

View file

@ -52,3 +52,8 @@
license: "CC-BY-4.0"
copyright: "Created by simeonradivoev"
source: "https://freesound.org/people/simeonradivoev/sounds/740218"
- files: ["nanite_gun.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Created by sadiefei"
source: "https://freesound.org/people/torn.rugged.audio.35/sounds/45934/"

Binary file not shown.

View file

@ -6,4 +6,9 @@
- files: ["ric1.ogg", "ric2.ogg", "ric3.ogg", "ric3.ogg", "ric5.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Taken from tgstation"
source: "https://github.com/tgstation/tgstation/tree/7501504b0ea029d2cf1c0336d09db5c0959aa412/sound/weapons/effects"
source: "https://github.com/tgstation/tgstation/tree/7501504b0ea029d2cf1c0336d09db5c0959aa412/sound/weapons/effects"
- files: ["nanite_hit1.ogg", "nanite_hit2.ogg", "nanitehit_3.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Created by sadiefei"
source: "https://github.com/tgstation/tgstation/tree/7501504b0ea029d2cf1c0336d09db5c0959aa412/sound/weapons/effects"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1572,6 +1572,22 @@
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-oil-gun-module }
- type: entity
parent: [ BaseXenoborgModuleEngi, BaseProviderBorgModule, BaseXenoborgContraband ]
id: XenoborgModuleNaniteGun
name: nanite gun xenoborg module
description: Module that allows Xenoborgs to have a crystal firing nanite gun.
components:
- type: Sprite
layers:
- state: xenoborg_engi
- state: icon-xenoborg-nanite-gun
- type: ItemBorgModule
hands:
- item: WeaponNaniteGun
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-nanite-module }
- type: entity
parent: [ BaseXenoborgModuleHeavy, BaseProviderBorgModule, BaseXenoborgContraband ]
id: XenoborgModuleJammer

View file

@ -0,0 +1,22 @@
- type: entity
parent: [ BaseCartridge, BaseXenoborgContraband ]
id: CartridgeNanite
name: nanite crystal
description: A high-power nanite crystal used by xenoborgs.
components:
- type: CartridgeAmmo
muzzleFlash: MuzzleFlashEffectNanite
proto: BulletNanite
- type: Sprite
sprite: Objects/Weapons/Guns/Ammunition/Casings/nanite_casing.rsi
layers:
- map: ["NaniteCasing"]
state: base
- type: RandomSprite
available:
- NaniteCasing:
base: ""
base1: ""
base2: ""
- type: StaticPrice
price: 20

View file

@ -0,0 +1,69 @@
- type: entity
id: MuzzleFlashEffectNanite
categories: [ HideSpawnMenu ]
components:
- type: TimedDespawn
lifetime: 0.4
- type: Sprite
drawdepth: BelowMobs
offset: -.25, 0
layers:
- shader: unshaded
map: ["enum.EffectLayers.Unshaded"]
sprite: Objects/Weapons/Guns/Projectiles/nanite_crystal.rsi
state: muzzle_nanite
- type: EffectVisuals
- type: Tag
tags:
- HideContextMenu
- type: AnimationPlayer
- type: entity
id: BulletImpactEffectNanite
categories: [ HideSpawnMenu ]
components:
- type: TimedDespawn
lifetime: 0.25
- type: Sprite
drawdepth: Effects
layers:
- shader: unshaded
map: ["enum.EffectLayers.Unshaded"]
sprite: Objects/Weapons/Guns/Projectiles/nanite_crystal.rsi
state: impact_nanite
- type: EffectVisuals
- type: Tag
tags:
- HideContextMenu
- type: entity
parent: BaseBullet
id: BulletNanite
categories: [ HideSpawnMenu ]
name: nanite crystal
components:
- type: Sprite
sprite: Objects/Weapons/Guns/Projectiles/nanite_crystal.rsi
layers:
- state: nanite
shader: unshaded
- type: Projectile
impactEffect: BulletImpactEffectNanite
damage:
types:
Piercing: 9
Poison: 3
soundHit:
collection: NaniteBulletImpact
- type: ComplexProjectileDamage
damageOptions:
- damage:
types:
Blunt: -10
Piercing: -10
Slash: -10
Heat: -10
Shock: -10
whitelist:
components:
- BorgChassis

View file

@ -0,0 +1,47 @@
- type: entity
parent: [BaseItem, BaseXenoborgContraband]
id: WeaponNaniteGun
name: nanite gun
description: A strange gun that shoots nanites encased in crystal shards that heals borgs but hurts fleshy inferior beings.
components:
- type: Sprite
sprite: Objects/Weapons/Guns/Rifles/nanite.rsi
layers:
- state: base
map: ["enum.GunVisualLayers.Base"]
- state: mag-unshaded-5
map: ["enum.GunVisualLayers.Mag"]
- type: AmmoCounter
- type: Gun
fireRate: 0.9
selectedMode: SemiAuto
availableModes:
- SemiAuto
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/nanite_gun.ogg
soundEmpty:
path: /Audio/Weapons/Guns/Empty/empty.ogg
- type: BallisticAmmoProvider
capacity: 5
proto: CartridgeNanite
soundInsert:
path: /Audio/Weapons/Guns/MagIn/shotgun_insert.ogg
cycleable: false # No synthesizing ammo
- type: BallisticAmmoSelfRefiller
autoRefillRate: 9s
affectedByEmp: true
- type: StaticPrice
price: 5000
- type: MagazineVisuals
magState: mag-unshaded
steps: 6
zeroVisible: true
- type: CustomSpriteAmmoCounter
loadedAmmoSprite: Interface/ItemStatus/Crystals/not_spent.png
spentAmmoSprite: Interface/ItemStatus/Crystals/spent.png
numberOfRows: 1
- type: Appearance
- type: ContainerContainer
containers:
ballistic-ammo: !type:Container
ents: [ ]

View file

@ -27,3 +27,9 @@
- "/Audio/Weapons/Guns/Hits/energy_metal1.ogg"
- "/Audio/Weapons/Guns/Hits/energy_metal2.ogg"
- type: soundCollection
id: NaniteBulletImpact
files:
- "/Audio/Weapons/Guns/Hits/nanite_hit1.ogg"
- "/Audio/Weapons/Guns/Hits/nanite_hit2.ogg"
- "/Audio/Weapons/Guns/Hits/nanite_hit3.ogg"

View file

@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from vgstation at commit https://github.com/vgstation-coders/vgstation13/commit/cdbcb1e858b11f083994a7a269ed67ef5b452ce9, inflatable module by FungiFellow (GitHub), Module actions by Scarky0. chem, adv-chem, and adv-mining by mubururu_, xenoborg actions by Samuka-C (github), advclown by ThatGuyUSA. c20r and esword by RedBookcase on Github, artistry-module by Kittygyat, with help from TiniestShark, xenoborg-laser3-module by august-sun(GitHub)",
"copyright": "Taken from vgstation at commit https://github.com/vgstation-coders/vgstation13/commit/cdbcb1e858b11f083994a7a269ed67ef5b452ce9, inflatable module by FungiFellow (GitHub), Module actions by Scarky0. chem, adv-chem, and adv-mining by mubururu_, xenoborg actions by Samuka-C (github), advclown by ThatGuyUSA. c20r and esword by RedBookcase on Github, artistry-module by Kittygyat, with help from TiniestShark, xenoborg-laser3-module by august-sun(GitHub), Xenoborg Nanite action by YoungThugSS14 (Gihutb)",
"size": {
"x": 32,
"y": 32
@ -176,7 +176,10 @@
"name":"xenoborg-oil-gun-module"
},
{
"name":"xenoborg-projector-module"
"name": "xenoborg-nanite-module"
},
{
"name": "xenoborg-projector-module"
},
{
"name":"xenoborg-space-movement-module"

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

View file

@ -22,3 +22,8 @@
license: "CC-BY-SA-3.0"
copyright: "Created by Samuka-C"
source: "https://github.com/space-wizards/space-station-14/pull/44389"
- files: ["Crystals/*.png"]
license: "CC-BY-SA-3.0"
copyright: "Created by YoungThugSS14"
source: "https://github.com/space-wizards/space-station-14/pull/43120"

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

View file

@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC0-1.0",
"copyright": "Created by EmoGarbage404 (github) for Space Station 14. icon-construction.png created by deltanedas (github). syndicateborgbomb.png created by Mangohydra (github). icon-chem.png & icon-mining-adv.png created by mubururu_ (github) icon-inflatable.png made by FungiFellow (GitHub), Xenoborg modules sprites by Samuka-C (github), icon-xenoborg-laser3 by august-sun(github), icon-artistry by Kittygyat",
"copyright": "Created by EmoGarbage404 (github) for Space Station 14. icon-construction.png created by deltanedas (github). syndicateborgbomb.png created by Mangohydra (github). icon-chem.png & icon-mining-adv.png created by mubururu_ (github) icon-inflatable.png made by FungiFellow (GitHub), Xenoborg modules sprites by Samuka-C (github), icon-xenoborg-laser3 by august-sun(github), Nanite gun module sprite made by YoungThugSS14 (Github), icon-artistry by Kittygyat",
"size": {
"x": 32,
"y": 32
@ -160,6 +160,9 @@
{
"name": "icon-xenoborg-sword"
},
{
"name": "icon-xenoborg-nanite-gun"
},
{
"name": "icon-xenoborg-sword2"
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

View file

@ -0,0 +1,20 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Sprites made by YoungThugSS14 (Github)",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "base"
},
{
"name": "base1"
},
{
"name": "base2"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

View file

@ -0,0 +1,44 @@
{
"version": 1,
"license": "CC-BY-NC-4.0",
"copyright": "Sprites by YoungThugSS14 (github)",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "nanite",
"delays": [
[
0.05,
0.05
]
]
},
{
"name": "muzzle_nanite",
"delays": [
[
0.05,
0.05,
0.05,
0.05,
0.05
]
]
},
{
"name": "impact_nanite",
"delays": [
[
0.05,
0.05,
0.05,
0.05,
0.05
]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

View file

@ -0,0 +1,35 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"copyright": "YoungThugSS14, SAMUKA-C(github)",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "base"
},
{
"name": "mag-unshaded-0"
},
{
"name": "mag-unshaded-1"
},
{
"name": "mag-unshaded-2"
},
{
"name": "mag-unshaded-3"
},
{
"name": "mag-unshaded-4"
},
{
"name": "mag-unshaded-5"
}
]
}