Улучшения Крысиного Короля: увеличен лимит армии, добавлены гвардейцы (#2923)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: VigersRay <60344369+VigersRay@users.noreply.github.com>
Co-authored-by: KaiserMaus <kaiser.ratte@gmail.com>
Co-authored-by: Vigers Ray <vigersray@gmail.com>
This commit is contained in:
Copilot 2025-08-24 01:47:46 +03:00 committed by GitHub
parent 83454714c0
commit bc55df1fe3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 424 additions and 11 deletions

View file

@ -34,6 +34,7 @@ namespace Content.Server.RatKing
base.Initialize();
SubscribeLocalEvent<RatKingComponent, RatKingRaiseArmyActionEvent>(OnRaiseArmy);
SubscribeLocalEvent<RatKingComponent, RatKingRaiseGuardActionEvent>(OnRaiseGuard); // Sunrise-Edit
SubscribeLocalEvent<RatKingComponent, RatKingDomainActionEvent>(OnDomain);
SubscribeLocalEvent<RatKingComponent, AfterPointedAtEvent>(OnPointedAt);
}
@ -82,6 +83,51 @@ namespace Content.Server.RatKing
UpdateServantNpc(servant, component.CurrentOrder);
}
// Sunrise-Start
/// <summary>
/// Summons an allied rat guard at the King, costing a large amount of hunger
/// </summary>
private void OnRaiseGuard(EntityUid uid, RatKingComponent component, RatKingRaiseGuardActionEvent args)
{
if (args.Handled)
return;
if (!TryComp<HungerComponent>(uid, out var hunger))
return;
// Check living guards count
var livingGuards = 0;
foreach (var guardId in component.Guards)
{
if (TryComp<MobStateComponent>(guardId, out var mobState) && mobState.CurrentState != MobState.Dead)
livingGuards++;
}
if (livingGuards >= component.MaxGuardCount)
{
_popup.PopupEntity(Loc.GetString("rat-king-max-guards", ("amount", component.MaxGuardCount)), uid, uid);
return;
}
//make sure the hunger doesn't go into the negatives
if (_hunger.GetHunger(hunger) < component.HungerPerGuardUse)
{
_popup.PopupEntity(Loc.GetString("rat-king-too-hungry"), uid, uid);
return;
}
args.Handled = true;
_hunger.ModifyHunger(uid, -component.HungerPerGuardUse, hunger);
var guard = Spawn(component.GuardMobSpawnId, Transform(uid).Coordinates);
var comp = EnsureComp<RatKingServantComponent>(guard);
comp.King = uid;
Dirty(guard, comp);
component.Guards.Add(guard);
_npc.SetBlackboard(guard, NPCBlackboard.FollowTarget, new EntityCoordinates(uid, Vector2.Zero));
UpdateServantNpc(guard, component.CurrentOrder);
}
// Sunrise-End
/// <summary>
/// uses hunger to release a specific amount of ammonia into the air. This heals the rat king
/// and his servants through a specific metabolism.
@ -117,6 +163,13 @@ namespace Content.Server.RatKing
{
_npc.SetBlackboard(servant, NPCBlackboard.CurrentOrderedTarget, args.Pointed);
}
// Sunrise-Start
foreach (var guard in component.Guards)
{
_npc.SetBlackboard(guard, NPCBlackboard.CurrentOrderedTarget, args.Pointed);
}
// Sunrise-End
}
public override void UpdateServantNpc(EntityUid uid, RatKingOrderType orderType)

View file

