Exemplo n.º 1
0
        public void AdvancedLadderIsFastWhenMaxNumberOfLadderImplantsButVeryHighStartingStats()
        {
            _character = new Character(
                agilityValue: 500, intelligenceValue: 500, psychicValue: 500,
                senseValue: 500, staminaValue: 500, strengthValue: 500, treatmentValue: 1000);

            _finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.TimeAndSpace, Skill.NanoPool, Ability.Sense),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Eye, Skill.AimedShot, Skill.Treatment, Skill.TimeAndSpace),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Ear, null, Skill.Concealment, Ability.Intelligence),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Chest, Ability.Stamina, Skill.BioMetamor, Skill.SensoryImpr),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Ability.Strength, null, null),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftArm, null, Ability.Strength, null),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Waist, ArmorClass.FireAC, MaxHealthOrNano.MaxHealth, Ability.Stamina),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightWrist, Skill.RunSpeed, Skill.NanoResist, Skill.MultMelee),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.RunSpeed, Skill.NanoResist),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Leg, Ability.Agility, Skill.EvadeClsC, ArmorClass.MeleeMaAC),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightHand, Skill.MartialArts, Skill.TimeAndSpace, Skill.Treatment),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftHand, null, ArmorClass.FireAC, Skill.MartialArts),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Feet, Skill.EvadeClsC, Ability.Agility, Skill.DuckExp),
            };
            Assert.AreEqual(10, _finalImplantTemplates.Count(t => t.RaisesLadderStats));

            var ladderProcess = new AdvancedLadderProcess(_character, _finalImplantTemplates);

            Assert.AreEqual(200, ladderProcess.AverageFinalImplantQL);
        }
        public void DegenerateLadderProcessWhenNoFinalLadderImplants()
        {
            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.MatterCrea, Skill.NanoPool, Skill.Tutoring),                      // Intelligence
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.RunSpeed, Skill.NanoResist),                // Agility
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Skill.OneHandBlunt, ArmorClass.ChemicalAC, ArmorClass.RadiationAC), // Strength
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Waist, ArmorClass.ChemicalAC, MaxHealthOrNano.MaxNano, Skill.BioMetamor)      // Sense
            };

            var ladderProcess = new DegenerateLadderProcess(_character, finalImplantTemplates);

            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Intelligence), _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[0]).QL);
            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Agility), _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[1]).QL);
            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Strength), _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[2]).QL);
            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Sense), _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[3]).QL);

            // Implants should be unequipped right now and stats should be the same as they were before laddering.
            Assert.AreEqual(0, _character.GetAverageImplantQL());
            Assert.AreEqual(0, _character.GetTotalImplantQL());
            Assert.AreEqual(91, _character.GetAbilityValue(Ability.Agility));
            Assert.AreEqual(91, _character.GetAbilityValue(Ability.Stamina));
            Assert.AreEqual(281.4, _character.TreatmentValue);
        }
Exemplo n.º 3
0
        public void AllLadderProcessesAreEquivalentWhenNoLadderSlotsAreAvailable()
        {
            var character = new Character(
                agilityValue: 281, intelligenceValue: 315, psychicValue: 305,
                senseValue: 213, staminaValue: 301, strengthValue: 316, treatmentValue: 662.6250);
            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightWrist, Skill.RunSpeed, Skill.NanoResist, Skill.MultMelee),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.RunSpeed, Skill.NanoResist),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftHand, null, ArmorClass.FireAC, Skill.MartialArts),
            };

            var degenerateLadderProcess = new DegenerateLadderProcess(character, finalImplantTemplates);
            var basicLadderProcess      = new BasicLadderProcess(character, finalImplantTemplates,
                                                                 unavailableImplantSlots: ImplantSlot.LadderImplantSlots);
            var advancedLadderProcess = new AdvancedLadderProcess(character, finalImplantTemplates,
                                                                  unavailableImplantSlots: ImplantSlot.LadderImplantSlots);

            CollectionAssert.AreEquivalent(
                degenerateLadderProcess.OrderedFinalImplants.ToArray(),
                basicLadderProcess.OrderedFinalImplants.ToArray());
            CollectionAssert.AreEquivalent(
                basicLadderProcess.OrderedFinalImplants.ToArray(),
                advancedLadderProcess.OrderedFinalImplants.ToArray());
            CollectionAssert.AreEquivalent(
                degenerateLadderProcess.OrderedLadderImplants.ToArray(),
                basicLadderProcess.OrderedLadderImplants.ToArray());
            CollectionAssert.AreEquivalent(
                basicLadderProcess.OrderedLadderImplants.ToArray(),
                advancedLadderProcess.OrderedLadderImplants.ToArray());
            Assert.AreEqual(138, degenerateLadderProcess.AverageFinalImplantQL);
            Assert.AreEqual(138, basicLadderProcess.AverageFinalImplantQL);
            Assert.AreEqual(138, advancedLadderProcess.AverageFinalImplantQL);
        }
Exemplo n.º 4
0
        public string GetLabel()
        {
            ImplantTemplate template = CreateImplantTemplate();

            if (template == null)
            {
                return(Slot.ShortName);
            }

            return($"{template.RequiredAbility.ShortName} {Slot.ShortName}");
        }
