DamageTest.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. using Content.Shared.Damage;
  2. using Content.Shared.Damage.Prototypes;
  3. using NUnit.Framework;
  4. using Robust.Shared.IoC;
  5. using Robust.Shared.Prototypes;
  6. using Robust.Shared.Serialization.Manager;
  7. using System.Collections.Generic;
  8. using Content.Shared.FixedPoint;
  9. namespace Content.Tests.Shared
  10. {
  11. // Basic tests of various damage prototypes and classes.
  12. [TestFixture]
  13. [TestOf(typeof(DamageSpecifier))]
  14. [TestOf(typeof(DamageModifierSetPrototype))]
  15. [TestOf(typeof(DamageGroupPrototype))]
  16. public sealed class DamageTest : ContentUnitTest
  17. {
  18. private static Dictionary<string, float> _resistanceCoefficientDict = new()
  19. {
  20. // "missing" blunt entry
  21. { "Piercing", -2 },// Turn Piercing into Healing
  22. { "Slash", 3 },
  23. { "Radiation", 1.5f },
  24. };
  25. private static Dictionary<string, float> _resistanceReductionDict = new()
  26. {
  27. { "Blunt", - 5 },
  28. // "missing" piercing entry
  29. { "Slash", 8 },
  30. { "Radiation", 0.5f }, // Fractional adjustment
  31. };
  32. private IPrototypeManager _prototypeManager;
  33. private DamageSpecifier _damageSpec;
  34. [OneTimeSetUp]
  35. public void OneTimeSetup()
  36. {
  37. IoCManager.Resolve<ISerializationManager>().Initialize();
  38. _prototypeManager = IoCManager.Resolve<IPrototypeManager>();
  39. _prototypeManager.Initialize();
  40. _prototypeManager.LoadString(_damagePrototypes);
  41. _prototypeManager.ResolveResults();
  42. // Create a damage data set
  43. _damageSpec = new(_prototypeManager.Index<DamageGroupPrototype>("Brute"), 6);
  44. _damageSpec += new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>("Radiation"), 3);
  45. _damageSpec += new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>("Slash"), -1); // already exists in brute
  46. }
  47. //Check that DamageSpecifier will split groups and can do arithmetic operations
  48. [Test]
  49. public void DamageSpecifierTest()
  50. {
  51. // Create a copy of the damage data
  52. DamageSpecifier damageSpec = new(_damageSpec);
  53. // Check that it properly split up the groups into types
  54. FixedPoint2 damage;
  55. Assert.That(damageSpec.GetTotal(), Is.EqualTo(FixedPoint2.New(8)));
  56. Assert.That(damageSpec.DamageDict.TryGetValue("Blunt", out damage));
  57. Assert.That(damage, Is.EqualTo(FixedPoint2.New(2)));
  58. Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage));
  59. Assert.That(damage, Is.EqualTo(FixedPoint2.New(2)));
  60. Assert.That(damageSpec.DamageDict.TryGetValue("Slash", out damage));
  61. Assert.That(damage, Is.EqualTo(FixedPoint2.New(1)));
  62. Assert.That(damageSpec.DamageDict.TryGetValue("Radiation", out damage));
  63. Assert.That(damage, Is.EqualTo(FixedPoint2.New(3)));
  64. // check that integer multiplication works
  65. damageSpec = damageSpec * 2;
  66. Assert.That(damageSpec.GetTotal(), Is.EqualTo(FixedPoint2.New(16)));
  67. Assert.That(damageSpec.DamageDict.TryGetValue("Blunt", out damage));
  68. Assert.That(damage, Is.EqualTo(FixedPoint2.New(4)));
  69. Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage));
  70. Assert.That(damage, Is.EqualTo(FixedPoint2.New(4)));
  71. Assert.That(damageSpec.DamageDict.TryGetValue("Slash", out damage));
  72. Assert.That(damage, Is.EqualTo(FixedPoint2.New(2)));
  73. Assert.That(damageSpec.DamageDict.TryGetValue("Radiation", out damage));
  74. Assert.That(damage, Is.EqualTo(FixedPoint2.New(6)));
  75. // check that float multiplication works
  76. damageSpec = damageSpec * 2.2f;
  77. Assert.That(damageSpec.DamageDict.TryGetValue("Blunt", out damage));
  78. Assert.That(damage, Is.EqualTo(FixedPoint2.New(8.8)));
  79. Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage));
  80. Assert.That(damage, Is.EqualTo(FixedPoint2.New(8.8)));
  81. Assert.That(damageSpec.DamageDict.TryGetValue("Slash", out damage));
  82. Assert.That(damage, Is.EqualTo(FixedPoint2.New(4.4)));
  83. Assert.That(damageSpec.DamageDict.TryGetValue("Radiation", out damage));
  84. Assert.That(damage, Is.EqualTo(FixedPoint2.New(13.2)));
  85. Assert.That(damageSpec.GetTotal(), Is.EqualTo(FixedPoint2.New(8.8 + 8.8 + 4.4 + 13.2)));
  86. // check that integer division works
  87. damageSpec = damageSpec / 2;
  88. Assert.That(damageSpec.DamageDict.TryGetValue("Blunt", out damage));
  89. Assert.That(damage, Is.EqualTo(FixedPoint2.New(4.4)));
  90. Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage));
  91. Assert.That(damage, Is.EqualTo(FixedPoint2.New(4.4)));
  92. Assert.That(damageSpec.DamageDict.TryGetValue("Slash", out damage));
  93. Assert.That(damage, Is.EqualTo(FixedPoint2.New(2.2)));
  94. Assert.That(damageSpec.DamageDict.TryGetValue("Radiation", out damage));
  95. Assert.That(damage, Is.EqualTo(FixedPoint2.New(6.6)));
  96. // check that float division works
  97. damageSpec = damageSpec / 2.2f;
  98. Assert.That(damageSpec.DamageDict.TryGetValue("Blunt", out damage));
  99. Assert.That(damage, Is.EqualTo(FixedPoint2.New(2)));
  100. Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage));
  101. Assert.That(damage, Is.EqualTo(FixedPoint2.New(2)));
  102. Assert.That(damageSpec.DamageDict.TryGetValue("Slash", out damage));
  103. Assert.That(damage, Is.EqualTo(FixedPoint2.New(1)));
  104. Assert.That(damageSpec.DamageDict.TryGetValue("Radiation", out damage));
  105. Assert.That(damage, Is.EqualTo(FixedPoint2.New(3)));
  106. // Lets also test the constructor with damage types and damage groups works properly.
  107. damageSpec = new(_prototypeManager.Index<DamageGroupPrototype>("Brute"), 4);
  108. Assert.That(damageSpec.DamageDict.TryGetValue("Blunt", out damage));
  109. Assert.That(damage, Is.EqualTo(FixedPoint2.New(1.33)));
  110. Assert.That(damageSpec.DamageDict.TryGetValue("Slash", out damage));
  111. Assert.That(damage, Is.EqualTo(FixedPoint2.New(1.33)));
  112. Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage));
  113. Assert.That(damage, Is.EqualTo(FixedPoint2.New(1.34))); // doesn't divide evenly, so the 0.01 goes to the last one
  114. damageSpec = new(_prototypeManager.Index<DamageTypePrototype>("Piercing"), 4);
  115. Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage));
  116. Assert.That(damage, Is.EqualTo(FixedPoint2.New(4)));
  117. }
  118. //Check that DamageSpecifier will be properly adjusted by a resistance set
  119. [Test]
  120. public void ModifierSetTest()
  121. {
  122. // Create a copy of the damage data
  123. DamageSpecifier damageSpec = 10 * new DamageSpecifier(_damageSpec);
  124. // Create a modifier set
  125. DamageModifierSetPrototype modifierSet = new()
  126. {
  127. Coefficients = _resistanceCoefficientDict,
  128. FlatReduction = _resistanceReductionDict
  129. };
  130. //damage is initially 20 / 20 / 10 / 30
  131. //Each time we subtract -5 / 0 / 8 / 0.5
  132. //then multiply by 1 / -2 / 3 / 1.5
  133. // Apply once
  134. damageSpec = DamageSpecifier.ApplyModifierSet(damageSpec, modifierSet);
  135. Assert.That(damageSpec.DamageDict["Blunt"], Is.EqualTo(FixedPoint2.New(25)));
  136. Assert.That(damageSpec.DamageDict["Piercing"], Is.EqualTo(FixedPoint2.New(-40))); // became healing
  137. Assert.That(damageSpec.DamageDict["Slash"], Is.EqualTo(FixedPoint2.New(6)));
  138. Assert.That(damageSpec.DamageDict["Radiation"], Is.EqualTo(FixedPoint2.New(44.25)));
  139. // And again, checking for some other behavior
  140. damageSpec = DamageSpecifier.ApplyModifierSet(damageSpec, modifierSet);
  141. Assert.That(damageSpec.DamageDict["Blunt"], Is.EqualTo(FixedPoint2.New(30)));
  142. Assert.That(damageSpec.DamageDict["Piercing"], Is.EqualTo(FixedPoint2.New(-40))); // resistances don't apply to healing
  143. Assert.That(!damageSpec.DamageDict.ContainsKey("Slash")); // Reduction reduced to 0, and removed from specifier
  144. Assert.That(damageSpec.DamageDict["Radiation"], Is.EqualTo(FixedPoint2.New(65.62)));
  145. }
  146. // Default damage Yaml
  147. private string _damagePrototypes = @"
  148. - type: damageType
  149. id: Blunt
  150. name: damage-type-blunt
  151. - type: damageType
  152. id: Slash
  153. name: damage-type-slash
  154. - type: damageType
  155. id: Piercing
  156. name: damage-type-piercing
  157. - type: damageType
  158. id: TestArrow
  159. name: damage-type-arrow
  160. - type: damageType
  161. id: Heat
  162. name: damage-type-heat
  163. - type: damageType
  164. id: Shock
  165. name: damage-type-shock
  166. - type: damageType
  167. id: Cold
  168. name: damage-type-cold
  169. # Poison damage. Generally caused by various reagents being metabolised.
  170. - type: damageType
  171. id: Poison
  172. name: damage-type-poison
  173. - type: damageType
  174. id: Radiation
  175. name: damage-type-radiation
  176. # Damage due to being unable to breathe.
  177. # Represents not enough oxygen (or equivalent) getting to the blood.
  178. # Usually healed automatically if entity can breathe
  179. - type: damageType
  180. id: Asphyxiation
  181. name: damage-type-asphyxiation
  182. # Damage representing not having enough blood.
  183. # Represents there not enough blood to supply oxygen (or equivalent).
  184. - type: damageType
  185. id: Bloodloss
  186. name: damage-type-bloodloss
  187. - type: damageType
  188. id: Cellular
  189. name: damage-type-cellular
  190. - type: damageGroup
  191. id: Brute
  192. name: damage-group-brute
  193. damageTypes:
  194. - Blunt
  195. - Slash
  196. - Piercing
  197. - type: damageGroup
  198. id: Burn
  199. name: damage-group-burn
  200. damageTypes:
  201. - Heat
  202. - Shock
  203. - Cold
  204. # Airloss (sometimes called oxyloss)
  205. # Caused by asphyxiation or bloodloss.
  206. # Note that most medicine and damaging effects should probably modify either asphyxiation or
  207. # bloodloss, not this whole group, unless you have a wonder drug that affects both.
  208. - type: damageGroup
  209. id: Airloss
  210. name: damage-group-airloss
  211. damageTypes:
  212. - Asphyxiation
  213. - Bloodloss
  214. # As with airloss, most medicine and damage effects should probably modify either poison or radiation.
  215. # Though there are probably some radioactive poisons.
  216. - type: damageGroup
  217. id: Toxin
  218. name: damage-group-toxin
  219. damageTypes:
  220. - Poison
  221. - Radiation
  222. - type: damageGroup
  223. id: Genetic
  224. name: damage-group-genetic
  225. damageTypes:
  226. - Cellular
  227. - type: damageModifierSet
  228. id: Metallic
  229. coefficients:
  230. Blunt: 0.7
  231. Slash: 0.5
  232. Piercing: 0.7
  233. Shock: 1.2
  234. flatReductions:
  235. Blunt: 5
  236. - type: damageModifierSet
  237. id: Inflatable
  238. coefficients:
  239. Blunt: 0.5
  240. Piercing: 2.0
  241. Heat: 0.5
  242. Shock: 0
  243. flatReductions:
  244. Blunt: 5
  245. - type: damageModifierSet
  246. id: Glass
  247. coefficients:
  248. Blunt: 0.5
  249. Slash: 0.5
  250. Piercing: 0.5
  251. Heat: 0
  252. Shock: 0
  253. flatReductions:
  254. Blunt: 5
  255. - type: damageContainer
  256. id: Biological
  257. supportedGroups:
  258. - Brute
  259. - Burn
  260. - Toxin
  261. - Airloss
  262. - Genetic
  263. - type: damageContainer
  264. id: Inorganic
  265. supportedGroups:
  266. - Brute
  267. supportedTypes:
  268. - Heat
  269. - Shock
  270. ";
  271. }
  272. }