From cc30b09b0191ef47e716ff0710e51fcdd21abd91 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 15 Jan 2025 16:59:05 +0100 Subject: [PATCH] Port Gladiabot from EE PR source: https://github.com/Simple-Station/Einstein-Engines/pull/1548 --- Content.Server/NPC/FactionData.cs | 3 + .../NPC/Systems/NPCCombatSystem.Melee.cs | 5 ++ .../NPC/Systems/NpcFactionSystem.cs | 9 ++- .../interaction-popup-component.ftl | 2 + .../Entities/Mobs/NPCs/gladiabot.yml | 70 ++++++++++++++++++ Resources/Prototypes/NPCs/gladiabot.yml | 12 +++ .../Crafting/Graphs/bots/gladiabot.yml | 25 +++++++ .../Prototypes/Recipes/Crafting/bots.yml | 13 ++++ Resources/Prototypes/ai_factions.yml | 5 ++ .../Silicon/Bots/gladiabot.rsi/gladiabot.png | Bin 0 -> 2372 bytes .../Mobs/Silicon/Bots/gladiabot.rsi/meta.json | 20 +++++ 11 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 Resources/Prototypes/Entities/Mobs/NPCs/gladiabot.yml create mode 100644 Resources/Prototypes/NPCs/gladiabot.yml create mode 100644 Resources/Prototypes/Recipes/Crafting/Graphs/bots/gladiabot.yml create mode 100644 Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/gladiabot.png create mode 100644 Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/meta.json diff --git a/Content.Server/NPC/FactionData.cs b/Content.Server/NPC/FactionData.cs index b74150acc9d..d42059d6aef 100644 --- a/Content.Server/NPC/FactionData.cs +++ b/Content.Server/NPC/FactionData.cs @@ -5,6 +5,9 @@ namespace Content.Server.NPC; /// public sealed class FactionData { + [ViewVariables] + public bool IsHostileToSelf; + [ViewVariables] public HashSet Friendly = new(); diff --git a/Content.Server/NPC/Systems/NPCCombatSystem.Melee.cs b/Content.Server/NPC/Systems/NPCCombatSystem.Melee.cs index 2ae20817e28..a5279ae857b 100644 --- a/Content.Server/NPC/Systems/NPCCombatSystem.Melee.cs +++ b/Content.Server/NPC/Systems/NPCCombatSystem.Melee.cs @@ -1,5 +1,6 @@ using System.Numerics; using Content.Server.NPC.Components; +using Content.Server.NPC.HTN; using Content.Shared.CombatMode; using Content.Shared.NPC; using Robust.Shared.Map; @@ -10,6 +11,7 @@ namespace Content.Server.NPC.Systems; public sealed partial class NPCCombatSystem { + [Dependency] private readonly IRobustRandom _rng = default!; private const float TargetMeleeLostRange = 14f; private void InitializeMelee() @@ -114,5 +116,8 @@ private void Attack(EntityUid uid, NPCMeleeCombatComponent component, TimeSpan c { _melee.AttemptLightAttack(uid, weaponUid, weapon, component.Target); } + + if (Comp(uid).Blackboard.TryGetValue("AttackDelayDeviation", out var dev, EntityManager)) + weapon.NextAttack += TimeSpan.FromSeconds(_rng.NextFloat(-dev, dev)); } } diff --git a/Content.Server/NPC/Systems/NpcFactionSystem.cs b/Content.Server/NPC/Systems/NpcFactionSystem.cs index a96067c5cf3..663dbac9c77 100644 --- a/Content.Server/NPC/Systems/NpcFactionSystem.cs +++ b/Content.Server/NPC/Systems/NpcFactionSystem.cs @@ -169,7 +169,12 @@ public bool IsEntityFriendly(EntityUid uidA, EntityUid uidB, NpcFactionMemberCom if (!Resolve(uidA, ref factionA, false) || !Resolve(uidB, ref factionB, false)) return false; - return factionA.Factions.Overlaps(factionB.Factions) || factionA.FriendlyFactions.Overlaps(factionB.Factions); + var intersect = factionA.Factions.Intersect(factionB.Factions); // factions which have both ent and other as members + foreach (var faction in intersect) + if (_factions[faction].IsHostileToSelf) + return false; + + return intersect.Count() > 0 || factionA.FriendlyFactions.Overlaps(factionB.Factions); } public bool IsFactionFriendly(string target, string with) @@ -234,9 +239,9 @@ private void RefreshFactions() faction => faction.ID, faction => new FactionData { + IsHostileToSelf = faction.Hostile.Contains(faction.ID), Friendly = faction.Friendly.ToHashSet(), Hostile = faction.Hostile.ToHashSet() - }); foreach (var comp in EntityQuery(true)) diff --git a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl index 7bce6616c5b..4792db3e5fa 100644 --- a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl +++ b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl @@ -62,11 +62,13 @@ petting-success-mimebot = You pet {THE($target)} on {POSS-ADJ($target)} cold met petting-success-cleanbot = You pet {THE($target)} on {POSS-ADJ($target)} damp metal head. petting-success-medibot = You pet {THE($target)} on {POSS-ADJ($target)} sterile metal head. petting-success-recycler = You pet {THE($target)} on {POSS-ADJ($target)} mildly threatening steel exterior. +petting-success-gladiabot = You pet {THE($target)} on {POSS-ADJ($target)} vicious cardboard head. petting-failure-honkbot = You reach out to pet {THE($target)}, but {SUBJECT($target)} honks in refusal! petting-failure-cleanbot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy mopping! petting-failure-mimebot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy miming! petting-failure-medibot = You reach out to pet {THE($target)}, but {POSS-ADJ($target)} syringe nearly stabs your hand! +petting-failure-gladiabot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} only wants to fight! ## Rattling fences diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/gladiabot.yml b/Resources/Prototypes/Entities/Mobs/NPCs/gladiabot.yml new file mode 100644 index 00000000000..a1a75ea6957 --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/NPCs/gladiabot.yml @@ -0,0 +1,70 @@ +- type: entity + parent: MobSiliconBase + id: MobGladiaBot + name: gladiabot + description: For glory! + components: + - type: Sprite + sprite: Mobs/Silicon/Bots/gladiabot.rsi + state: gladiabot + - type: Construction + graph: GladiaBot + node: bot + - type: SentienceTarget + flavorKind: station-event-random-sentience-flavor-mechanical + - type: UseDelay + delay: 1 + - type: NpcFactionMember + factions: + - GladiabotFFA + - type: CombatMode + - type: MeleeWeapon + altDisarm: false + soundHit: + path: /Audio/Weapons/bladeslice.ogg + angle: 0 + animation: WeaponArcPunch + damage: + types: + Slash: 3 + - type: MobThresholds + thresholds: + 0: Alive + 40: Dead + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 30 + behaviors: + - !type:TriggerBehavior + - trigger: + !type:DamageTrigger + damage: 40 + behaviors: + - !type:SpawnEntitiesBehavior + spawn: + ProximitySensor: + min: 1 + max: 1 + - !type:SpawnEntitiesBehavior + spawn: + MaterialCloth1: + min: 1 + max: 1 + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: MovementSpeedModifier + baseWalkSpeed: 2 + baseSprintSpeed: 3 + - type: HTN + rootTask: + task: GladiabotCompound + blackboard: + AttackDelayDeviation: !type:Single + 0.3 + - type: InteractionPopup + interactSuccessString: petting-success-gladiabot + interactFailureString: petting-failure-gladiabot + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg diff --git a/Resources/Prototypes/NPCs/gladiabot.yml b/Resources/Prototypes/NPCs/gladiabot.yml new file mode 100644 index 00000000000..5e7170ee276 --- /dev/null +++ b/Resources/Prototypes/NPCs/gladiabot.yml @@ -0,0 +1,12 @@ +- type: htnCompound + id: GladiabotCompound + branches: + - tasks: + - !type:HTNPrimitiveTask + operator: !type:UtilityOperator + proto: NearbyMeleeTargets + - !type:HTNCompoundTask + task: MeleeAttackTargetCompound + - tasks: + - !type:HTNCompoundTask + task: IdleCompound diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/bots/gladiabot.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/gladiabot.yml new file mode 100644 index 00000000000..ddcfceaef40 --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/gladiabot.yml @@ -0,0 +1,25 @@ +- type: constructionGraph + id: GladiaBot + start: start + graph: + - node: start + edges: + - to: bot + steps: + - material: Cardboard + amount: 1 + doAfter: 2 + - tag: ProximitySensor + icon: + sprite: Objects/Misc/proximity_sensor.rsi + state: icon + name: proximity sensor + doAfter: 2 + - tag: Shiv + icon: + sprite: Objects/Weapons/Melee/shiv.rsi + state: icon + name: shiv + doAfter: 2 + - node: bot + entity: MobGladiaBot diff --git a/Resources/Prototypes/Recipes/Crafting/bots.yml b/Resources/Prototypes/Recipes/Crafting/bots.yml index 3031f4a7803..64106f663f1 100644 --- a/Resources/Prototypes/Recipes/Crafting/bots.yml +++ b/Resources/Prototypes/Recipes/Crafting/bots.yml @@ -75,3 +75,16 @@ icon: sprite: Mobs/Silicon/Bots/supplybot.rsi state: supplybot + +- type: construction + name: gladiabot + id: gladiabot + graph: GladiaBot + startNode: start + targetNode: bot + category: construction-category-utilities + objectType: Item + description: This bot fights for honour and glory! + icon: + sprite: Mobs/Silicon/Bots/gladiabot.rsi + state: gladiabot diff --git a/Resources/Prototypes/ai_factions.yml b/Resources/Prototypes/ai_factions.yml index cdbbf868662..6c5b611f958 100644 --- a/Resources/Prototypes/ai_factions.yml +++ b/Resources/Prototypes/ai_factions.yml @@ -106,3 +106,8 @@ - type: npcFaction id: AnimalFriend + +- type: npcFaction + id: GladiabotFFA + hostile: + - GladiabotFFA diff --git a/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/gladiabot.png b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/gladiabot.png new file mode 100644 index 0000000000000000000000000000000000000000..e8994abca125332e4c4c581239bdc0fc15322416 GIT binary patch literal 2372 zcmah~4Nwzj8V;5K#SxH0r9yRGwSc(E=08~jC?P^DAvp+F?Agj@cLO_+Y}hO$F#aGv z2hx^u7Az>&DR*t}2c;*dT!&hr<$9dgJ3MGR2gf1SRvi@qwRm^6aNmYN>5S9M%x3p{ z_j#Z9eV_OJzCCKrNL>}YK3E_StTLpfWP&>cuAM|oQ+ccgt}j`-R9J9TjO>K(P*fcY2OYsJx9>-4`jj|QK{n#Udpjq8s^tV``X zH!(q+xi#^{srJftC@68~m@r1aE^cP*t;?`wy7#L?j~>n?-FRbV(7Ev8Q}snVhwZY} zP5qoL`%YPP=)uTdd9t+YokioD*Uv;0<$T6nS~s+z zy|r6i@OE&)gFo+&9Jm#4=ok*(RJXN1tR_gfCgR5xuLMnEacjdl(Ycw>o;me<5$u}2 zfivY&`9R0UN1=xXKfh$m@EH7_ym_Fg_0`pH7OeZtb5Gy+<{w43V#?>A`oqx4Id)a^ zw_7fZe)?hR&UvM?=wF{UCQPt_k!4act7K~uvg!3F#s_bnl=e;_m%Fb2^>k7Fa3G}b zdj12ykdPyP*HZ6xm%81z$L8L@_P5ZX&@;hoZ~Rx+_zvZo(=B?HTA7-bQd?K&(XmWf@nK(5UsHTYlt3U%rY$*Kjxil07`q5387n37*qs0^5NMM;PMj#9ILJ!n(T)Uo zs^=mM(PRSroWh72ojNL?PAg-ntg;LXQC2``NH{5RRj}5B0R}t8;gH8(=x|}41lUWA zfoI+n%r?c`|20r9lBl_};DV35Z` zf_A6TxWw*o`E&q^h&{MdED@n%yPeP4i*|AP65#C1<*{g&rPN7@GbtBS%o3EogmQ43 z7u`u>$=6xT7J9272{Bbj*#XQ2qDhuQr5cRpB{W}k9&LAeJ%GYXD2}#$r_J~B;oo@E zUknc1miWGhT&$A^0x_@@hA8IqF{C8Gd{B&J2%5yak1DAex2Xv!qEg~GBDYZlV#O6C zf>J6HC*^7hDnS={3=S8EI|z#B0n8#Akf?D&j>@bAqLx}wM6N>Bh*e>w5E)4l8jV^( zDixYVe-lfC(ZdUu=fm@mfConjN}^H_h)hLNh+K^;5DhM|A(UJulW9nm5(I%ElE8K| ztQ`j}qwRPeC3ZUUV2D>1+hsN+z)}%N*1I$p;+zdY!FzCU!Vs@K29gI7;{4bFS8qv}j-_ypVJ!?(m;m!( zA>L=p1e3@u5-Fz8U@`@Q0?Q(pA!%Fb|ATtB5(IwQg}$cI zE)czR$?V%8Sya(7lh0U4L*7}(aAKhZ7hXb3bdQE{1N?NTN zM6JSYh@7INh!q75$K?{6RbwMj(DFrp7h~hxI7{uy1F8XWz}R`kfnt6Ah+9Ou^C@0z zAP|B|knaRi!;pAc9a=HJ*_YR*6+cdf1>CYj!ppH>1t$<#0l&pVjbAMtjFbZiz=C7% zMBRrsz_<9YA!U~(?b*r3NwxwF({}}o2K;eo_wVv0Q}f3!^h6C;y*zYr^1+0lv!?3Z zo@Y)?2MTphojJDBM#z-UUlMK;9;;Nf(I;w>htHc{t$OF++BWD%XE)q@yS(+KR}Fk#lAm#0t+Pvh8m#T<6}L;aU~z0%+-!uZHSZ}8Jx|@ ziTqP2T3^%mw5g>xprg+edx^Ps_rNE@aeP-m`HHKY$p6jFv9EP^G*|Q~rXvI^ME5dR zMlgO8$|UiBqr>HglY%;Bcx@(nKi%cOf0_Qihlp;#yP zAJYL-vNl^8{=%Irw?ic-9u8mF)?bE9#|YaB6g|azz?XJNh%KgvVZd z