Exemplo n.º 5
0
        public ImplantTemplate CreateImplantTemplate()
        {
            shinyClusterHash.TryGetValue(ShinyClusterSelection ?? string.Empty, out ShinyClusterTemplate shinyCluster);
            brightClusterHash.TryGetValue(BrightClusterSelection ?? string.Empty, out BrightClusterTemplate brightCluster);
            fadedClusterHash.TryGetValue(FadedClusterSelection ?? string.Empty, out FadedClusterTemplate fadedCluster);
            if (shinyCluster == null && brightCluster == null && fadedCluster == null)
            {
                return(null);
            }

            return(ImplantTemplate.GetImplantTemplate(Slot, shinyCluster?.Stat, brightCluster?.Stat, fadedCluster?.Stat));
        }
Exemplo n.º 6
0
        public async Task <IActionResult> Create(ImplantTemplate template)
        {
            try
            {
                await _context.CreateImplantTemplate(template);

                return(RedirectToAction(nameof(Index)));
            }
            catch (Exception e) when(e is ControllerNotFoundException || e is ControllerBadRequestException || e is ControllerUnauthorizedException)
            {
                return(RedirectToAction(nameof(Index)));
            }
        }
 public async Task <ActionResult <ImplantTemplate> > EditImplantTemplate([FromBody] ImplantTemplate template)
 {
     try
     {
         return(await _service.EditImplantTemplate(template));
     }
     catch (ControllerNotFoundException e)
     {
         return(NotFound(e.Message));
     }
     catch (ControllerBadRequestException e)
     {
         return(BadRequest(e.Message));
     }
 }
Exemplo n.º 8
0
        public void BasicLadderProcessIsAtLeastAsGoodAsOldApplicationWhenNoInitialLimitingFactor()
        {
            // There's no limiting factor here, they have the exact stats required to equip a QL 100 left-arm.
            _character = new Character(
                agilityValue: 204, intelligenceValue: 204, psychicValue: 204,
                senseValue: 204, staminaValue: 204, strengthValue: 204, treatmentValue: 479);
            _finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftArm, Skill.Brawling, Skill.TwoHandBlunt, ArmorClass.ChemicalAC)
            };

            var ladderProcess = new BasicLadderProcess(_character, _finalImplantTemplates);

            Assert.IsTrue(121 <= ladderProcess.AverageFinalImplantQL);
        }