@ -7,6 +7,13 @@ public sealed partial class RatKingRaiseArmyActionEvent : InstantActionEvent
}
// Sunrise-Start
public sealed partial class RatKingRaiseGuardActionEvent : InstantActionEvent
{
}
// Sunrise-End
public sealed partial class RatKingDomainActionEvent : InstantActionEvent
{

View file

@ -18,6 +18,29 @@ public sealed partial class RatKingComponent : Component
[DataField("actionRaiseArmyEntity")]
public EntityUid? ActionRaiseArmyEntity;
// Sunrise-Start
[DataField("actionRaiseGuard", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string ActionRaiseGuard = "ActionRatKingRaiseGuard";
/// <summary>
/// The action for the Raise Guard ability
/// </summary>
[DataField("actionRaiseGuardEntity")]
public EntityUid? ActionRaiseGuardEntity;
/// <summary>
/// The amount of hunger one use of Raise Guard consumes
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("hungerPerGuardUse", required: true)]
public float HungerPerGuardUse = 75f;
/// <summary>
/// The entity prototype of the mob that Raise Guard summons
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("guardMobSpawnId", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string GuardMobSpawnId = "MobRatGuard";
// Sunrise-End
/// <summary>
/// The amount of hunger one use of Raise Army consumes
/// </summary>
@ -100,10 +123,19 @@ public sealed partial class RatKingComponent : Component
{ RatKingOrderType.Loose, "RatKingCommandLoose" }
};
// Sunrise-start
// Sunrise-Start
[DataField]
public int MaxArmyCount = 20;
// Sunrise-end
public int MaxArmyCount = 50;
[DataField]
public int MaxGuardCount = 4;
/// <summary>
/// The guards that the rat king is currently controlling
/// </summary>
[DataField("guards")]
public HashSet<EntityUid> Guards = new();
// Sunrise-End
}
[Serializable, NetSerializable]

View file

@ -41,6 +41,7 @@ public abstract class SharedRatKingSystem : EntitySystem
return;
_action.AddAction(uid, ref component.ActionRaiseArmyEntity, component.ActionRaiseArmy, component: comp);
_action.AddAction(uid, ref component.ActionRaiseGuardEntity, component.ActionRaiseGuard, component: comp); // Sunrise-Edit
_action.AddAction(uid, ref component.ActionDomainEntity, component.ActionDomain, component: comp);
_action.AddAction(uid, ref component.ActionOrderStayEntity, component.ActionOrderStay, component: comp);
_action.AddAction(uid, ref component.ActionOrderFollowEntity, component.ActionOrderFollow, component: comp);
@ -58,11 +59,20 @@ public abstract class SharedRatKingSystem : EntitySystem
servantComp.King = null;
}
// Sunrise-Start
foreach (var guard in component.Guards)
{
if (TryComp(guard, out RatKingServantComponent? guardComp))
guardComp.King = null;
}
// Sunrise-End
if (!TryComp(uid, out ActionsComponent? comp))
return;
var actions = new Entity<ActionsComponent?>(uid, comp);
_action.RemoveAction(actions, component.ActionRaiseArmyEntity);
_action.RemoveAction(actions, component.ActionRaiseGuardEntity); // Sunrise-Edit
_action.RemoveAction(actions, component.ActionDomainEntity);
_action.RemoveAction(actions, component.ActionOrderStayEntity);
_action.RemoveAction(actions, component.ActionOrderFollowEntity);
@ -86,8 +96,13 @@ public abstract class SharedRatKingSystem : EntitySystem
private void OnServantShutdown(EntityUid uid, RatKingServantComponent component, ComponentShutdown args)
{
// Sunrise-Start
if (TryComp(component.King, out RatKingComponent? ratKingComponent))
{
ratKingComponent.Servants.Remove(uid);
ratKingComponent.Guards.Remove(uid);
}
// Sunrise-End
}
private void UpdateActions(EntityUid uid, RatKingComponent? component = null)
@ -148,6 +163,13 @@ public abstract class SharedRatKingSystem : EntitySystem
{
UpdateServantNpc(servant, component.CurrentOrder);
}
// Sunrise-Start
foreach (var guard in component.Guards)
{
UpdateServantNpc(guard, component.CurrentOrder);
}
// Sunrise-End
}
public virtual void UpdateServantNpc(EntityUid uid, RatKingOrderType orderType)

View file

@ -2,4 +2,8 @@ rat-king-domain-popup = A cloud of ammonia is released into the air!
rat-king-too-hungry = You are too hungry to use this ability!
rat-king-max-army = You can't have more than {$amount} rats in your army!
rat-king-max-guards = You can't have more than {$amount} rat guards!
rat-king-rummage-text = Rummage

View file

@ -95,6 +95,9 @@ ghost-role-information-rat-king-description = You are the Rat King, your interes
ghost-role-information-rat-servant-name = Rat Servant
ghost-role-information-rat-servant-description = You are a Rat Servant. You must follow your king's orders.
rat-guard-ghost-role-name = Rat Guard
rat-guard-ghost-role-description = You are an elite Rat Guard. Protect your king and follow his orders.
ghost-role-information-salvage-carp-name = Space Carp on Salvage Wreck
ghost-role-information-salvage-carp-description = Defend the loot inside the salvage wreck!

View file

