Magic staves + wands (#9070)

This commit is contained in:
Kara
2022-07-14 19:45:27 -07:00
committed by GitHub
parent 9608005db0
commit ad7889e8a9
85 changed files with 1299 additions and 34 deletions

View File

@@ -0,0 +1,20 @@
using Content.Shared.Weapons.Ranged.Components;
namespace Content.Client.Weapons.Ranged.Systems;
public partial class GunSystem
{
protected override void InitializeBasicEntity()
{
base.InitializeBasicEntity();
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, UpdateAmmoCounterEvent>(OnBasicEntityAmmoCount);
}
private void OnBasicEntityAmmoCount(EntityUid uid, BasicEntityAmmoProviderComponent component, UpdateAmmoCounterEvent args)
{
if (args.Control is DefaultStatusControl control && component.Count != null && component.Capacity != null)
{
control.Update(component.Count.Value, component.Capacity.Value);
}
}
}

View File

@@ -0,0 +1,21 @@
using Content.Shared.Polymorph;
using Content.Shared.Sound;
using Content.Shared.Whitelist;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Polymorph.Components;
[RegisterComponent]
public sealed class PolymorphOnCollideComponent : Component
{
[DataField("polymorph", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<PolymorphPrototype>))]
public string Polymorph = default!;
[DataField("whitelist", required: true)]
public EntityWhitelist Whitelist = default!;
[DataField("blacklist")]
public EntityWhitelist? Blacklist;
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Magic/forcewall.ogg");
}

View File

@@ -0,0 +1,65 @@
using Content.Server.Polymorph.Components;
using Content.Shared.Projectiles;
using Content.Shared.Sound;
using Robust.Shared.Audio;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Player;
namespace Content.Server.Polymorph.Systems;
public partial class PolymorphableSystem
{
// Need to do this so we don't get a collection enumeration error in physics by polymorphing
// an entity we're colliding with
private Queue<PolymorphQueuedData> _queuedPolymorphUpdates = new();
public override void Update(float frameTime)
{
base.Update(frameTime);
while (_queuedPolymorphUpdates.TryDequeue(out var data))
{
if (Deleted(data.Ent))
continue;
var ent = PolymorphEntity(data.Ent, data.Polymorph);
if (ent != null)
{
SoundSystem.Play(data.Sound.GetSound(), Filter.Pvs(ent.Value, entityManager: EntityManager),
ent.Value, data.Sound.Params);
}
}
}
private void InitializeCollide()
{
SubscribeLocalEvent<PolymorphOnCollideComponent, StartCollideEvent>(OnPolymorphCollide);
}
private void OnPolymorphCollide(EntityUid uid, PolymorphOnCollideComponent component, StartCollideEvent args)
{
if (args.OurFixture.ID != SharedProjectileSystem.ProjectileFixture)
return;
var other = args.OtherFixture.Body.Owner;
if (!component.Whitelist.IsValid(other)
|| component.Blacklist != null && component.Blacklist.IsValid(other))
return;
_queuedPolymorphUpdates.Enqueue(new (other, component.Sound, component.Polymorph));
}
}
struct PolymorphQueuedData
{
public EntityUid Ent;
public SoundSpecifier Sound;
public string Polymorph;
public PolymorphQueuedData(EntityUid ent, SoundSpecifier sound, string polymorph)
{
Ent = ent;
Sound = sound;
Polymorph = polymorph;
}
}

View File

@@ -1,4 +1,5 @@
using Content.Server.Actions; using Content.Server.Actions;
using Content.Server.Body.Components;
using Content.Server.Buckle.Components; using Content.Server.Buckle.Components;
using Content.Server.Inventory; using Content.Server.Inventory;
using Content.Server.Mind.Commands; using Content.Server.Mind.Commands;
@@ -12,8 +13,11 @@ using Content.Shared.Damage;
using Content.Shared.Hands.EntitySystems; using Content.Shared.Hands.EntitySystems;
using Content.Shared.Polymorph; using Content.Shared.Polymorph;
using Robust.Server.Containers; using Robust.Server.Containers;
using Robust.Shared.Audio;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -39,6 +43,7 @@ namespace Content.Server.Polymorph.Systems
SubscribeLocalEvent<PolymorphableComponent, ComponentStartup>(OnStartup); SubscribeLocalEvent<PolymorphableComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<PolymorphableComponent, PolymorphActionEvent>(OnPolymorphActionEvent); SubscribeLocalEvent<PolymorphableComponent, PolymorphActionEvent>(OnPolymorphActionEvent);
InitializeCollide();
InitializeMap(); InitializeMap();
} }