Exemplo n.º 9
0
        public void AdvancedLadderUsesOneLadderImplantWhenTheresOnlyOneAvailable()
        {
            _finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightWrist, Skill.RunSpeed, Skill.NanoResist, Skill.MultMelee),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.RunSpeed, Skill.NanoResist),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftHand, null, ArmorClass.FireAC, Skill.MartialArts),
            };

            var advancedLadderProcess = new AdvancedLadderProcess(_character, _finalImplantTemplates,
                                                                  unavailableImplantSlots: ImplantSlot.LadderImplantSlots.Where(s => s != ImplantSlot.RightHand));

            Assert.AreEqual(ImplantSlot.RightHand, advancedLadderProcess.OrderedLadderImplants.Single().ImplantSlot);
            Assert.IsTrue(advancedLadderProcess.AverageFinalImplantQL > 138);
        }
        public void DegenerateLadderProcessWhenASingleFinalLadderImplant()
        {
            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.QuantumFT, null, Skill.Tutoring),                                 // Agility
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.RunSpeed, Skill.NanoResist),                // Agility
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Skill.OneHandBlunt, ArmorClass.ChemicalAC, ArmorClass.RadiationAC), // Strength
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Leg, Ability.Agility, Ability.Stamina, null),                                 // Stamina
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Waist, ArmorClass.ChemicalAC, null, Skill.BioMetamor)                         // Stamina
            };

            var ladderProcess = new DegenerateLadderProcess(_character, finalImplantTemplates);

            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Stamina), _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants[0].QL);
            Assert.AreEqual(finalImplantTemplates[3], ladderProcess.OrderedFinalImplants[0].ImplantTemplate);
            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Agility) + ladderProcess.OrderedFinalImplants[0].ShinyStatIncrease.Value, _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[0]).QL);
            Assert.AreEqual(51, ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[0]).QL);
            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Agility) + ladderProcess.OrderedFinalImplants[0].ShinyStatIncrease.Value, _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[1]).QL);
            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Strength), _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[2]).QL);
            Assert.AreEqual(
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Stamina) + ladderProcess.OrderedFinalImplants[0].ShinyStatIncrease.Value, _character.TreatmentValue),
                Implant.GetMaxImplantQL(_character.GetAbilityValue(Ability.Sense), _character.TreatmentValue),
                ladderProcess.OrderedFinalImplants.Single(i => i.ImplantTemplate == finalImplantTemplates[4]).QL);

            // Implants should be unequipped right now and stats should be the same as they were before laddering.
            Assert.AreEqual(0, _character.GetAverageImplantQL());
            Assert.AreEqual(0, _character.GetTotalImplantQL());
            Assert.AreEqual(91, _character.GetAbilityValue(Ability.Agility));
            Assert.AreEqual(91, _character.GetAbilityValue(Ability.Stamina));
            Assert.AreEqual(281.4, _character.TreatmentValue);

            // Using the order the ladder process outlines, all equips should be possible and maximal.
            foreach (var finalImplant in ladderProcess.OrderedFinalImplants)
            {
                Assert.IsTrue(_character.CanEquipImplant(finalImplant));
                var maxImplant = _character.EquipMaxImplant(finalImplant.ImplantTemplate);
                Assert.AreEqual(maxImplant, finalImplant);
            }
        }
        public void DegenerateLadderProcessWhenManyFinalLadderImplants()
        {
            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.Treatment, null, Ability.Sense),              // Agility
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Chest, Ability.Sense, Ability.Psychic, Ability.Strength), // Psychic
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Ability.Strength, null, null),                  // Sense
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Leg, Ability.Agility, Ability.Stamina, null),             // Stamina
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Waist, null, Ability.Sense, Ability.Stamina),             // Psychic
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Eye, null, Skill.Treatment, null),                        // Agility
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightHand, null, null, Skill.Treatment),                  // Intelligence
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Feet, null, Ability.Agility, null),                       // Agility
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Ear, null, null, Ability.Intelligence)                    // Psychic
            };

            var ladderProcess = new DegenerateLadderProcess(_character, finalImplantTemplates);

            // Implants should be unequipped right now and stats should be the same as they were before laddering.
            Assert.AreEqual(0, _character.GetAverageImplantQL());
            Assert.AreEqual(0, _character.GetTotalImplantQL());
            Assert.AreEqual(91, _character.GetAbilityValue(Ability.Agility));
            Assert.AreEqual(91, _character.GetAbilityValue(Ability.Stamina));
            Assert.AreEqual(281.4, _character.TreatmentValue);

            // The final QL should be greater than what we get by w/o any laddered equips.
            int unladderedTotalImplantQL = 0;

            foreach (var implantTemplate in finalImplantTemplates)
            {
                unladderedTotalImplantQL += _character.GetMaxImplant(implantTemplate).QL;
            }
            Assert.IsTrue(unladderedTotalImplantQL < ladderProcess.TotalFinalImplantQL);

            // The final QL should be greater than what we get by laddering in the arbitrary order declared above.
            foreach (var implantTemplate in finalImplantTemplates)
            {
                _character.EquipMaxImplant(implantTemplate);
            }
            Assert.IsTrue(unladderedTotalImplantQL < _character.GetTotalImplantQL());
            Assert.IsTrue(_character.GetTotalImplantQL() < ladderProcess.TotalFinalImplantQL);

            Assert.AreEqual(0, ladderProcess.OrderedLadderImplants.Count);

            // Some regression tests, I don't know for sure that 480 is what to expect, hopefully won't ever drop below this.
            Assert.AreEqual(480, ladderProcess.TotalFinalImplantQL);
            Assert.AreEqual(480 / (double)9, ladderProcess.AverageFinalImplantQL);
        }
        public void EquipsAndVerifiesSomeMaxImplants()
        {
            Assert.AreEqual(0, _character.GetTotalImplantQL());
            Assert.AreEqual(0, _character.GetAverageImplantQL());

            var maxHead = _character.EquipMaxImplant(ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.Treatment, null, Ability.Sense));

            Assert.AreEqual(43, maxHead.QL);
            Assert.AreEqual(308.7, _character.TreatmentValue);
            Assert.AreEqual(100, _character.GetAbilityValue(Ability.Sense));
            Assert.AreEqual(91, _character.GetAbilityValue(Ability.Strength));
            Assert.AreEqual(43, _character.GetTotalImplantQL());
            Assert.AreEqual(43, _character.GetAverageImplantQL());

            var maxRightArm1 = _character.EquipMaxImplant(ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Ability.Strength, Skill.Brawling, null));

            Assert.AreEqual(43, maxRightArm1.QL);
            Assert.AreEqual(308.7, _character.TreatmentValue);
            Assert.AreEqual(100, _character.GetAbilityValue(Ability.Sense));
            Assert.AreEqual(107, _character.GetAbilityValue(Ability.Strength));

            var maxLeftArm = _character.EquipMaxImplant(ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftArm, Skill.Brawling, Ability.Strength, ArmorClass.ChemicalAC));

            Assert.AreEqual(51, maxLeftArm.QL);
            Assert.AreEqual(308.7, _character.TreatmentValue);
            Assert.AreEqual(100, _character.GetAbilityValue(Ability.Sense));
            Assert.AreEqual(118, _character.GetAbilityValue(Ability.Strength));

            var maxRightArm2 = _character.EquipMaxImplant(ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Ability.Strength, Skill.Brawling, null));

            Assert.AreEqual(49, maxRightArm2.QL);
            Assert.AreEqual(308.7, _character.TreatmentValue);
            Assert.AreEqual(100, _character.GetAbilityValue(Ability.Sense));
            Assert.AreEqual(119, _character.GetAbilityValue(Ability.Strength));

            var maxLeg = _character.EquipMaxImplant(ImplantTemplate.GetImplantTemplate(ImplantSlot.Leg, Ability.Agility, Ability.Stamina, null));

            Assert.AreEqual(43, maxLeg.QL);
            Assert.AreEqual(309.9, _character.TreatmentValue);
            Assert.AreEqual(100, _character.GetAbilityValue(Ability.Sense));
            Assert.AreEqual(119, _character.GetAbilityValue(Ability.Strength));
            Assert.AreEqual(107, _character.GetAbilityValue(Ability.Agility));
            Assert.AreEqual(100, _character.GetAbilityValue(Ability.Stamina));
            Assert.AreEqual(186, _character.GetTotalImplantQL());
            Assert.AreEqual(46.5, _character.GetAverageImplantQL());
        }
        public async Task <ActionResult <ImplantTemplate> > CreateImplantTemplate([FromBody] ImplantTemplate template)
        {
            try
            {
                ImplantTemplate createdTemplate = await _service.CreateImplantTemplate(template);

                return(CreatedAtRoute(nameof(GetImplantTemplate), new { id = createdTemplate.Id }, createdTemplate));
            }
            catch (ControllerNotFoundException e)
            {
                return(NotFound(e.Message));
            }
            catch (ControllerBadRequestException e)
            {
                return(BadRequest(e.Message));
            }
        }
        public void VerifiesAOIDsAndRequiredAbilities()
        {
            var waist = ImplantTemplate.GetImplantTemplate(ImplantSlot.Waist, ArmorClass.ColdAC, Skill.BodyDev, Skill.EvadeClsC);

            Assert.AreEqual(111104, waist.AOID);
            Assert.AreEqual(Ability.Stamina, waist.RequiredAbility);

            var leftWrist = ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.Parry, Skill.NanoResist);

            Assert.AreEqual(111199, leftWrist.AOID);
            Assert.AreEqual(Ability.Agility, leftWrist.RequiredAbility);

            var rightHand = ImplantTemplate.GetImplantTemplate(ImplantSlot.RightHand, Skill.MartialArts, Skill.SharpObj, Skill.OneHandBlunt);

            Assert.AreEqual(111688, rightHand.AOID);
            Assert.AreEqual(Ability.Agility, rightHand.RequiredAbility);
        }