@ -13,3 +13,19 @@ names-regal-rat-kingdom-dataset-12 = Sewer
names-regal-rat-kingdom-dataset-13 = Disposal
names-regal-rat-kingdom-dataset-14 = Service
names-regal-rat-kingdom-dataset-15 = The
names-guard-rat-dataset-1 = Squeaky
names-guard-rat-dataset-2 = Moldy
names-guard-rat-dataset-3 = Nasty
names-guard-rat-dataset-4 = Itchy
names-guard-rat-dataset-5 = Greedy
names-guard-rat-dataset-6 = Rabid
names-guard-rat-dataset-7 = Hungry
names-guard-rat-dataset-8 = Slimy
names-guard-rat-dataset-9 = Cheesy
names-guard-rat-dataset-10 = Rotten
names-guard-rat-dataset-11 = Crusty
names-guard-rat-dataset-12 = Filthy
names-guard-rat-dataset-13 = Wriggly
names-guard-rat-dataset-14 = Foul
names-guard-rat-dataset-15 = Shady

View file

@ -15,3 +15,25 @@ names-regal-rat-title-dataset-14 = Mayor
names-regal-rat-title-dataset-15 = Boss
names-regal-rat-title-dataset-16 = Prophet
names-regal-rat-title-dataset-17 = Cheese
names-guard-rat-title-dataset-1 = Fang
names-guard-rat-title-dataset-2 = Whisker
names-guard-rat-title-dataset-3 = Snout
names-guard-rat-title-dataset-4 = Claw
names-guard-rat-title-dataset-5 = Tail
names-guard-rat-title-dataset-6 = Nibbler
names-guard-rat-title-dataset-7 = Chewer
names-guard-rat-title-dataset-8 = Scab
names-guard-rat-title-dataset-9 = Scratch
names-guard-rat-title-dataset-10 = Muzzle
names-guard-rat-title-dataset-11 = Paws
names-guard-rat-title-dataset-12 = Tooth
names-guard-rat-title-dataset-13 = Bite
names-guard-rat-title-dataset-14 = Gnasher
names-guard-rat-title-dataset-15 = Crumb
names-guard-rat-title-dataset-16 = Ironfang
names-guard-rat-title-dataset-17 = Bloodtail
names-guard-rat-title-dataset-18 = Plaguetooth
names-guard-rat-title-dataset-19 = Spearclaw
names-guard-rat-title-dataset-20 = Rotwhisker
names-guard-rat-title-dataset-21 = Kaiser

View file

@ -1 +1,2 @@
rat-king-max-army = У вас превышено максимальное количество подданных: { $amount }
rat-king-max-army = У вас не может быть больше {$amount} крыс в армии!
rat-king-max-guards = У вас не может быть больше {$amount} крысиных гвардейцев!

View file

@ -75,6 +75,9 @@ ghost-role-information-kobold-name = Кобольд
ghost-role-information-kobold-description = Будьте маленьким гремлином, которым и являетесь, кричите на членов экипажа и просите мяса!
ghost-role-information-rat-king-name = Крысиный король
ghost-role-information-rat-king-description = Вы - Крысиный король, вас интересует еда, еда и ещё раз еда. Сотрудничайте со станцией или сражайтесь с ней ради еды. Я уже упоминал, что вас интересует еда?
rat-guard-ghost-role-name = Крысиный гвардеец
rat-guard-ghost-role-description = Вы элитный крысиный гвардеец. Защищайте своего короля и выполняйте его приказы.
ghost-role-information-rat-servant-name = Крысиный слуга
ghost-role-information-rat-servant-description = Вы Крысиный слуга. Выполняйте приказы своего короля.
ghost-role-information-salvage-carp-name = Космический карп на аварийном обломке

View file

@ -13,3 +13,19 @@ names-regal-rat-kingdom-dataset-12 = Водосточный
names-regal-rat-kingdom-dataset-13 = Помойный
names-regal-rat-kingdom-dataset-14 = Сервисный
names-regal-rat-kingdom-dataset-15 = Конкретный
names-guard-rat-dataset-1 = Пискливый
names-guard-rat-dataset-2 = Плесневый
names-guard-rat-dataset-3 = Гнусный
names-guard-rat-dataset-4 = Зудящий
names-guard-rat-dataset-5 = Жадный
names-guard-rat-dataset-6 = Бешеный
names-guard-rat-dataset-7 = Голодный
names-guard-rat-dataset-8 = Слизкий
names-guard-rat-dataset-9 = Сырный
names-guard-rat-dataset-10 = Гнилой
names-guard-rat-dataset-11 = Корявый
names-guard-rat-dataset-12 = Грязный
names-guard-rat-dataset-13 = Извивающийся
names-guard-rat-dataset-14 = Вонючий
names-guard-rat-dataset-15 = Теневой

View file

