Ling stuff (#245)

* - fix: Absorb is transfered on transform.

* - fix: Transfer absorbed count on transform.

* - fix: Transfer rev roles on transform.

* - add: Ling mood effect.

* - tweak: Buff armblade.

* - fix: Transfer mood on transform.

* - tweak: Better absorbed desc.

* - add: Hive head.

* - remove: No popup.
This commit is contained in:
Aviu00
2024-03-25 21:57:32 +09:00
committed by GitHub
parent c60f37788a
commit da0f192444
20 changed files with 310 additions and 19 deletions

View File

@@ -9,6 +9,7 @@ using Content.Server.Mind;
using Content.Server.NPC.Systems;
using Content.Server.Objectives;
using Content.Server.Roles;
using Content.Shared._White.Mood;
using Content.Shared.Changeling;
using Content.Shared.GameTicking;
using Content.Shared.Objectives.Components;
@@ -191,6 +192,8 @@ public sealed class ChangelingRuleSystem : GameRuleSystem<ChangelingRuleComponen
_npcFaction.RemoveFaction(entity, "NanoTrasen", false);
_npcFaction.AddFaction(entity, "Syndicate");
RaiseLocalEvent(mind.OwnedEntity.Value, new MoodEffectEvent("TraitorFocused"));
EnsureComp<ChangelingComponent>(entity, out var readyChangeling);
readyChangeling.HiveName = _nameGenerator.GetName();

View File

@@ -1,5 +1,6 @@
using System.Linq;
using Content.Server._White.Cult.GameRule;
using Content.Server._White.Mood;
using Content.Server.Administration.Systems;
using Content.Server.Bible.Components;
using Content.Server.Body.Components;
@@ -84,6 +85,7 @@ public sealed partial class ChangelingSystem
[Dependency] private readonly CuffableSystem _cuffable = default!;
[Dependency] private readonly NukeopsRuleSystem _nukeOps = default!;
[Dependency] private readonly CultRuleSystem _cult = default!;
[Dependency] private readonly RevolutionaryRuleSystem _rev = default!;
[Dependency] private readonly NpcFactionSystem _faction = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly EmpSystem _empSystem = default!;
@@ -91,6 +93,7 @@ public sealed partial class ChangelingSystem
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly ServerBorerSystem _borer = default!;
[Dependency] private readonly CarryingSystem _carrying = default!;
[Dependency] private readonly MoodSystem _mood = default!;
private void InitializeAbilities()
{
@@ -116,6 +119,7 @@ public sealed partial class ChangelingSystem
SubscribeLocalEvent<ChangelingComponent, ArmbladeActionEvent>(OnArmBlade);
SubscribeLocalEvent<ChangelingComponent, OrganicShieldActionEvent>(OnShield);
SubscribeLocalEvent<ChangelingComponent, ChitinousArmorActionEvent>(OnArmor);
SubscribeLocalEvent<ChangelingComponent, HiveHeadActionEvent>(OnHiveHead);
SubscribeLocalEvent<ChangelingComponent, TentacleArmActionEvent>(OnTentacleArm);
SubscribeLocalEvent<ChangelingComponent, TransformDoAfterEvent>(OnTransformDoAfter);
@@ -147,6 +151,13 @@ public sealed partial class ChangelingSystem
private const string ChangelingArmor = "ActionArmor";
private const string ChangelingTentacleArm = "ActionTentacleArm";
private const string OuterName = "outerClothing";
private const string HeadName = "head";
private const string ArmorName = "ClothingOuterChangeling";
private const string HelmetName = "ClothingHeadHelmetLing";
private const string HiveHeadName = "ClothingHeadHelmetLingHive";
#endregion
#region Handlers
@@ -564,15 +575,10 @@ public sealed partial class ChangelingSystem
private void OnArmor(EntityUid uid, ChangelingComponent component, ChitinousArmorActionEvent args)
{
const string outerName = "outerClothing";
const string headName = "head";
const string armorName = "ClothingOuterChangeling";
const string helmetName = "ClothingHeadHelmetLing";
_inventorySystem.TryUnequip(uid, OuterName, out var outer, true, true);
_inventorySystem.TryUnequip(uid, HeadName, out var helmet, true, true);
_inventorySystem.TryUnequip(uid, outerName, out var outer, true, true);
_inventorySystem.TryUnequip(uid, headName, out var helmet, true, true);
if (TryComp(outer, out MetaDataComponent? metaData) && metaData.EntityPrototype is {ID: armorName})
if (TryComp(outer, out MetaDataComponent? metaData) && metaData.EntityPrototype is {ID: ArmorName})
{
args.Handled = true;
return;
@@ -581,16 +587,49 @@ public sealed partial class ChangelingSystem
if (!TakeChemicals(uid, component, 20))
{
if (outer != null)
_inventorySystem.TryEquip(uid, outer.Value, outerName, true, true);
_inventorySystem.TryEquip(uid, outer.Value, OuterName, true, true);
if (helmet != null)
_inventorySystem.TryEquip(uid, helmet.Value, headName, true, true);
_inventorySystem.TryEquip(uid, helmet.Value, HeadName, true, true);
return;
}
_inventorySystem.SpawnItemInSlot(uid, outerName, armorName, true, true);
_inventorySystem.SpawnItemInSlot(uid, headName, helmetName, true, true);
_inventorySystem.SpawnItemInSlot(uid, OuterName, ArmorName, true, true);
_inventorySystem.SpawnItemInSlot(uid, HeadName, HelmetName, true, true);
args.Handled = true;
}
private void OnHiveHead(EntityUid uid, ChangelingComponent component, HiveHeadActionEvent args)
{
if (!_mobStateSystem.IsAlive(uid))
return;
_inventorySystem.TryUnequip(uid, HeadName, out var helmet, true, true);
if (TryComp(helmet, out MetaDataComponent? metaData) && metaData.EntityPrototype != null)
{
switch (metaData.EntityPrototype.ID)
{
case HiveHeadName:
args.Handled = true;
return;
case HelmetName:
_inventorySystem.TryUnequip(uid, OuterName, out _, true, true);
break;
}
}
if (!TakeChemicals(uid, component, 15))
{
if (helmet != null)
_inventorySystem.TryEquip(uid, helmet.Value, HeadName, true, true);
return;
}
_inventorySystem.SpawnItemInSlot(uid, HeadName, HiveHeadName, true, true);
args.Handled = true;
}
@@ -783,6 +822,7 @@ public sealed partial class ChangelingSystem
ChemicalsBalance = component.ChemicalsBalance,
AbsorbedEntities = component.AbsorbedEntities,
IsInited = component.IsInited,
AbsorbedCount = component.AbsorbedCount,
IsLesserForm = true
};
@@ -928,7 +968,8 @@ public sealed partial class ChangelingSystem
HiveName = lingComp.HiveName,
ChemicalsBalance = lingComp.ChemicalsBalance,
AbsorbedEntities = lingComp.AbsorbedEntities,
IsInited = lingComp.IsInited
IsInited = lingComp.IsInited,
AbsorbedCount = lingComp.AbsorbedCount
};
EntityManager.AddComponent(polymorphEntity.Value, toAdd);
@@ -955,6 +996,9 @@ public sealed partial class ChangelingSystem
private void TransferComponents(EntityUid from, EntityUid to)
{
if (HasComp<AbsorbedComponent>(from))
EnsureComp<AbsorbedComponent>(to);
if (HasComp<BibleUserComponent>(from))
EnsureComp<BibleUserComponent>(to);
@@ -992,6 +1036,22 @@ public sealed partial class ChangelingSystem
}
}
if (TryComp(from, out MoodComponent? mood))
{
var newMood = EnsureComp<MoodComponent>(to);
foreach (var effect in mood.CategorisedEffects)
{
_mood.ApplyEffect(to, newMood, effect.Value);
}
foreach (var effect in mood.UncategorisedEffects)
{
_mood.ApplyEffect(to, newMood, effect.Key);
}
}
_rev.TransferRole(from, to);
_nukeOps.TransferRole(from, to);
_cult.TransferRole(from, to);