Exemplo n.º 15
0
        public async Task <ActionResult> PostStage2(Grunt egressGrunt, Grunt targetGrunt, ModelUtilities.GruntEncryptedMessage gruntStage2Response)
        {
            if (targetGrunt == null || targetGrunt.Status != GruntStatus.Stage1 || !gruntStage2Response.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey)))
            {
                // Always return NotFound, don't give away unnecessary info
                return(NotFound());
            }
            if (egressGrunt == null)
            {
                egressGrunt = targetGrunt;
            }
            byte[] challenge2test = _utilities.GruntSessionDecrypt(targetGrunt, gruntStage2Response);
            if (targetGrunt.GruntChallenge != Convert.ToBase64String(challenge2test))
            {
                // Always return NotFound, don't give away unnecessary info
                return(NotFound());
            }
            targetGrunt.Status      = GruntStatus.Stage2;
            targetGrunt.LastCheckIn = DateTime.UtcNow;
            await _client.ApiGruntsPutAsync(targetGrunt);

            ImplantTemplate template = await this._client.ApiImplanttemplatesGruntByIdGetAsync(targetGrunt.Id ?? default);

            string GruntExecutorAssembly = this._utilities.ListenerCompileGruntExecutorCode(_context.HttpListener.First(), targetGrunt, _context.HttpProfile.First(), template);

            ModelUtilities.GruntEncryptedMessage message;
            try
            {
                message = this.CreateMessageForGrunt(egressGrunt, targetGrunt, Convert.FromBase64String(GruntExecutorAssembly));
            }
            catch (HttpOperationException)
            {
                return(NotFound());
            }

            // Transform response
            string transformed = this._utilities.ProfileTransform(_context.HttpProfile.First(), Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message)));
            // Format transformed response
            string response = String.Format(_context.HttpProfile.First().HttpPostResponse, transformed);

            // returns: "Base64(IV),Base64(AES(GruntExecutorAssembly)),Base64(HMAC)"
            return(Ok(response));
        }
Exemplo n.º 16
0
 public void Initialize()
 {
     _character = new Character(
         agilityValue: 281, intelligenceValue: 315, psychicValue: 305,
         senseValue: 213, staminaValue: 301, strengthValue: 316, treatmentValue: 662.6250);
     _finalImplantTemplates = new[]
     {
         ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.BioMetamor, Skill.NanoPool, Ability.Sense),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.Eye, Skill.AimedShot, Skill.SensoryImpr, Skill.TimeAndSpace),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.Ear, null, Skill.Concealment, Skill.PsychoModi),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.Chest, Skill.BodyDev, Skill.BioMetamor, Skill.SensoryImpr),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.Waist, ArmorClass.FireAC, ArmorClass.MeleeMaAC, Skill.EvadeClsC),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.RightWrist, Skill.RunSpeed, Skill.NanoResist, Skill.MultMelee),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.RunSpeed, Skill.NanoResist),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.Leg, Ability.Agility, Skill.EvadeClsC, ArmorClass.MeleeMaAC),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.RightHand, Skill.MartialArts, Skill.TimeAndSpace, Skill.Treatment),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftHand, null, ArmorClass.FireAC, Skill.MartialArts),
         ImplantTemplate.GetImplantTemplate(ImplantSlot.Feet, Skill.EvadeClsC, Skill.MartialArts, Skill.DuckExp),
     };
 }