@ -15,3 +15,25 @@ names-regal-rat-title-dataset-14 = Мэр
names-regal-rat-title-dataset-15 = Босс
names-regal-rat-title-dataset-16 = Пророк
names-regal-rat-title-dataset-17 = Сыр
names-guard-rat-title-dataset-1 = Клык
names-guard-rat-title-dataset-2 = Ус
names-guard-rat-title-dataset-3 = Пятачок
names-guard-rat-title-dataset-4 = Коготь
names-guard-rat-title-dataset-5 = Хвост
names-guard-rat-title-dataset-6 = Грызун
names-guard-rat-title-dataset-7 = Жевун
names-guard-rat-title-dataset-8 = Струп
names-guard-rat-title-dataset-9 = Царап
names-guard-rat-title-dataset-10 = Мордень
names-guard-rat-title-dataset-11 = Лапы
names-guard-rat-title-dataset-12 = Зуб
names-guard-rat-title-dataset-13 = Укус
names-guard-rat-title-dataset-14 = Склепун
names-guard-rat-title-dataset-15 = Крошка
names-guard-rat-title-dataset-16 = Железноклык
names-guard-rat-title-dataset-17 = Кровехвост
names-guard-rat-title-dataset-18 = Чумозуб
names-guard-rat-title-dataset-19 = Копьекоготь
names-guard-rat-title-dataset-20 = Гнилоус
names-guard-rat-title-dataset-21 = Кайзер

View file

@ -9,3 +9,17 @@
values:
prefix: names-regal-rat-title-dataset-
count: 17
# Sunrise-Start
- type: localizedDataset
id: NamesRatGuard
values:
prefix: names-guard-rat-dataset-
count: 15
- type: localizedDataset
id: NamesRatGuardTitle
values:
prefix: names-guard-rat-title-dataset-
count: 21
# Sunrise-End

View file