View File

@@ -3,6 +3,7 @@ using Content.Server.Store.Systems;
using Content.Shared.Actions;
using Content.Shared.Changeling;
using Content.Shared.Examine;
using Content.Shared.IdentityManagement;
using Content.Shared.Implants;
using Content.Shared.Implants.Components;
@@ -41,7 +42,7 @@ public sealed partial class ChangelingSystem : EntitySystem
private void OnExamine(EntityUid uid, AbsorbedComponent component, ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("changeling-juices-sucked-up"));
args.PushMarkup(Loc.GetString("changeling-juices-sucked-up", ("target", Identity.Entity(uid, EntityManager))));
}
#endregion

View File

@@ -0,0 +1,50 @@
using Content.Server.Actions;
using Content.Shared.Actions;
using Content.Shared.Changeling;
using Content.Shared.Inventory;
namespace Content.Server.Changeling;
public sealed class HiveHeadSystem : EntitySystem
{
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HiveHeadComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<HiveHeadComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<HiveHeadComponent, GetItemActionsEvent>(OnGetActions);
SubscribeLocalEvent<HiveHeadComponent, ReleaseBeesEvent>(OnReleaseBees);
}
private void OnReleaseBees(Entity<HiveHeadComponent> ent, ref ReleaseBeesEvent args)
{
args.Handled = true;
var coords = Transform(args.Performer).Coordinates;
for (var i = 0; i < ent.Comp.BeesAmount; i++)
{
Spawn(ent.Comp.BeeProto, coords);
}
}
private void OnGetActions(Entity<HiveHeadComponent> ent, ref GetItemActionsEvent args)
{
if (args.SlotFlags == SlotFlags.HEAD)
args.AddAction(ref ent.Comp.ActionEntity, ent.Comp.Action);
}
private void OnShutdown(Entity<HiveHeadComponent> ent, ref ComponentShutdown args)
{
_actions.RemoveAction(ent, ent.Comp.ActionEntity);
}
private void OnMapInit(Entity<HiveHeadComponent> ent, ref MapInitEvent args)
{
_actionContainer.EnsureAction(ent, ref ent.Comp.ActionEntity, ent.Comp.Action);
}
}