Exemplo n.º 17
0
 public string CompileGruntStagerCode(Grunt grunt, HttpProfile profile, ImplantTemplate template, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary, bool Compress = false)
 {
     byte[] ILBytes = Compiler.Compile(new Compiler.CompilationRequest
     {
         Language            = grunt.Language,
         Source              = this.GetGruntStagerCode(grunt, profile, template),
         TargetDotNetVersion = grunt.DotNetFrameworkVersion,
         OutputKind          = outputKind,
         References          = grunt.DotNetFrameworkVersion == Common.DotNetVersion.Net35 ? Common.DefaultNet35References : Common.DefaultNet40References
     });
     if (ILBytes == null || ILBytes.Length == 0)
     {
         throw new CovenantCompileGruntStagerFailedException("Compiling Grunt code failed");
     }
     if (Compress)
     {
         ILBytes = Utilities.Compress(ILBytes);
     }
     return(Convert.ToBase64String(ILBytes));
 }
        public void DegenerateLadderProcessEquipsImplantsInTheProperThreePhases()
        {
            // The three phases are
            //  1. the final ladder implants in initially empty slots,
            //  2. the final non-ladder implants in initially empty slots,
            //  3. the final implants in initially full slots.

            var alreadyEquippedImplants = new[]
            {
                Implant.GetImplant(ImplantSlot.Head, Skill.Treatment, null, Ability.Sense, 200),
                Implant.GetImplant(ImplantSlot.Leg, Ability.Agility, Ability.Stamina, null, 200),
                Implant.GetImplant(ImplantSlot.Ear, Skill.Perception, null, Ability.Intelligence, 200)
            };

            _character.SetImplants(alreadyEquippedImplants);

            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Chest, Ability.Sense, Ability.Psychic, Ability.Strength), // 1
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Skill.Burst, null, null),                       // 2
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.Treatment, null, null),                       // 3
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Eye, null, Skill.Treatment, null),                        // 1
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightHand, null, null, Skill.Grenade),                    // 2
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftArm, Skill.Brawling, null, null),                     // 2
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Feet, null, Ability.Agility, null),                       // 1
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Ear, null, null, Skill.PsychoModi)                        // 3
            };

            var ladderProcess = new DegenerateLadderProcess(_character, finalImplantTemplates);

            CollectionAssert.AreEquivalent(
                new[] { finalImplantTemplates[0], finalImplantTemplates[3], finalImplantTemplates[6] },
                ladderProcess.OrderedFinalImplants.Take(3).Select(i => i.ImplantTemplate).ToArray());
            CollectionAssert.AreEquivalent(
                new[] { finalImplantTemplates[1], finalImplantTemplates[4], finalImplantTemplates[5] },
                ladderProcess.OrderedFinalImplants.Skip(3).Take(3).Select(i => i.ImplantTemplate).ToArray());
            CollectionAssert.AreEquivalent(
                new[] { finalImplantTemplates[2], finalImplantTemplates[7] },
                ladderProcess.OrderedFinalImplants.Skip(6).Take(2).Select(i => i.ImplantTemplate).ToArray());
        }
        public void DegenerateLadderDoesntTakeForeverEvenWhenHighNumberOfFinalImplantsAsLadderImplants()
        {
            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.TimeAndSpace, Skill.NanoPool, Ability.Sense),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Eye, Skill.AimedShot, Skill.Treatment, Skill.TimeAndSpace),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Ear, null, Skill.Concealment, Ability.Intelligence),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Chest, Ability.Stamina, Skill.BioMetamor, Skill.SensoryImpr),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Ability.Strength, null, null),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftArm, null, Ability.Strength, null),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Waist, ArmorClass.FireAC, MaxHealthOrNano.MaxHealth, Skill.EvadeClsC),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightWrist, Skill.RunSpeed, Skill.NanoResist, Skill.MultMelee),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.RunSpeed, Skill.NanoResist),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Leg, Ability.Agility, Skill.EvadeClsC, ArmorClass.MeleeMaAC),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightHand, Skill.MartialArts, Skill.TimeAndSpace, Skill.Treatment),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftHand, null, ArmorClass.FireAC, Skill.MartialArts),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Feet, Skill.EvadeClsC, Ability.Agility, Skill.DuckExp),
            };

            Assert.AreEqual(9, finalImplantTemplates.Count(t => t.RaisesLadderStats));

            var ladderProcess = new DegenerateLadderProcess(_character, finalImplantTemplates);
        }
        public void DegenerateLadderProcessUnequipsWeakLadderImplantsFirst()
        {
            // The head and ear are strong ladder implants and shouldn't be equipped before the weaker leg, eye, and feet.
            var alreadyEquippedImplants = new[]
            {
                Implant.GetImplant(ImplantSlot.Head, Skill.Treatment, null, Ability.Sense, 200),
                Implant.GetImplant(ImplantSlot.Leg, Ability.Agility, Ability.Stamina, null, 1),
                Implant.GetImplant(ImplantSlot.Ear, Skill.Perception, null, Ability.Intelligence, 200),
                Implant.GetImplant(ImplantSlot.Eye, null, Skill.Treatment, null, 1),
                Implant.GetImplant(ImplantSlot.Feet, null, Ability.Agility, null, 1)
            };

            _character.SetImplants(alreadyEquippedImplants);

            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Chest, Ability.Sense, Ability.Psychic, Ability.Strength), // 1
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Skill.Burst, null, null),                       // 2
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Head, Skill.Treatment, null, null),                       // 3
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Eye, null, Skill.Treatment, Skill.Bow),                   // 1
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightHand, null, null, Skill.Grenade),                    // 2
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftArm, Skill.Brawling, null, null),                     // 2
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Feet, null, Ability.Agility, null),                       // 1
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Ear, null, null, Skill.PsychoModi)                        // 3
            };

            var ladderProcess = new DegenerateLadderProcess(_character, finalImplantTemplates);

            var orderedFinalImplantSlots = ladderProcess.OrderedFinalImplants
                                           .Select(i => i.ImplantSlot)
                                           .ToArray();

            Assert.IsTrue(Array.IndexOf(orderedFinalImplantSlots, ImplantSlot.Head) > Array.IndexOf(orderedFinalImplantSlots, ImplantSlot.Eye));
            Assert.IsTrue(Array.IndexOf(orderedFinalImplantSlots, ImplantSlot.Head) > Array.IndexOf(orderedFinalImplantSlots, ImplantSlot.Feet));
            Assert.IsTrue(Array.IndexOf(orderedFinalImplantSlots, ImplantSlot.Ear) > Array.IndexOf(orderedFinalImplantSlots, ImplantSlot.Eye));
            Assert.IsTrue(Array.IndexOf(orderedFinalImplantSlots, ImplantSlot.Ear) > Array.IndexOf(orderedFinalImplantSlots, ImplantSlot.Feet));
        }