View File

@@ -15,6 +15,9 @@ namespace Content.Server.Projectiles.Components
[DataField("deleteOnCollide")] [DataField("deleteOnCollide")]
public bool DeleteOnCollide { get; } = true; public bool DeleteOnCollide { get; } = true;
[DataField("ignoreResistances")]
public bool IgnoreResistances { get; } = false;
// Get that juicy FPS hit sound // Get that juicy FPS hit sound
[DataField("soundHit")] public SoundSpecifier? SoundHit; [DataField("soundHit")] public SoundSpecifier? SoundHit;

View File

@@ -40,7 +40,7 @@ namespace Content.Server.Projectiles
var otherEntity = args.OtherFixture.Body.Owner; var otherEntity = args.OtherFixture.Body.Owner;
var modifiedDamage = _damageableSystem.TryChangeDamage(otherEntity, component.Damage); var modifiedDamage = _damageableSystem.TryChangeDamage(otherEntity, component.Damage, component.IgnoreResistances);
component.DamagedEntity = true; component.DamagedEntity = true;
if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter)) if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter))

View File

@@ -0,0 +1,33 @@
using Content.Shared.Sound;
using Robust.Shared.Audio;
namespace Content.Server.Weapon.Ranged.Components;
/// <summary>
/// Responsible for handling recharging a basic entity ammo provider over time.
/// </summary>
[RegisterComponent]
public sealed class RechargeBasicEntityAmmoComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
[DataField("minRechargeCooldown")]
public float MinRechargeCooldown = 30f;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxRechargeCooldown")]
public float MaxRechargeCooldown = 45f;
[DataField("rechargeSound")]
public SoundSpecifier RechargeSound = new SoundPathSpecifier("/Audio/Magic/forcewall.ogg")
{
Params = AudioParams.Default.WithVolume(-5f)
};
[DataField("accumulatedFrametime")]
public float AccumulatedFrameTime;
/// <summary>
/// Number of seconds until the next recharge.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float NextRechargeTime = 0f;
}

View File

@@ -0,0 +1,75 @@
using Content.Server.Weapon.Ranged.Components;
using Content.Shared.Examine;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server.Weapon.Ranged.Systems;
public sealed class RechargeBasicEntityAmmoSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedGunSystem _gun = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RechargeBasicEntityAmmoComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<RechargeBasicEntityAmmoComponent, ExaminedEvent>(OnExamined);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
foreach (var (recharge, ammo) in
EntityQuery<RechargeBasicEntityAmmoComponent, BasicEntityAmmoProviderComponent>())
{
if (ammo.Count is null || ammo.Count == ammo.Capacity)
continue;
recharge.AccumulatedFrameTime += frameTime;
if (recharge.AccumulatedFrameTime < recharge.NextRechargeTime)
return;
recharge.AccumulatedFrameTime -= recharge.NextRechargeTime;
UpdateCooldown(recharge);
if (_gun.UpdateBasicEntityAmmoCount(ammo.Owner, ammo.Count.Value + 1, ammo))
{
SoundSystem.Play(recharge.RechargeSound.GetSound(), Filter.Pvs(recharge.Owner), recharge.Owner,
recharge.RechargeSound.Params);
}
}
}
private void OnInit(EntityUid uid, RechargeBasicEntityAmmoComponent component, ComponentInit args)
{
UpdateCooldown(component);
}
private void OnExamined(EntityUid uid, RechargeBasicEntityAmmoComponent component, ExaminedEvent args)
{
if (!TryComp<BasicEntityAmmoProviderComponent>(uid, out var ammo)
|| ammo.Count == ammo.Capacity)
{
args.PushMarkup(Loc.GetString("recharge-basic-entity-ammo-full"));
return;
}
var timeLeft = component.NextRechargeTime - component.AccumulatedFrameTime;
args.PushMarkup(Loc.GetString("recharge-basic-entity-ammo-can-recharge", ("seconds", Math.Round(timeLeft, 1))));
}
private void UpdateCooldown(RechargeBasicEntityAmmoComponent component)
{
component.NextRechargeTime = _random.NextFloat(component.MinRechargeCooldown, component.MaxRechargeCooldown);
}
}