View File

@@ -358,4 +358,25 @@ public sealed class RevolutionaryRuleSystem : GameRuleSystem<RevolutionaryRuleCo
// revs lost and heads died
"rev-stalemate"
};
public void TransferRole(EntityUid transferFrom, EntityUid transferTo)
{
if (HasComp<CommandStaffComponent>(transferFrom))
{
EnsureComp<CommandStaffComponent>(transferTo);
RemComp<CommandStaffComponent>(transferFrom);
}
if (HasComp<HeadRevolutionaryComponent>(transferFrom))
{
EnsureComp<HeadRevolutionaryComponent>(transferTo);
RemComp<HeadRevolutionaryComponent>(transferFrom);
}
if (!HasComp<RevolutionaryComponent>(transferFrom))
return;
EnsureComp<RevolutionaryComponent>(transferTo);
RemComp<RevolutionaryComponent>(transferFrom);
}
}

View File

@@ -80,6 +80,14 @@ public sealed class MoodSystem : EntitySystem
ApplyEffect(uid, component, prototype);
}
public void ApplyEffect(EntityUid uid, MoodComponent component, string id)
{
if (!_prototypeManager.TryIndex<MoodEffectPrototype>(id, out var prototype))
return;
ApplyEffect(uid, component, prototype);
}
private void ApplyEffect(EntityUid uid, MoodComponent component, MoodEffectPrototype prototype)
{
var amount = component.CurrentMoodLevel;

View File

@@ -0,0 +1,20 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Changeling;
[RegisterComponent]
public sealed partial class HiveHeadComponent : Component
{
[DataField]
public int BeesAmount = 4;
[DataField(customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string BeeProto = "MobTemporaryAngryBee";
[DataField(customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Action = "ActionReleaseBees";
[DataField]
public EntityUid? ActionEntity;
}

View File

@@ -86,6 +86,14 @@ public sealed partial class ChitinousArmorActionEvent : InstantActionEvent
{
}
public sealed partial class HiveHeadActionEvent : InstantActionEvent
{
}
public sealed partial class ReleaseBeesEvent : InstantActionEvent
{
}
public sealed partial class TentacleArmActionEvent : InstantActionEvent
{
}

View File

@@ -1,6 +1,7 @@
using System.Numerics;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Humanoid;
using Content.Shared.Mobs.Components;
using Content.Shared.Physics;
using Content.Shared.Projectiles;
using Content.Shared.Stunnable;
@@ -11,6 +12,7 @@ using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.Input;
using Robust.Shared.Network;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
@@ -36,6 +38,22 @@ public abstract class SharedTentacleGun : EntitySystem
SubscribeLocalEvent<TentacleGunComponent, GunShotEvent>(OnTentacleShot);
SubscribeLocalEvent<TentacleProjectileComponent, MapInitEvent>(OnMapInit); // WD
SubscribeLocalEvent<TentacleProjectileComponent, ProjectileEmbedEvent>(OnTentacleCollide);
SubscribeLocalEvent<TentacleProjectileComponent, PreventCollideEvent>(PreventCollision);
}
private void PreventCollision(Entity<TentacleProjectileComponent> ent, ref PreventCollideEvent args)
{
if (HasComp<MobStateComponent>(args.OtherEntity) && !HasComp<HumanoidAppearanceComponent>(args.OtherEntity))
{
args.Cancelled = true;
return;
}
if (!TryComp(ent, out ProjectileComponent? projectile))
return;
if (args.OtherEntity == projectile.Shooter || args.OtherEntity == projectile.Weapon)
args.Cancelled = true;
}
// WD EDIT START

View File

@@ -2,7 +2,7 @@ chat-manager-changeling-channel-name = УЛЕЙ
hud-chatbox-select-channel-Changeling = Улей
chat-manager-send-changeling-chat-wrap-message = [bold]\[УЛЕЙ\][/bold] [font size=13][italic][bold]{ $player }[/bold] шипит, "{ $message }"[/italic][/font]
changeling-juices-sucked-up = [color=#A30000]Все его соки были высосаны![/color]
changeling-juices-sucked-up = [color=#A30000]Все { POSS-ADJ($target) } соки были высосаны![/color]
changeling-unknown-creature = Неизвестное существо

View File

@@ -32,7 +32,7 @@ changeling-ability-transform-sting = Жало трансформации
changeling-ability-transform-sting-desc = Вводит в кровь цели вирус, заставляющий её превратиться в другое существо. Стоит 50 химикатов.
changeling-ability-extraction-sting = Жало извлечения
changeling-ability-extraction-sting-desc = Безшумно и безопасно извлекает ДНК из цели. Стоит 25 химикатов.
changeling-ability-extraction-sting-desc = Бесшумно и безопасно извлекает ДНК из цели. Стоит 25 химикатов.
changeling-ability-tentacle-arm = Рука-щупальце
changeling-ability-tentacle-arm-desc = Превращает одну из рук в щупальце, способное притягивать людей или забирать вещи из их рук. Стоит 10 химикатов.
@@ -40,6 +40,9 @@ changeling-ability-tentacle-arm-desc = Превращает одну из рук
changeling-ability-changeling-armor = Хитиновая броня
changeling-ability-changeling-armor-desc = Надувает тело, превращая его в крепкую хитиновую броню. При использовании замедляет регенерацию химикатов на 25%. Стоит 20 химикатов.
changeling-ability-hive = Голова улья
changeling-ability-hive-desc = Хотя голова улья не предоставляет особых возможностей для защиты, она позволяет отправлять пчёл в атаку на цели. Также защищает от вспышек и яркого света. Несовместимо с хитиновой бронёй. Стоит 15 химикатов.
changeling-ability-changeling-shield = Органический щит
changeling-ability-changeling-shield-desc = Превращает одну из рук в крепкий органический щит. Стоит 20 химикатов.
@@ -49,6 +52,9 @@ changeling-ability-changeling-armblade-desc = Превращает одну из
changeling-ability-changeling-lesser-form = Примитивная форма
changeling-ability-changeling-lesser-form-desc = Превращает в самую примитивную форму. Полезно для побега из наручников. Стоит 5 химикатов.
changeling-ability-bees = Выпустить пчёл
changeling-ability-bees-desc = Выпускает 4 агрессивных пчелы из улья.
ent-ActionChangelingShop = Эволюции
.desc = Эволюционируйте и развивайтесь.
@@ -67,6 +73,9 @@ ent-OrganicShield = органический щит
ent-ClothingOuterChangeling = хитиновая броня
.desc = Броня из хитина и плоти.
ent-ClothingHeadHelmetLingHive = голова улья
.desc = Странное восковое образование, покрывающее голову. Вызывает шум в ушах.
ent-TentacleArmGun = рука-щупальце
.desc = Огромное щупальце, способное притягивать людей и вырывать предметы из их рук.

View File

@@ -206,6 +206,20 @@
useDelay: 1
- type: LesserFormRestricted
- type: entity
id: ActionHive
name: changeling-ability-hive
description: changeling-ability-hive-desc
noSpawn: true
components:
- type: InstantAction
itemIconStyle: NoItem
icon: White/Actions/changeling.rsi/hive_head.png
event: !type:HiveHeadActionEvent
useDelay: 1
checkCanInteract: false
- type: LesserFormRestricted
- type: entity
id: ActionTentacleArm
name: changeling-ability-tentacle-arm

View File

@@ -51,6 +51,19 @@
- !type:ListingLimitedStockCondition
stock: 1
- type: listing
id: ChangelingHive
name: changeling-ability-hive
description: changeling-ability-hive-desc
productAction: ActionHive
cost:
ChangelingPoint: 2
categories:
- ChangelingAbilities
conditions:
- !type:ListingLimitedStockCondition
stock: 1
- type: listing
id: ChangelingTentacleArm
name: changeling-ability-tentacle-arm

View File

@@ -10,11 +10,10 @@
state: icon
- type: MeleeWeapon
wideAnimationRotation: 90
attackRate: 0.75
damage:
types:
Slash: 17
Piercing: 17
Slash: 20
Piercing: 20
Structural: 45
soundHit:
path: /Audio/Weapons/bladeslice.ogg

View File

@@ -0,0 +1,46 @@
- type: entity
parent: ClothingHeadBase
id: ClothingHeadHelmetLingHive
name: hive head
description: A strange, waxy outer coating covering your head. Gives you tinnitus.
components:
- type: Sprite
sprite: White/Clothing/Head/hive.rsi
- type: Clothing
sprite: White/Clothing/Head/hive.rsi
- type: Armor
modifiers:
coefficients:
Blunt: 0.9
Slash: 0.9
Piercing: 0.9
Heat: 0.9
- type: Unremoveable
deleteOnDrop: true
- type: DeleteOnChangelingRefund
- type: FlashImmunity
- type: EyeProtection
- type: HiveHead
- type: entity
id: ActionReleaseBees
name: changeling-ability-bees
description: changeling-ability-bees-desc
noSpawn: true
components:
- type: InstantAction
itemIconStyle: NoItem
icon: White/Clothing/Head/hive.rsi/icon.png
event: !type:ReleaseBeesEvent
checkCanInteract: false
useDelay: 30
- type: entity
parent: MobAngryBee
id: MobTemporaryAngryBee
components:
- type: TimedDespawn
lifetime: 25.0
- type: NpcFactionMember
factions:
- Syndicate

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

View File

@@ -31,6 +31,9 @@
{
"name": "organic_suit"
},
{
"name": "hive_head"
},
{
"name": "fleshmend"
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

View File

@@ -0,0 +1,18 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from TGstation github https://github.com/tgstation/tgstation/commit/94186dcdb93420d617cc6418534556e05fa8a7d8",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "equipped-HELMET",
"directions": 4
}
]
}