Exemplo n.º 21
0
        public void AllLadderProcessesAreEquivalentWhenTheOnlyLadderSlotsAvailableArentUseful()
        {
            var character = new Character(
                agilityValue: 281, intelligenceValue: 315, psychicValue: 305,
                senseValue: 213, staminaValue: 301, strengthValue: 380, treatmentValue: 662.6250);
            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightWrist, Skill.RunSpeed, Skill.NanoResist, Skill.MultMelee),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftWrist, Skill.MultMelee, Skill.RunSpeed, Skill.NanoResist),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftHand, null, ArmorClass.FireAC, Skill.MartialArts),
                ImplantTemplate.GetImplantTemplate(ImplantSlot.LeftArm, Skill.Brawling, Skill.TwoHandBlunt, null),
            };

            // Right-arm and left-arm can only buff strength, which doesn't trickle to treatment, so it's not useful.
            var unavailableImplantSlots = ImplantSlot.LadderImplantSlots
                                          .Where(s => s != ImplantSlot.RightArm && s != ImplantSlot.LeftArm);

            var degenerateLadderProcess = new DegenerateLadderProcess(character, finalImplantTemplates);
            var basicLadderProcess      = new BasicLadderProcess(character, finalImplantTemplates, unavailableImplantSlots);
            var advancedLadderProcess   = new AdvancedLadderProcess(character, finalImplantTemplates, unavailableImplantSlots);

            CollectionAssert.AreEquivalent(
                degenerateLadderProcess.OrderedFinalImplants.ToArray(),
                basicLadderProcess.OrderedFinalImplants.ToArray());
            CollectionAssert.AreEquivalent(
                basicLadderProcess.OrderedFinalImplants.ToArray(),
                advancedLadderProcess.OrderedFinalImplants.ToArray());
            CollectionAssert.AreEquivalent(
                degenerateLadderProcess.OrderedLadderImplants.ToArray(),
                basicLadderProcess.OrderedLadderImplants.ToArray());
            CollectionAssert.AreEquivalent(
                basicLadderProcess.OrderedLadderImplants.ToArray(),
                advancedLadderProcess.OrderedLadderImplants.ToArray());
            Assert.AreEqual(138, degenerateLadderProcess.AverageFinalImplantQL);
            Assert.AreEqual(138, basicLadderProcess.AverageFinalImplantQL);
            Assert.AreEqual(138, advancedLadderProcess.AverageFinalImplantQL);
        }
Exemplo n.º 22
0
 public static Implant GetImplant(ImplantSlot implantSlot, Stat shinyStat, Stat brightStat, Stat fadedStat, int implantQL)
 => new Implant(ImplantTemplate.GetImplantTemplate(implantSlot, shinyStat, brightStat, fadedStat), implantQL);