View File

@@ -0,0 +1,44 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Weapons.Ranged.Components;
/// <summary>
/// Simply provides a certain capacity of entities that cannot be reloaded through normal means and have
/// no special behavior like cycling, magazine
/// </summary>
[RegisterComponent]
public sealed class BasicEntityAmmoProviderComponent : AmmoProviderComponent
{
[ViewVariables(VVAccess.ReadWrite)]
[DataField("proto", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Proto = default!;
/// <summary>
/// Max capacity.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("capacity")]
public int? Capacity = null;
/// <summary>
/// Actual ammo left. Initialized to capacity unless they are non-null and differ.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("count")]
public int? Count = null;
}
[Serializable, NetSerializable]
public sealed class BasicEntityAmmoProviderComponentState : ComponentState
{
public int? Capacity;
public int? Count;
public BasicEntityAmmoProviderComponentState(int? capacity, int? count)
{
Capacity = capacity;
Count = count;
}
}

View File

@@ -0,0 +1,96 @@
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.GameStates;
namespace Content.Shared.Weapons.Ranged.Systems;
public abstract partial class SharedGunSystem
{
protected virtual void InitializeBasicEntity()
{
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, ComponentInit>(OnBasicEntityInit);
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, TakeAmmoEvent>(OnBasicEntityTakeAmmo);
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, GetAmmoCountEvent>(OnBasicEntityAmmoCount);
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, ComponentGetState>(OnBasicEntityGetState);
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, ComponentHandleState>(OnBasicEntityHandleState);
}
private void OnBasicEntityGetState(EntityUid uid, BasicEntityAmmoProviderComponent component, ref ComponentGetState args)
{
args.State = new BasicEntityAmmoProviderComponentState(component.Capacity, component.Count);
}
private void OnBasicEntityHandleState(EntityUid uid, BasicEntityAmmoProviderComponent component, ref ComponentHandleState args)
{
if (args.Current is BasicEntityAmmoProviderComponentState state)
{
component.Capacity = state.Capacity;
component.Count = state.Count;
}
}
private void OnBasicEntityInit(EntityUid uid, BasicEntityAmmoProviderComponent component, ComponentInit args)
{
if (component.Count is null)
{
component.Count = component.Capacity;
Dirty(component);
}
UpdateBasicEntityAppearance(component);
}
private void OnBasicEntityTakeAmmo(EntityUid uid, BasicEntityAmmoProviderComponent component, TakeAmmoEvent args)
{
for (int i = 0; i < args.Shots; i++)
{
if (component.Count <= 0)
return;
if (component.Count != null)
{
component.Count--;
}
var ent = Spawn(component.Proto, args.Coordinates);
args.Ammo.Add(EnsureComp<AmmoComponent>(ent));
}
UpdateBasicEntityAppearance(component);
Dirty(component);
}
private void OnBasicEntityAmmoCount(EntityUid uid, BasicEntityAmmoProviderComponent component, ref GetAmmoCountEvent args)
{
args.Capacity = component.Capacity ?? int.MaxValue;
args.Count = component.Count ?? int.MaxValue;
}
private void UpdateBasicEntityAppearance(BasicEntityAmmoProviderComponent component)
{
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(component.Owner, out var appearance)) return;
appearance.SetData(AmmoVisuals.HasAmmo, component.Count != 0);
appearance.SetData(AmmoVisuals.AmmoCount, component.Count ?? int.MaxValue);
appearance.SetData(AmmoVisuals.AmmoMax, component.Capacity ?? int.MaxValue);
}
#region Public API
public bool UpdateBasicEntityAmmoCount(EntityUid uid, int count, BasicEntityAmmoProviderComponent? component = null)
{
if (!Resolve(uid, ref component))
return false;
if (count > component.Capacity)
return false;
component.Count = count;
Dirty(component);
UpdateBasicEntityAppearance(component);
return true;
}
#endregion
}

View File

@@ -83,6 +83,7 @@ public abstract partial class SharedGunSystem
protected void UpdateBatteryAppearance(EntityUid uid, BatteryAmmoProviderComponent component) protected void UpdateBatteryAppearance(EntityUid uid, BatteryAmmoProviderComponent component)
{ {
if (!TryComp<AppearanceComponent>(uid, out var appearance)) return; if (!TryComp<AppearanceComponent>(uid, out var appearance)) return;
appearance.SetData(AmmoVisuals.HasAmmo, component.Shots != 0);
appearance.SetData(AmmoVisuals.AmmoCount, component.Shots); appearance.SetData(AmmoVisuals.AmmoCount, component.Shots);
appearance.SetData(AmmoVisuals.AmmoMax, component.Capacity); appearance.SetData(AmmoVisuals.AmmoMax, component.Capacity);
} }

View File

@@ -142,6 +142,7 @@ public abstract partial class SharedGunSystem
{ {
// Copy the magazine's appearance data // Copy the magazine's appearance data
appearance?.SetData(AmmoVisuals.MagLoaded, magLoaded); appearance?.SetData(AmmoVisuals.MagLoaded, magLoaded);
appearance?.SetData(AmmoVisuals.HasAmmo, count != 0);
appearance?.SetData(AmmoVisuals.AmmoCount, count); appearance?.SetData(AmmoVisuals.AmmoCount, count);
appearance?.SetData(AmmoVisuals.AmmoMax, capacity); appearance?.SetData(AmmoVisuals.AmmoMax, capacity);
} }

View File

@@ -220,7 +220,9 @@ public partial class SharedGunSystem
private void UpdateRevolverAppearance(RevolverAmmoProviderComponent component) private void UpdateRevolverAppearance(RevolverAmmoProviderComponent component)
{ {
if (!TryComp<AppearanceComponent>(component.Owner, out var appearance)) return; if (!TryComp<AppearanceComponent>(component.Owner, out var appearance)) return;
appearance.SetData(AmmoVisuals.AmmoCount, GetRevolverCount(component)); var count = GetRevolverCount(component);
appearance.SetData(AmmoVisuals.HasAmmo, count != 0);
appearance.SetData(AmmoVisuals.AmmoCount, count);
appearance.SetData(AmmoVisuals.AmmoMax, component.Capacity); appearance.SetData(AmmoVisuals.AmmoMax, component.Capacity);
} }

View File

@@ -73,6 +73,7 @@ public abstract partial class SharedGunSystem : EntitySystem
InitializeChamberMagazine(); InitializeChamberMagazine();
InitializeMagazine(); InitializeMagazine();
InitializeRevolver(); InitializeRevolver();
InitializeBasicEntity();
// Interactions // Interactions
SubscribeLocalEvent<GunComponent, GetVerbsEvent<AlternativeVerb>>(OnAltVerb); SubscribeLocalEvent<GunComponent, GetVerbsEvent<AlternativeVerb>>(OnAltVerb);
@@ -389,5 +390,6 @@ public enum AmmoVisuals : byte
Spent, Spent,
AmmoCount, AmmoCount,
AmmoMax, AmmoMax,
HasAmmo, // used for generic visualizers. c# stuff can just check ammocount != 0
MagLoaded, MagLoaded,
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,6 @@
# BEHOLD:
# FIRST EVER USAGE OF ROBUST GENERIC ATTRIBUTION STANDARD IN SPACE STATION 14
- files: [ "staff_animation.ogg", "staff_change.ogg", "staff_chaos.ogg", "staff_door.ogg", "staff_healing.ogg" ]
license: "CC-BY-SA-3.0"
copyright: "https://github.com/tgstation/tgstation/commit/906fb0682bab6a0975b45036001c54f021f58ae7"

View File

@@ -0,0 +1,2 @@
recharge-basic-entity-ammo-can-recharge = It will recharge its ammo in [color=yellow]{$seconds}[/color] seconds.
recharge-basic-entity-ammo-full = It doesn't need to recharge its ammo yet.

View File

@@ -100,3 +100,14 @@
amount: 1 amount: 1
- id: MedkitCombatFilled - id: MedkitCombatFilled
- type: entity
parent: ClothingBeltWand
id: ClothingBeltWandFilled
suffix: Filled
components:
- type: StorageFill
contents:
- id: WeaponWandPolymorphCarp
- id: WeaponWandFireball
- id: WeaponWandDeath
- id: WeaponWandPolymorphDoor

View File

@@ -503,3 +503,19 @@
- type: Clothing - type: Clothing
sprite: Clothing/Belt/suspenders.rsi sprite: Clothing/Belt/suspenders.rsi
quickEquip: true quickEquip: true
- type: entity
parent: ClothingBeltStorageBase
id: ClothingBeltWand
name: wand belt
description: A belt designed to hold various rods of power. A veritable fanny pack of exotic magic.
components:
- type: Sprite
sprite: Clothing/Belt/wand.rsi
- type: Clothing
sprite: Clothing/Belt/wand.rsi
- type: Storage
capacity: 120
whitelist:
tags:
- WizardWand

View File

@@ -69,6 +69,9 @@
- type: TypingIndicator - type: TypingIndicator
proto: alien proto: alien
- type: NoSlip - type: NoSlip
- type: Tag
tags:
- Carp
- type: entity - type: entity
name: magicarp name: magicarp

View File

@@ -0,0 +1,23 @@
- type: entity
id: WeaponStaffBase
abstract: true
parent: BaseItem
components:
- type: Sprite
sprite: Objects/Weapons/Guns/Magic/staves.rsi
- type: Item
sprite: Objects/Weapons/Guns/Magic/staves.rsi
HeldPrefix: staff
size: 60
- type: Gun
fireRate: 1
selectedMode: SemiAuto
availableModes:
- SemiAuto
- type: AmmoCounter
# All staves recharge. Wands are not.
- type: RechargeBasicEntityAmmo
- type: Tag
tags:
- WizardStaff

View File

@@ -0,0 +1,28 @@
- type: entity
id: WeaponWandBase
abstract: true
parent: BaseItem
components:
- type: Sprite
sprite: Objects/Weapons/Guns/Magic/wands.rsi
- type: Item
sprite: Objects/Weapons/Guns/Magic/wands.rsi
HeldPrefix: wand
size: 30
- type: Gun
fireRate: 0.5
selectedMode: SemiAuto
availableModes:
- SemiAuto
- type: AmmoCounter
# These will only do anything if the effect layer is actually set.
- type: Appearance
- type: GenericVisualizer
visuals:
enum.AmmoVisuals.HasAmmo:
effect:
True: { visible: True }
False: { visible: False }
- type: Tag
tags:
- WizardWand

View File

@@ -0,0 +1,37 @@
# To be implemented: see #9072
- type: entity
name: staff of healing
parent: WeaponStaffBase
id: WeaponStaffHealing
description: You don't foresee having to use this in your quest for carnage too often.
components:
- type: Sprite
layers:
- state: healing
- type: Item
HeldPrefix: healing
- type: Gun
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/Magic/staff_healing.ogg
- type: BasicEntityAmmoProvider
proto: ProjectileHealingBolt
capacity: 10
- type: entity
name: staff of entrance
parent: WeaponStaffBase
id: WeaponStaffPolymorphDoor
description: For when you need a get-away route.
components:
- type: Sprite
layers:
- state: door
- type: Item
HeldPrefix: door
- type: Gun
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/Magic/staff_door.ogg
- type: BasicEntityAmmoProvider
proto: ProjectilePolyboltDoor
capacity: 10

View File

@@ -0,0 +1,72 @@
- type: entity
name: wand of carp polymorph
parent: WeaponWandBase
id: WeaponWandPolymorphCarp
description: For when you need a carp filet quick and the clown is looking juicy.
components:
- type: Sprite
layers:
- state: poly
- state: poly-effect
map: ["effect"]
- type: Gun
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/Magic/staff_animation.ogg
- type: BasicEntityAmmoProvider
proto: ProjectilePolyboltCarp
capacity: 5
- type: entity
name: wand of fireball
parent: WeaponWandBase
id: WeaponWandFireball
description: Great big balls of fire!
components:
- type: Sprite
layers:
- state: fire
- state: fire-effect
map: ["effect"]
- type: Gun
fireRate: 0.25
soundGunshot:
path: /Audio/Magic/fireball.ogg
- type: BasicEntityAmmoProvider
proto: ProjectileFireball
capacity: 5
- type: entity
name: magical wand of instant death
parent: WeaponWandBase
id: WeaponWandDeath
description: Only the best and brightest of the Space Wizards R&D team worked together to create this beauty.
components:
- type: Sprite
layers:
- state: death
- state: death-effect
map: ["effect"]
- type: Gun
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/mateba.ogg # PUNCH
- type: BasicEntityAmmoProvider
proto: BulletInstakillMagic
capacity: 3
- type: entity
name: wand of entrance
parent: WeaponWandBase
id: WeaponWandPolymorphDoor
description: For when you need a get-away route.
components:
- type: Sprite
layers:
- state: door
- state: door-effect
map: ["effect"]
- type: Gun
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/Magic/staff_door.ogg
- type: BasicEntityAmmoProvider
proto: ProjectilePolyboltDoor
capacity: 10

View File

@@ -15,3 +15,87 @@
intensitySlope: 6 intensitySlope: 6
totalIntensity: 200 totalIntensity: 200
maxTileBreak: 0 maxTileBreak: 0
- type: entity
id: ProjectilePolyboltCarp
name: carp polybolt
description: Nooo, I don't wanna be fish!
parent: BaseBullet
noSpawn: true
components:
- type: Sprite
sprite: Objects/Weapons/Guns/Projectiles/magic.rsi
layers:
- state: spell
color: '#00FF00'
- type: PolymorphOnCollide
polymorph: WizardForcedCarp
whitelist:
components:
- Body
blacklist:
tags:
- Carp # can't re-polymorph
- type: Projectile
damage:
types:
Poison: 5
- type: entity
id: ProjectilePolyboltDoor
name: door polybolt
description: Nooo, I don't wanna be door!
parent: BaseBullet
noSpawn: true
components:
- type: Sprite
sprite: Objects/Weapons/Guns/Projectiles/magic.rsi
layers:
- state: spell
color: brown
- type: PolymorphOnCollide
polymorph: WizardWallDoor
whitelist:
components:
- Airlock
- Firelock
tags:
- Wall
- type: Projectile
damage:
types:
Poison: 5
- type: entity
id: ProjectileHealingBolt
name: healing bolt
description: I COMMAND YOU TO LIVE!
parent: BaseBullet
noSpawn: true
components:
- type: Sprite
sprite: Objects/Weapons/Guns/Projectiles/magic.rsi
layers:
- state: spell
color: white
- type: Projectile
damage:
groups: # good enough. Maybe make it call the rejuvenate command later.
Brute: -900
Burn: -900
Airloss: -600
Toxin: -600
ignoreResistances: true
- type: entity
id: BulletInstakillMagic
name: magical lead cylinder
parent: BaseBulletHighVelocity
noSpawn: true
description: This looks familiar.
components:
- type: Projectile
damage:
types:
Piercing: 300
ignoreResistances: true

View File

@@ -18,6 +18,26 @@
revertOnCrit: true revertOnCrit: true
revertOnDeath: true revertOnDeath: true
- type: polymorph
id: WizardForcedCarp
entity: MobCarpMagic
forced: true
inventory: None
transferName: true
transferDamage: true
revertOnCrit: false
revertOnDeath: true
- type: polymorph
id: WizardWallDoor
entity: WoodDoor
forced: true
inventory: None
transferName: false
transferDamage: false
revertOnCrit: false
revertOnDeath: false
# this is a test for transferring some visual appearance stuff # this is a test for transferring some visual appearance stuff
- type: polymorph - type: polymorph
id: TestHumanMorph id: TestHumanMorph

View File

@@ -51,6 +51,9 @@
- type: Tag - type: Tag
id: CaptainSabre id: CaptainSabre
- type: Tag
id: Carp
- type: Tag - type: Tag
id: Cartridge id: Cartridge
@@ -426,6 +429,12 @@
- type: Tag - type: Tag
id: Window id: Window
- type: Tag
id: WizardWand # that evil vvizard vvand
- type: Tag
id: WizardStaff
- type: Tag - type: Tag
id: Wirecutter id: Wirecutter

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

View File

@@ -0,0 +1,26 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "tgstation at https://github.com/tgstation/tgstation/commit/270acce4f551253d8ac75de19236b8b4be598f7f",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "equipped-BELT",
"directions": 4
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,522 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "/tg/station at https://github.com/tgstation/tgstation/commit/270acce4f551253d8ac75de19236b8b4be598f7f. edited by mirrorcult to allow layering",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "animation",
"delays": [
[
0.5,
0.5,
0.5,
0.5
]
]
},
{
"name": "healing",
"delays": [
[
0.1,
0.1,
0.2,
0.1,
0.1,
0.1,
0.2,
0.1,
0.1,
0.1,
0.2,
0.1,
0.1,
0.1,
0.2,
0.1
]
]
},
{
"name": "door",
"delays": [
[
2,
2,
2,
2
]
]
},
{
"name": "staff-inhand-left",
"directions": 4,
"delays": [
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
]
]
},
{
"name": "animation-inhand-left",
"directions": 4,
"delays": [
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
]
]
},
{
"name": "healing-inhand-left",
"directions": 4,
"delays": [
[
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1
],
[
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1
],
[
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1
],
[
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1
]
]
},
{
"name": "door-inhand-left",
"directions": 4,
"delays": [
[
2,
2,
2,
2
],
[
2,
2,
2,
2
],
[
2,
2,
2,
2
],
[
2,
2,
2,
2
]
]
},
{
"name": "staff-inhand-right",
"directions": 4,
"delays": [
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
]
]
},
{
"name": "animation-inhand-right",
"directions": 4,
"delays": [
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
]
]
},
{
"name": "healing-inhand-right",
"directions": 4,
"delays": [
[
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1
],
[
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1
],
[
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1
],
[
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1,
0.2,
0.2,
0.1
]
]
},
{
"name": "door-inhand-right",
"directions": 4,
"delays": [
[
2,
2,
2,
2
],
[
2,
2,
2,
2
],
[
2,
2,
2,
2
],
[
2,
2,
2,
2
]
]
},
{
"name": "change",
"delays": [
[
0.4,
0.4,
0.4,
0.4,
0.4
]
]
},
{
"name": "nothing",
"delays": [
[
0.5,
0.5,
0.5,
0.5
]
]
},
{
"name": "chaos",
"delays": [
[
0.5,
0.5,
0.5,
0.5
]
]
},
{
"name": "change-inhand-left",
"directions": 4,
"delays": [
[
0.4,
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4,
0.4
]
]
},
{
"name": "chaos-inhand-left",
"directions": 4,
"delays": [
[
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4
]
]
},
{
"name": "change-inhand-right",
"directions": 4,
"delays": [
[
0.4,
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4,
0.4
],
[
0.4,
0.4,
0.4,
0.4,
0.4
]
]
},
{
"name": "chaos-inhand-right",
"directions": 4,
"delays": [
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
],
[
0.5,
0.5,
0.5,
0.5
]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -0,0 +1,68 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "/tg/station at https://github.com/tgstation/tgstation/commit/270acce4f551253d8ac75de19236b8b4be598f7f. edited by mirrorcult to allow layering",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "death-effect",
"delays": [
[
0.3,
0.3
]
]
},
{
"name": "poly-effect",
"delays": [
[
0.5,
0.5,
0.5,
0.5
]
]
},
{
"name": "fire-effect",
"delays": [
[
0.2,
0.2,
0.2,
0.2
]
]
},
{
"name": "death"
},
{
"name": "poly"
},
{
"name": "fire"
},
{
"name": "door-effect"
},
{
"name": "door"
},
{
"name": "nothing"
},
{
"name": "wand-inhand-left",
"directions": 4
},
{
"name": "wand-inhand-right",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 B

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 906 B

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 325 B

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 B

After

Width:  |  Height:  |  Size: 398 B

View File

@@ -7,16 +7,6 @@
"y": 32 "y": 32
}, },
"states": [ "states": [
{
"name": "energy",
"delays": [
[
0.1,
0.1,
0.1
]
]
},
{ {
"name": "magicm", "name": "magicm",
"delays": [ "delays": [
@@ -59,26 +49,6 @@
] ]
] ]
}, },
{
"name": "energy2",
"delays": [
[
0.1,
0.1,
0.1
]
]
},
{
"name": "energy3",
"delays": [
[
0.1,
0.1,
0.1
]
]
},
{ {
"name": "chronobolt" "name": "chronobolt"
}, },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 B

After

Width:  |  Height:  |  Size: 314 B