@ -12,8 +12,8 @@
# Sunrise edit end
- type: CombatMode
- type: MovementSpeedModifier
baseWalkSpeed : 3.00
baseSprintSpeed : 5.00
baseSprintSpeed: 5
baseWalkSpeed: 4.5
- type: InputMover
- type: MobMover
- type: HTN
@ -54,7 +54,7 @@
- type: MobThresholds
thresholds:
0: Alive
200: Dead
400: Dead # Sunrise-Edit # Пусть стреляют Экспансивками
- type: MeleeWeapon
altDisarm: false
soundHit:
@ -70,7 +70,7 @@
requiredLegs: 1 # TODO: More than 1 leg
- type: Hunger # probably should be prototyped
thresholds:
Overfed: 200
Overfed: 250 # Sunrise-Edit
Okay: 150
Peckish: 100
Starving: 50
@ -111,6 +111,7 @@
- type: RatKing
hungerPerArmyUse: 15 # Sunrise-edit
hungerPerDomainUse: 50 # Sunrise-edit
hungerPerGuardUse: 75 # High cost for guards
- type: MobsterAccent
- type: Speech
speechVerb: SmallMob
@ -137,6 +138,7 @@
bleedReductionAmount: 1
bloodRefreshAmount: 1.5
- type: VentCrawler
- type: NightVision
# Sunrise-end
- type: entity
@ -188,6 +190,7 @@
name: ghost-panel-antagonist-rats-name
description: ghost-panel-antagonist-rats-description
priority: 110
- type: NightVision
# Sunrise edit end
- type: VentCrawler # Sunrise-edit
- type: CombatMode
@ -208,7 +211,7 @@
3.0
- type: Bloodstream
bloodReagent: Blood
bloodMaxVolume: 75
bloodMaxVolume: 60
- type: Reactive
groups:
Flammable: [Touch]
@ -249,8 +252,8 @@
- type: MobThresholds
thresholds:
0: Alive
50: Critical # Sunrise-edit
60: Dead # Sunrise-edit
40: Critical # Sunrise-edit
50: Dead # Sunrise-edit
- type: Destructible
thresholds:
- trigger:
@ -327,6 +330,182 @@
sprite: Mobs/Effects/onfire.rsi
normalState: Mouse_burning
# Sunrise-Start
- type: entity
name: rat guard
id: MobRatGuard
parent: [ SimpleMobBase, MobCombat ]
description: A massive, imposing rat that serves as the king's elite guard.
categories: [ HideSpawnMenu ] #Must be configured to a King or the AI breaks.
components:
- type: GhostPanelAntagonistMarker
name: ghost-panel-antagonist-rats-name
description: ghost-panel-antagonist-rats-description
priority: 110
- type: TypingIndicator
proto: lizard
- type: VentCrawler # Sunrise-edit
- type: CombatMode
- type: MovementSpeedModifier
baseWalkSpeed : 3.2
baseSprintSpeed : 3.8
- type: InputMover
- type: MobMover
- type: HTN
rootTask:
task: RatServantCompound
blackboard:
IdleRange: !type:Single
4.0
FollowCloseRange: !type:Single
2.5
FollowRange: !type:Single
3.5
- type: Bloodstream
bleedReductionAmount: 1
bloodRefreshAmount: 1.5
bloodReagent: Blood
bloodMaxVolume: 200
- type: Reactive
groups:
Flammable: [Touch]
Extinguish: [Touch]
- type: NpcFactionMember
factions:
- SimpleHostile
- type: Sprite
drawdepth: SmallMobs
sprite: Mobs/Animals/buffrat.rsi
# scale: 1.2, 1.2 # Smaller that RatKingBuff
layers:
- map: ["enum.DamageStateVisualLayers.Base"]
state: regalrat
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded"]
state: eyes
shader: unshaded
- type: Physics
bodyType: KinematicController
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeCircle
radius: 0.35
density: 80 #Bulky guard
mask:
- SmallMobMask
layer:
- SmallMobLayer
- type: MobState
- type: MobThresholds
thresholds:
0: Alive
350: Critical # High HP as requested
400: Dead # High HP as requested
- type: SlowOnDamage
speedModifierThresholds:
200: 0.8
250: 0.6
- type: Destructible
thresholds:
- trigger:
!type:DamageTypeTrigger
damageType: Blunt
damage: 600
behaviors:
- !type:GibBehavior
recursive: false
- type: Stamina
critThreshold: 400
- type: MeleeWeapon
soundHit:
path: /Audio/Weapons/Xeno/alien_claw_flesh2.ogg
angle: 0
animation: WeaponArcClaw
damage:
types:
Slash: 5 # Additional claw damage
Piercing: 5 # Additional claw damage
Blunt: 25 # Strong guard attack
Structural: 10 # Strong guard attack
bluntStaminaDamageFactor: 1.75
- type: MeleeThrowOnHit
distance: 0.75
speed: 8
- type: Body
prototype: Rat
requiredLegs: 1 # TODO: More than 1 leg
- type: Hunger # probably should be prototyped
thresholds:
Overfed: 300
Okay: 200
Peckish: 150
Starving: 100
Dead: 0
baseDecayRate: 0.025 # Faster hunger decay for guards
- type: Thirst
thresholds:
OverHydrated: 600
Okay: 450
Thirsty: 300
Parched: 150
Dead: 0
baseDecayRate: 0.15 # Faster thirst decay
- type: DamageStateVisuals
states:
Alive:
Base: regalrat
BaseUnshaded: eyes
Critical:
Base: dead
Dead:
Base: dead
- type: Butcherable
spawned:
- id: FoodMeatRat
amount: 3 # More meat from guards
- type: Vocal
sounds:
Male: Mouse
Female: Mouse
Unsexed: Mouse
wilhelmProbability: 0.001
- type: Tag
tags:
- CannotSuicide
- FootstepSound
- type: NoSlip
- type: MobPrice
price: 1500 # Higher value for guards
- type: MobsterAccent
isBoss: false
- type: Speech
speechVerb: SmallMob
- type: GuideHelp
guides:
- MinorAntagonists
- type: FireVisuals
sprite: Mobs/Effects/onfire.rsi
normalState: Mouse_burning
- type: RatKingServant # Make them servants too
- type: GhostRole
makeSentient: true
name: rat-guard-ghost-role-name
description: rat-guard-ghost-role-description
rules: ghost-role-information-antagonist-rules
mindRoles:
- MindRoleGhostRoleSoloAntagonist
raffle:
settings: short
- type: GhostTakeoverAvailable
- type: NightVision
- type: RandomMetadata
nameSegments:
- NamesRatGuard
- NamesRatGuardTitle
nameFormat: name-format-regal-rat
# Sunrise-end
- type: weightedRandomEntity
id: RatKingLoot
weights:
@ -438,3 +617,19 @@
event:
!type:RatKingOrderActionEvent
type: Loose
# Sunrise-Start
- type: entity
parent: BaseAction
id: ActionRatKingRaiseGuard
name: Raise Guard
description: Spend a large amount of hunger to summon an elite rat guard to serve you.
components:
- type: Action
useDelay: 8
icon:
sprite: Interface/Actions/actions_rat_king.rsi
state: ratKingGuard
- type: InstantAction
event: !type:RatKingRaiseGuardActionEvent
# Sunrise-End

View file

@ -36,6 +36,9 @@
},
{
"name": "ratKingDomain"
},
{
"name": "ratKingGuard"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 B