Exemplo n.º 23
0
        public override string GetLauncher(string StagerCode, byte[] StagerAssembly, Grunt grunt, ImplantTemplate template)
        {
            this.StagerCode         = StagerCode;
            this.Base64ILByteString = Convert.ToBase64String(StagerAssembly);
            string code = CodeTemplate.Replace("{{GRUNT_IL_BYTE_STRING}}", this.Base64ILByteString);

            List <Compiler.Reference> references = grunt.DotNetFrameworkVersion == Common.DotNetVersion.Net35 ? Common.DefaultNet35References : Common.DefaultNet40References;

            references.Add(new Compiler.Reference
            {
                File = grunt.DotNetFrameworkVersion == Common.DotNetVersion.Net35 ? Common.CovenantAssemblyReferenceNet35Directory + "System.Configuration.Install.dll" :
                       Common.CovenantAssemblyReferenceNet40Directory + "System.Configuration.Install.dll",
                Framework = grunt.DotNetFrameworkVersion,
                Enabled   = true
            });
            this.DiskCode = Convert.ToBase64String(Compiler.Compile(new Compiler.CompilationRequest
            {
                Language            = template.Language,
                Source              = code,
                TargetDotNetVersion = grunt.DotNetFrameworkVersion,
                OutputKind          = OutputKind.DynamicallyLinkedLibrary,
                References          = references
            }));

            this.LauncherString = "InstallUtil.exe" + " " + "/U" + " " + "file.dll";
            return(this.LauncherString);
        }
        public void DegenerateLadderProcessLeavesAlreadyEquippedImplantsAlone()
        {
            var alreadyEquippedImplants = new[]
            {
                Implant.GetImplant(ImplantSlot.Head, Skill.Treatment, null, Ability.Sense, 200),
                Implant.GetImplant(ImplantSlot.Leg, Ability.Agility, Ability.Stamina, null, 200)
            };

            _character.SetImplants(alreadyEquippedImplants);
            Assert.AreEqual(146, _character.GetAbilityValue(Ability.Agility));
            Assert.AreEqual(124, _character.GetAbilityValue(Ability.Stamina));
            Assert.AreEqual(116, _character.GetAbilityValue(Ability.Sense));
            Assert.AreEqual(391.625, _character.TreatmentValue);

            var finalImplantTemplates = new[]
            {
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Chest, Ability.Sense, Ability.Psychic, Ability.Strength), // Psychic
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightArm, Ability.Strength, null, null),                  // Sense
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Waist, null, Ability.Sense, Ability.Stamina),             // Psychic
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Eye, null, Skill.Treatment, null),                        // Agility
                ImplantTemplate.GetImplantTemplate(ImplantSlot.RightHand, null, null, Skill.Treatment),                  // Intelligence
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Feet, null, Ability.Agility, null),                       // Agility
                ImplantTemplate.GetImplantTemplate(ImplantSlot.Ear, null, null, Ability.Intelligence)                    // Psychic
            };
            var finalImplantSlots = finalImplantTemplates.Select(t => t.ImplantSlot).ToArray();

            var ladderProcess = new DegenerateLadderProcess(_character, finalImplantTemplates);

            Assert.AreEqual(146, _character.GetAbilityValue(Ability.Agility));
            Assert.AreEqual(124, _character.GetAbilityValue(Ability.Stamina));
            Assert.AreEqual(116, _character.GetAbilityValue(Ability.Sense));
            Assert.AreEqual(391.625, _character.TreatmentValue);
            Assert.AreEqual(_character.GetImplant(ImplantSlot.Head), alreadyEquippedImplants[0]);
            Assert.AreEqual(_character.GetImplant(ImplantSlot.Leg), alreadyEquippedImplants[1]);
            Assert.AreEqual(400, _character.GetTotalImplantQL());

            // The final QL should be greater than what we get by w/o any laddered equips.
            int unladderedTotalFinalImplantQL = 0;

            foreach (var implantTemplate in finalImplantTemplates)
            {
                unladderedTotalFinalImplantQL += _character.GetMaxImplant(implantTemplate).QL;
            }
            Assert.IsTrue(unladderedTotalFinalImplantQL < ladderProcess.TotalFinalImplantQL);

            // The final QL should be greater than what we get by laddering in the arbitrary order declared above.
            foreach (var implantTemplate in finalImplantTemplates)
            {
                _character.EquipMaxImplant(implantTemplate);
            }
            Assert.IsTrue(unladderedTotalFinalImplantQL < _character.GetTotalImplantQL(finalImplantSlots));
            Assert.IsTrue(_character.GetTotalImplantQL(finalImplantSlots) < ladderProcess.TotalFinalImplantQL);

            Assert.AreEqual(0, ladderProcess.OrderedLadderImplants.Count);

            // Some regression tests, I don't know for sure that 423 is what to expect, hopefully won't ever drop below this.
            Assert.AreEqual(388, unladderedTotalFinalImplantQL);
            Assert.AreEqual(406, _character.GetTotalImplantQL(finalImplantSlots));
            Assert.AreEqual(406 / (double)7, _character.GetAverageImplantQL(finalImplantSlots));
            Assert.AreEqual(423, ladderProcess.TotalFinalImplantQL);
            Assert.AreEqual(423 / (double)7, ladderProcess.AverageFinalImplantQL);
        }
Exemplo n.º 25
0
 public Task <ImplantTemplate> EditImplantTemplate(ImplantTemplate template)
 {
     return(_connection.InvokeAsync <ImplantTemplate>("EditImplantTemplate", template));
 }
Exemplo n.º 26
0
        public override string GetLauncher(string StagerCode, byte[] StagerAssembly, Grunt grunt, ImplantTemplate template)
        {
            this.StagerCode         = StagerCode;
            this.Base64ILByteString = Convert.ToBase64String(StagerAssembly);
            this.DiskCode           = XMLTemplate.Replace("{{GRUNT_IL_BYTE_STRING}}", this.Base64ILByteString);
            this.DiskCode           = DiskCode.Replace("{{TARGET_NAME}}", this.TargetName);
            this.DiskCode           = DiskCode.Replace("{{TASK_NAME}}", this.TaskName);

            string launcher = "msbuild.exe" + " " + "file.xml";

            this.LauncherString = launcher;
            return(this.LauncherString);
        }
