magic bread wand (#17044)
Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
@@ -293,9 +293,16 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(component.TrashPrototype))
|
var ev = new BeforeFullyEatenEvent
|
||||||
EntityManager.QueueDeleteEntity(uid);
|
{
|
||||||
|
User = args.User
|
||||||
|
};
|
||||||
|
RaiseLocalEvent(uid, ev);
|
||||||
|
if (ev.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(component.TrashPrototype))
|
||||||
|
QueueDel(uid);
|
||||||
else
|
else
|
||||||
DeleteAndSpawnTrash(component, uid, args.User);
|
DeleteAndSpawnTrash(component, uid, args.User);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Chemistry.Components.SolutionManager;
|
using Content.Server.Chemistry.Components.SolutionManager;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
|
using Content.Server.Nutrition;
|
||||||
using Content.Server.Nutrition.Components;
|
using Content.Server.Nutrition.Components;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
@@ -51,12 +52,12 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent(usedItem, out UtensilComponent ? utensil) || (utensil.Types & UtensilType.Knife) == 0)
|
if (!TryComp<UtensilComponent>(usedItem, out var utensil) || (utensil.Types & UtensilType.Knife) == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sliceUid = EntityManager.SpawnEntity(component.Slice, transform.Coordinates);
|
var sliceUid = Spawn(component.Slice, transform.Coordinates);
|
||||||
|
|
||||||
var lostSolution = _solutionContainerSystem.SplitSolution(uid, solution,
|
var lostSolution = _solutionContainerSystem.SplitSolution(uid, solution,
|
||||||
solution.Volume / FixedPoint2.New(component.Count));
|
solution.Volume / FixedPoint2.New(component.Count));
|
||||||
@@ -91,7 +92,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
// If someone makes food proto with 1 slice...
|
// If someone makes food proto with 1 slice...
|
||||||
if (component.Count < 1)
|
if (component.Count < 1)
|
||||||
{
|
{
|
||||||
EntityManager.DeleteEntity(uid);
|
DeleteFood(uid, user);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +100,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
if (component.Count > 1)
|
if (component.Count > 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
sliceUid = EntityManager.SpawnEntity(component.Slice, transform.Coordinates);
|
sliceUid = Spawn(component.Slice, transform.Coordinates);
|
||||||
|
|
||||||
// Fill last slice with the rest of the solution
|
// Fill last slice with the rest of the solution
|
||||||
FillSlice(sliceUid, solution);
|
FillSlice(sliceUid, solution);
|
||||||
@@ -115,14 +116,26 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
xform.LocalRotation = 0;
|
xform.LocalRotation = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityManager.DeleteEntity(uid);
|
DeleteFood(uid, user);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DeleteFood(EntityUid uid, EntityUid user)
|
||||||
|
{
|
||||||
|
var ev = new BeforeFullySlicedEvent
|
||||||
|
{
|
||||||
|
User = user
|
||||||
|
};
|
||||||
|
RaiseLocalEvent(uid, ev);
|
||||||
|
|
||||||
|
if (!ev.Cancelled)
|
||||||
|
Del(uid);
|
||||||
|
}
|
||||||
|
|
||||||
private void FillSlice(EntityUid sliceUid, Solution solution)
|
private void FillSlice(EntityUid sliceUid, Solution solution)
|
||||||
{
|
{
|
||||||
// Replace all reagents on prototype not just copying poisons (example: slices of eaten pizza should have less nutrition)
|
// Replace all reagents on prototype not just copying poisons (example: slices of eaten pizza should have less nutrition)
|
||||||
if (EntityManager.TryGetComponent<FoodComponent>(sliceUid, out var sliceFoodComp) &&
|
if (TryComp<FoodComponent>(sliceUid, out var sliceFoodComp) &&
|
||||||
_solutionContainerSystem.TryGetSolution(sliceUid, sliceFoodComp.SolutionName, out var itsSolution))
|
_solutionContainerSystem.TryGetSolution(sliceUid, sliceFoodComp.SolutionName, out var itsSolution))
|
||||||
{
|
{
|
||||||
_solutionContainerSystem.RemoveAllSolution(sliceUid, itsSolution);
|
_solutionContainerSystem.RemoveAllSolution(sliceUid, itsSolution);
|
||||||
@@ -135,9 +148,9 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
private void OnComponentStartup(EntityUid uid, SliceableFoodComponent component, ComponentStartup args)
|
private void OnComponentStartup(EntityUid uid, SliceableFoodComponent component, ComponentStartup args)
|
||||||
{
|
{
|
||||||
component.Count = component.TotalCount;
|
component.Count = component.TotalCount;
|
||||||
var foodComp = EntityManager.EnsureComponent<FoodComponent>(uid);
|
var foodComp = EnsureComp<FoodComponent>(uid);
|
||||||
|
|
||||||
EntityManager.EnsureComponent<SolutionContainerManagerComponent>(uid);
|
EnsureComp<SolutionContainerManagerComponent>(uid);
|
||||||
_solutionContainerSystem.EnsureSolution(uid, foodComp.SolutionName);
|
_solutionContainerSystem.EnsureSolution(uid, foodComp.SolutionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,3 +10,27 @@ public sealed class IngestionAttemptEvent : CancellableEntityEventArgs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public EntityUid? Blocker = null;
|
public EntityUid? Blocker = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised directed at the food after finishing eating a food before it's deleted.
|
||||||
|
/// Cancel this if you want to do something special before a food is deleted.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class BeforeFullyEatenEvent : CancellableEntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The person that ate the food.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid User;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised directed at the food being sliced before it's deleted.
|
||||||
|
/// Cancel this if you want to do something special before a food is deleted.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class BeforeFullySlicedEvent : CancellableEntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The person slicing the food.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid User;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.Humanoid;
|
|||||||
using Content.Server.Inventory;
|
using Content.Server.Inventory;
|
||||||
using Content.Server.Mind.Commands;
|
using Content.Server.Mind.Commands;
|
||||||
using Content.Server.Mind.Components;
|
using Content.Server.Mind.Components;
|
||||||
|
using Content.Server.Nutrition;
|
||||||
using Content.Server.Polymorph.Components;
|
using Content.Server.Polymorph.Components;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Actions.ActionTypes;
|
using Content.Shared.Actions.ActionTypes;
|
||||||
@@ -41,7 +42,7 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
[Dependency] private readonly TransformSystem _transform = default!;
|
[Dependency] private readonly TransformSystem _transform = default!;
|
||||||
|
|
||||||
private readonly ISawmill _saw = default!;
|
private ISawmill _sawmill = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -50,10 +51,14 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
SubscribeLocalEvent<PolymorphableComponent, ComponentStartup>(OnStartup);
|
SubscribeLocalEvent<PolymorphableComponent, ComponentStartup>(OnStartup);
|
||||||
SubscribeLocalEvent<PolymorphableComponent, PolymorphActionEvent>(OnPolymorphActionEvent);
|
SubscribeLocalEvent<PolymorphableComponent, PolymorphActionEvent>(OnPolymorphActionEvent);
|
||||||
SubscribeLocalEvent<PolymorphedEntityComponent, ComponentStartup>(OnStartup);
|
SubscribeLocalEvent<PolymorphedEntityComponent, ComponentStartup>(OnStartup);
|
||||||
|
SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullyEatenEvent>(OnBeforeFullyEaten);
|
||||||
|
SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullySlicedEvent>(OnBeforeFullySliced);
|
||||||
SubscribeLocalEvent<PolymorphedEntityComponent, RevertPolymorphActionEvent>(OnRevertPolymorphActionEvent);
|
SubscribeLocalEvent<PolymorphedEntityComponent, RevertPolymorphActionEvent>(OnRevertPolymorphActionEvent);
|
||||||
|
|
||||||
InitializeCollide();
|
InitializeCollide();
|
||||||
InitializeMap();
|
InitializeMap();
|
||||||
|
|
||||||
|
_sawmill = Logger.GetSawmill("polymorph");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStartup(EntityUid uid, PolymorphableComponent component, ComponentStartup args)
|
private void OnStartup(EntityUid uid, PolymorphableComponent component, ComponentStartup args)
|
||||||
@@ -82,7 +87,7 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
if (!_proto.TryIndex(component.Prototype, out PolymorphPrototype? proto))
|
if (!_proto.TryIndex(component.Prototype, out PolymorphPrototype? proto))
|
||||||
{
|
{
|
||||||
// warning instead of error because of the all-comps one entity test.
|
// warning instead of error because of the all-comps one entity test.
|
||||||
Logger.Warning($"{nameof(PolymorphSystem)} encountered an improperly set up polymorph component while initializing. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}");
|
_sawmill.Warning($"{nameof(PolymorphSystem)} encountered an improperly set up polymorph component while initializing. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}");
|
||||||
RemCompDeferred(uid, component);
|
RemCompDeferred(uid, component);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -102,6 +107,36 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
_actions.AddAction(uid, act, null);
|
_actions.AddAction(uid, act, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnBeforeFullyEaten(EntityUid uid, PolymorphedEntityComponent comp, BeforeFullyEatenEvent args)
|
||||||
|
{
|
||||||
|
if (!_proto.TryIndex<PolymorphPrototype>(comp.Prototype, out var proto))
|
||||||
|
{
|
||||||
|
_sawmill.Error("Invalid polymorph prototype {comp.Prototype}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proto.RevertOnEat)
|
||||||
|
{
|
||||||
|
args.Cancel();
|
||||||
|
Revert(uid, comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBeforeFullySliced(EntityUid uid, PolymorphedEntityComponent comp, BeforeFullySlicedEvent args)
|
||||||
|
{
|
||||||
|
if (!_proto.TryIndex<PolymorphPrototype>(comp.Prototype, out var proto))
|
||||||
|
{
|
||||||
|
_sawmill.Error("Invalid polymorph prototype {comp.Prototype}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proto.RevertOnEat)
|
||||||
|
{
|
||||||
|
args.Cancel();
|
||||||
|
Revert(uid, comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Polymorphs the target entity into the specific polymorph prototype
|
/// Polymorphs the target entity into the specific polymorph prototype
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -111,7 +146,7 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
{
|
{
|
||||||
if (!_proto.TryIndex<PolymorphPrototype>(id, out var proto))
|
if (!_proto.TryIndex<PolymorphPrototype>(id, out var proto))
|
||||||
{
|
{
|
||||||
_saw.Error("Invalid polymorph prototype");
|
_sawmill.Error("Invalid polymorph prototype {id}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +260,7 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
|
|
||||||
if (!_proto.TryIndex(component.Prototype, out PolymorphPrototype? proto))
|
if (!_proto.TryIndex(component.Prototype, out PolymorphPrototype? proto))
|
||||||
{
|
{
|
||||||
Logger.Error($"{nameof(PolymorphSystem)} encountered an improperly initialized polymorph component while reverting. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}");
|
_sawmill.Error($"{nameof(PolymorphSystem)} encountered an improperly initialized polymorph component while reverting. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,9 +271,6 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
parentXform.Coordinates = uidXform.Coordinates;
|
parentXform.Coordinates = uidXform.Coordinates;
|
||||||
parentXform.LocalRotation = uidXform.LocalRotation;
|
parentXform.LocalRotation = uidXform.LocalRotation;
|
||||||
|
|
||||||
if (_container.TryGetContainingContainer(uid, out var cont))
|
|
||||||
cont.Insert(component.Parent);
|
|
||||||
|
|
||||||
if (proto.TransferDamage &&
|
if (proto.TransferDamage &&
|
||||||
TryComp<DamageableComponent>(parent, out var damageParent) &&
|
TryComp<DamageableComponent>(parent, out var damageParent) &&
|
||||||
_mobThreshold.GetScaledDamage(uid, parent, out var damage) &&
|
_mobThreshold.GetScaledDamage(uid, parent, out var damage) &&
|
||||||
@@ -277,6 +309,9 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
mind.Mind.TransferTo(parent);
|
mind.Mind.TransferTo(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if an item polymorph was picked up, put it back down after reverting
|
||||||
|
Transform(parent).AttachToGridOrMap();
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("polymorph-revert-popup-generic",
|
_popup.PopupEntity(Loc.GetString("polymorph-revert-popup-generic",
|
||||||
("parent", Identity.Entity(uid, EntityManager)),
|
("parent", Identity.Entity(uid, EntityManager)),
|
||||||
("child", Identity.Entity(parent, EntityManager))),
|
("child", Identity.Entity(parent, EntityManager))),
|
||||||
@@ -293,7 +328,7 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
{
|
{
|
||||||
if (!_proto.TryIndex<PolymorphPrototype>(id, out var polyproto))
|
if (!_proto.TryIndex<PolymorphPrototype>(id, out var polyproto))
|
||||||
{
|
{
|
||||||
_saw.Error("Invalid polymorph prototype");
|
_sawmill.Error("Invalid polymorph prototype");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,27 +370,32 @@ namespace Content.Server.Polymorph.Systems
|
|||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|
||||||
foreach (var comp in EntityQuery<PolymorphedEntityComponent>())
|
var query = EntityQueryEnumerator<PolymorphedEntityComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var comp))
|
||||||
{
|
{
|
||||||
comp.Time += frameTime;
|
comp.Time += frameTime;
|
||||||
var ent = comp.Owner;
|
|
||||||
|
|
||||||
if (!_proto.TryIndex(comp.Prototype, out PolymorphPrototype? proto))
|
if (!_proto.TryIndex(comp.Prototype, out PolymorphPrototype? proto))
|
||||||
{
|
{
|
||||||
Logger.Error($"{nameof(PolymorphSystem)} encountered an improperly initialized polymorph component while updating. Entity {ToPrettyString(ent)}. Prototype: {comp.Prototype}");
|
_sawmill.Error($"{nameof(PolymorphSystem)} encountered an improperly initialized polymorph component while updating. Entity {ToPrettyString(uid)}. Prototype: {comp.Prototype}");
|
||||||
RemCompDeferred(ent, comp);
|
RemCompDeferred(uid, comp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proto.Duration != null && comp.Time >= proto.Duration)
|
if (proto.Duration != null && comp.Time >= proto.Duration)
|
||||||
Revert(ent, comp);
|
{
|
||||||
|
Revert(uid, comp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!TryComp<MobStateComponent>(ent, out var mob))
|
if (!TryComp<MobStateComponent>(uid, out var mob))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (proto.RevertOnDeath && _mobState.IsDead(ent, mob) ||
|
if (proto.RevertOnDeath && _mobState.IsDead(uid, mob) ||
|
||||||
proto.RevertOnCrit && _mobState.IsIncapacitated(ent, mob))
|
proto.RevertOnCrit && _mobState.IsIncapacitated(uid, mob))
|
||||||
Revert(ent, comp);
|
{
|
||||||
|
Revert(uid, comp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateCollide();
|
UpdateCollide();
|
||||||
|
|||||||
@@ -89,6 +89,12 @@ namespace Content.Shared.Polymorph
|
|||||||
[DataField("revertOnDeath", serverOnly: true)]
|
[DataField("revertOnDeath", serverOnly: true)]
|
||||||
public bool RevertOnDeath = true;
|
public bool RevertOnDeath = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the polymorph reverts when the entity is eaten or fully sliced.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("revertOnEat", serverOnly: true)]
|
||||||
|
public bool RevertOnEat = false;
|
||||||
|
|
||||||
[DataField("allowRepeatedMorphs", serverOnly: true)]
|
[DataField("allowRepeatedMorphs", serverOnly: true)]
|
||||||
public bool AllowRepeatedMorphs = false;
|
public bool AllowRepeatedMorphs = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,3 +105,14 @@
|
|||||||
proto: ProjectilePolyboltCluwne
|
proto: ProjectilePolyboltCluwne
|
||||||
capacity: 3
|
capacity: 3
|
||||||
count: 3
|
count: 3
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: WeaponWandPolymorphBase
|
||||||
|
id: WeaponWandPolymorphBread
|
||||||
|
name: magic bread wand
|
||||||
|
description: Turn all your friends into bread! Your boss! Your enemies! Your dog! Make everything bread!
|
||||||
|
components:
|
||||||
|
- type: BasicEntityAmmoProvider
|
||||||
|
proto: ProjectilePolyboltBread
|
||||||
|
capacity: 10
|
||||||
|
count: 10
|
||||||
|
|||||||
@@ -141,3 +141,15 @@
|
|||||||
Cold: 20
|
Cold: 20
|
||||||
Structural: 40
|
Structural: 40
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: ProjectilePolyboltBase
|
||||||
|
id: ProjectilePolyboltBread
|
||||||
|
name: bread polybolt
|
||||||
|
description: Nooo, I don't wanna be bread!
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: PolymorphOnCollide
|
||||||
|
polymorph: BreadMorph
|
||||||
|
whitelist:
|
||||||
|
components:
|
||||||
|
- Body
|
||||||
|
|||||||
@@ -83,3 +83,14 @@
|
|||||||
transferName: true
|
transferName: true
|
||||||
revertOnCrit: false
|
revertOnCrit: false
|
||||||
revertOnDeath: false
|
revertOnDeath: false
|
||||||
|
|
||||||
|
- type: polymorph
|
||||||
|
id: BreadMorph
|
||||||
|
entity: FoodBreadPlain
|
||||||
|
forced: true
|
||||||
|
inventory: None
|
||||||
|
transferName: false
|
||||||
|
transferDamage: true
|
||||||
|
revertOnCrit: false
|
||||||
|
revertOnDeath: true
|
||||||
|
revertOnEat: true
|
||||||
|
|||||||
Reference in New Issue
Block a user