Exemplo n.º 27
0
 public Implant(ImplantTemplate implantTemplate, int implantQL)
 {
     ImplantTemplate = implantTemplate;
     QL = implantQL;
 }
        public async static Task InitializeImplantTemplates(ICovenantService service, CovenantContext context)
        {
            if (!context.ImplantTemplates.Any())
            {
                var templates = new ImplantTemplate[]
                {
                    new ImplantTemplate
                    {
                        Name                     = "GruntHTTP",
                        Description              = "A Windows implant written in C# that communicates over HTTP.",
                        Language                 = ImplantLanguage.CSharp,
                        CommType                 = CommunicationType.HTTP,
                        ImplantDirection         = ImplantDirection.Pull,
                        CompatibleDotNetVersions = new List <Common.DotNetVersion> {
                            Common.DotNetVersion.Net35, Common.DotNetVersion.Net40
                        }
                    },
                    new ImplantTemplate
                    {
                        Name                     = "GruntSMB",
                        Description              = "A Windows implant written in C# that communicates over SMB.",
                        Language                 = ImplantLanguage.CSharp,
                        CommType                 = CommunicationType.SMB,
                        ImplantDirection         = ImplantDirection.Push,
                        CompatibleDotNetVersions = new List <Common.DotNetVersion> {
                            Common.DotNetVersion.Net35, Common.DotNetVersion.Net40
                        }
                    },
                    new ImplantTemplate
                    {
                        Name                     = "GruntBridge",
                        Description              = "A customizable implant written in C# that communicates with a custom C2Bridge.",
                        Language                 = ImplantLanguage.CSharp,
                        CommType                 = CommunicationType.Bridge,
                        ImplantDirection         = ImplantDirection.Push,
                        CompatibleDotNetVersions = new List <Common.DotNetVersion> {
                            Common.DotNetVersion.Net35, Common.DotNetVersion.Net40
                        }
                    },
                    new ImplantTemplate
                    {
                        Name                     = "Brute",
                        Description              = "A cross-platform implant built on .NET Core 3.1.",
                        Language                 = ImplantLanguage.CSharp,
                        CommType                 = CommunicationType.HTTP,
                        ImplantDirection         = ImplantDirection.Pull,
                        CompatibleDotNetVersions = new List <Common.DotNetVersion> {
                            Common.DotNetVersion.NetCore31
                        }
                    },
                    new ImplantTemplate
                    {
                        Name                     = "GruntHTTPPortForward",
                        Description              = "A Windows implant written in C# that communicates over HTTP. Contains reverse port forward functionality.",
                        Language                 = ImplantLanguage.CSharp,
                        CommType                 = CommunicationType.HTTP,
                        ImplantDirection         = ImplantDirection.Pull,
                        CompatibleDotNetVersions = new List <Common.DotNetVersion> {
                            Common.DotNetVersion.Net35, Common.DotNetVersion.Net40
                        }
                    }
                };
                templates.ToList().ForEach(t => t.ReadFromDisk());
                await service.CreateImplantTemplates(templates);

                await service.CreateEntities(
                    new ListenerTypeImplantTemplate
                {
                    ListenerType    = await service.GetListenerTypeByName("HTTP"),
                    ImplantTemplate = await service.GetImplantTemplateByName("GruntHTTP")
                },
                    new ListenerTypeImplantTemplate
                {
                    ListenerType    = await service.GetListenerTypeByName("HTTP"),
                    ImplantTemplate = await service.GetImplantTemplateByName("GruntSMB")
                },
                    new ListenerTypeImplantTemplate
                {
                    ListenerType    = await service.GetListenerTypeByName("Bridge"),
                    ImplantTemplate = await service.GetImplantTemplateByName("GruntBridge")
                },
                    new ListenerTypeImplantTemplate
                {
                    ListenerType    = await service.GetListenerTypeByName("Bridge"),
                    ImplantTemplate = await service.GetImplantTemplateByName("GruntSMB")
                },
                    new ListenerTypeImplantTemplate
                {
                    ListenerType    = await service.GetListenerTypeByName("HTTP"),
                    ImplantTemplate = await service.GetImplantTemplateByName("Brute")
                },
                    new ListenerTypeImplantTemplate
                {
                    ListenerType    = await service.GetListenerTypeByName("HTTP"),
                    ImplantTemplate = await service.GetImplantTemplateByName("GruntHTTPPortForward")
                }
                    );
            }
        }
Exemplo n.º 29
0
 public override string GetLauncher(string StagerCode, byte[] StagerAssembly, Grunt grunt, ImplantTemplate template)
 {
     this.StagerCode         = StagerCode;
     this.Base64ILByteString = Convert.ToBase64String(StagerAssembly);
     this.LauncherString     = template.Name + ".exe";
     return(this.LauncherString);
 }
Exemplo n.º 30
0
 public override int GetHashCode()
 => ImplantTemplate.GetHashCode();