From 589724d051e6ca05290a400aad762c8a04601c72 Mon Sep 17 00:00:00 2001 From: Matthew Walls Date: Mon, 10 Oct 2022 08:30:29 -0700 Subject: [PATCH] 1.4 update --- 1.1+1.2/Defs/AbilityDefs/Abilities_Base.xml | 11 + .../Defs/DamageDefs/AbilityUser_Damages.xml | 23 + 1.1+1.2/Defs/JobDefs/AbilityUser_Jobs.xml | 20 + 1.1+1.2/Defs/JobDefs/CompDeflector_Jobs.xml | 12 + .../Defs/JobDefs/CompInstalledPart_Jobs.xml | 17 + .../Defs/JobDefs/CompSlotLoadable_Jobs.xml | 10 + 1.1+1.2/Defs/JobDefs/CompVehicle_Jobs.xml | 13 + 1.1+1.2/Defs/PawnShields/Shields.xml | 212 ++++ .../Defs/RulePackDefs/JT_DeflectionRules.xml | 198 +++ 1.1+1.2/Defs/RulePackDefs/JT_GrappleRules.xml | 55 + .../Defs/Stats/CompDeflection_StatWorkers.xml | 18 + .../ThingDefs_Projectiles/JT_Projectiles.xml | 35 + .../CompSlotLoadable_Slots.xml | 15 + .../CompSlotLoadable_ThingDefExample | 138 +++ .../ThinkTreeDefs/CompVehicles_ThinkTree.xml | 126 ++ .../InsertHook_AbilityUserAI.xml | 15 + 1.1+1.2/Defs/WorldObjectDefs/WorldObjects.xml | 19 + .../DamageDef/AbilityUser_Damages.xml | 8 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 8 + .../DefInjected/JobDef/CompDeflector_Jobs.xml | 7 + .../JobDef/CompInstalledPart_Jobs.xml | 8 + .../JobDef/CompSlotLoadable_Jobs.xml | 7 + .../DefInjected/JobDef/CompVehicle_Jobs.xml | 8 + .../RecipeDef/Recipes_Add_Make.xml | 14 + .../StatDef/CompDeflection_StatWorkers.xml | 8 + .../ThingDef/CompSlotLoadable_Slots.xml | 7 + .../CompSlotLoadable_ThingDefExample.xml | 8 + .../WorldObjectDef/WorldObjects.xml | 8 + .../ChineseSimplified/Keyed/AbilityUser.xml | 25 + .../Keyed/CompActivatableEffect.xml | 6 + .../ChineseSimplified/Keyed/CompDeflector.xml | 19 + .../Keyed/CompInstalledPart.xml | 9 + .../ChineseSimplified/Keyed/CompVehicle.xml | 33 + .../Keyed/Eng_WorldObjectMods.xml | 8 + .../Languages/English/Keyed/AbilityUser.xml | 29 + .../English/Keyed/CompActivatableEffect.xml | 6 + .../Languages/English/Keyed/CompDeflector.xml | 20 + .../English/Keyed/CompInstalledPart.xml | 9 + .../Languages/English/Keyed/CompShield.xml | 18 + .../Languages/English/Keyed/CompVehicle.xml | 33 + .../English/Keyed/Eng_WorldObjectMods.xml | 9 + 1.1+1.2/Languages/English/Keyed/Grapple.xml | 11 + 1.1+1.2/Languages/English/Keyed/Misc.xml | 10 + .../DamageDef/AbilityUser_Damages.xml | 8 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 8 + .../DefInjected/JobDef/CompDeflector_Jobs.xml | 7 + .../JobDef/CompInstalledPart_Jobs.xml | 8 + .../JobDef/CompSlotLoadable_Jobs.xml | 7 + .../DefInjected/JobDef/CompVehicle_Jobs.xml | 8 + .../RecipeDef/Recipes_Add_Make.xml | 14 + .../StatDef/CompDeflection_StatWorkers.xml | 8 + .../ThingDef/CompSlotLoadable_Slots.xml | 7 + .../CompSlotLoadable_ThingDefExample.xml | 8 + .../WorldObjectDef/WorldObjects.xml | 8 + .../Languages/French/Keyed/AbilityUser.xml | 25 + .../French/Keyed/CompActivatableEffect.xml | 6 + .../Languages/French/Keyed/CompDeflector.xml | 20 + .../French/Keyed/CompInstalledPart.xml | 9 + 1.1+1.2/Languages/French/Keyed/CompShield.xml | 18 + .../Languages/French/Keyed/CompVehicle.xml | 33 + .../French/Keyed/Eng_WorldObjectMods.xml | 8 + 1.1+1.2/Languages/French/Keyed/Grapple.xml | 11 + 1.1+1.2/Languages/French/Keyed/Misc.xml | 10 + .../DamageDef/AbilityUser_Damages.xml | 7 + .../DefInjected/HediffDef/Shields.xml | 12 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 7 + .../DefInjected/JobDef/CompDeflector_Jobs.xml | 6 + .../JobDef/CompInstalledPart_Jobs.xml | 7 + .../JobDef/CompSlotLoadable_Jobs.xml | 6 + .../DefInjected/JobDef/CompVehicle_Jobs.xml | 7 + .../RulePackDef/JT_GrappleRules.xml | 32 + .../DefInjected/StatCategoryDef/Shields.xml | 6 + .../StatDef/CompDeflection_StatWorkers.xml | 7 + .../Japanese/DefInjected/StatDef/Shields.xml | 25 + .../ThingDef/CompSlotLoadable_Slots.xml | 6 + .../DefInjected/ThingDef/JT_Projectiles.xml | 6 + .../WorldObjectDef/WorldObjects.xml | 7 + .../Languages/Japanese/Keyed/AbilityUser.xml | 27 + .../Japanese/Keyed/CompActivatableEffect.xml | 6 + .../Japanese/Keyed/CompDeflector.xml | 19 + .../Japanese/Keyed/CompInstalledPart.xml | 9 + .../Languages/Japanese/Keyed/CompVehicle.xml | 33 + .../Japanese/Keyed/Eng_WorldObjectMods.xml | 10 + 1.1+1.2/Languages/Japanese/Keyed/Grapple.xml | 11 + 1.1+1.2/Languages/Japanese/Keyed/Misc.xml | 11 + 1.1+1.2/Languages/Japanese/LanguageInfo.xml | 13 + .../DamageDef/AbilityUser_Damages.xml | 8 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 8 + .../Languages/Spanish/Keyed/AbilityUser.xml | 25 + .../DamageDef/AbilityUser_Damages.xml | 8 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 8 + .../DefInjected/JobDef/CompDeflector_Jobs.xml | 7 + .../JobDef/CompInstalledPart_Jobs.xml | 8 + .../JobDef/CompSlotLoadable_Jobs.xml | 7 + .../DefInjected/JobDef/CompVehicle_Jobs.xml | 8 + .../RulePackDef/JT_GrappleRules.xml | 33 + .../StatDef/CompDeflection_StatWorkers.xml | 8 + .../ThingDef/CompSlotLoadable_Slots.xml | 7 + .../DefInjected/ThingDef/JT_Projectiles.xml | 7 + .../WorldObjectDef/WorldObjects.xml | 8 + .../SpanishLatin/Keyed/AbilityUser.xml | 25 + .../Keyed/CompActivatableEffect.xml | 6 + .../SpanishLatin/Keyed/CompDeflector.xml | 20 + .../SpanishLatin/Keyed/CompInstalledPart.xml | 9 + .../SpanishLatin/Keyed/CompVehicle.xml | 33 + .../Keyed/Eng_WorldObjectMods.xml | 8 + .../Languages/SpanishLatin/Keyed/Grapple.xml | 11 + 1.1+1.2/Languages/SpanishLatin/Keyed/Misc.xml | 10 + 1.1/Assemblies/0JecsTools.dll | Bin 0 -> 122368 bytes 1.1/Assemblies/AbilityUser.dll | Bin 0 -> 68096 bytes 1.1/Assemblies/AbilityUserAI.dll | Bin 0 -> 26112 bytes 1.1/Assemblies/CompActivatableEffect.dll | Bin 0 -> 17920 bytes 1.1/Assemblies/CompAnimated.dll | Bin 0 -> 12288 bytes 1.1/Assemblies/CompBalloon.dll | Bin 0 -> 6144 bytes 1.1/Assemblies/CompBigBox.dll | Bin 0 -> 6656 bytes 1.1/Assemblies/CompDeflector.dll | Bin 0 -> 27648 bytes 1.1/Assemblies/CompDelayedSpawner.dll | Bin 0 -> 8192 bytes 1.1/Assemblies/CompExtraSounds.dll | Bin 0 -> 5632 bytes 1.1/Assemblies/CompInstalledPart.dll | Bin 0 -> 18944 bytes 1.1/Assemblies/CompLumbering.dll | Bin 0 -> 7168 bytes 1.1/Assemblies/CompOverlays.dll | Bin 0 -> 5120 bytes 1.1/Assemblies/CompOversizedWeapon.dll | Bin 0 -> 9728 bytes 1.1/Assemblies/CompSlotLoadable.dll | Bin 0 -> 32256 bytes 1.1/Assemblies/CompToggleDef.dll | Bin 0 -> 8192 bytes 1.1/Assemblies/CompVehicle.dll | Bin 0 -> 87040 bytes 1.1/Assemblies/PawnShields.dll | Bin 0 -> 34816 bytes 1.1/Assemblies/ThinkNodes.dll | Bin 0 -> 8704 bytes 1.2/Assemblies/0JecsTools.dll | Bin 0 -> 122368 bytes 1.2/Assemblies/AbilityUser.dll | Bin 0 -> 68096 bytes 1.2/Assemblies/AbilityUserAI.dll | Bin 0 -> 26112 bytes 1.2/Assemblies/CompActivatableEffect.dll | Bin 0 -> 17920 bytes 1.2/Assemblies/CompAnimated.dll | Bin 0 -> 12288 bytes 1.2/Assemblies/CompBalloon.dll | Bin 0 -> 6144 bytes 1.2/Assemblies/CompBigBox.dll | Bin 0 -> 6656 bytes 1.2/Assemblies/CompDeflector.dll | Bin 0 -> 27648 bytes 1.2/Assemblies/CompDelayedSpawner.dll | Bin 0 -> 8192 bytes 1.2/Assemblies/CompExtraSounds.dll | Bin 0 -> 5632 bytes 1.2/Assemblies/CompInstalledPart.dll | Bin 0 -> 18944 bytes 1.2/Assemblies/CompLumbering.dll | Bin 0 -> 7168 bytes 1.2/Assemblies/CompOverlays.dll | Bin 0 -> 5120 bytes 1.2/Assemblies/CompOversizedWeapon.dll | Bin 0 -> 9728 bytes 1.2/Assemblies/CompSlotLoadable.dll | Bin 0 -> 32256 bytes 1.2/Assemblies/CompToggleDef.dll | Bin 0 -> 8192 bytes 1.2/Assemblies/CompVehicle.dll | Bin 0 -> 87552 bytes 1.2/Assemblies/PawnShields.dll | Bin 0 -> 34816 bytes 1.2/Assemblies/ThinkNodes.dll | Bin 0 -> 8704 bytes 1.3/Assemblies/0JecsTools.dll | Bin 0 -> 112640 bytes 1.3/Assemblies/AbilityUser.dll | Bin 0 -> 76288 bytes 1.3/Assemblies/AbilityUserAI.dll | Bin 0 -> 22528 bytes 1.3/Assemblies/CompActivatableEffect.dll | Bin 0 -> 16896 bytes 1.3/Assemblies/CompAnimated.dll | Bin 0 -> 12288 bytes 1.3/Assemblies/CompBalloon.dll | Bin 0 -> 6144 bytes 1.3/Assemblies/CompBigBox.dll | Bin 0 -> 6656 bytes 1.3/Assemblies/CompDeflector.dll | Bin 0 -> 27648 bytes 1.3/Assemblies/CompDelayedSpawner.dll | Bin 0 -> 8192 bytes 1.3/Assemblies/CompExtraSounds.dll | Bin 0 -> 6144 bytes 1.3/Assemblies/CompInstalledPart.dll | Bin 0 -> 20480 bytes 1.3/Assemblies/CompLumbering.dll | Bin 0 -> 7168 bytes 1.3/Assemblies/CompOverlays.dll | Bin 0 -> 5120 bytes 1.3/Assemblies/CompOversizedWeapon.dll | Bin 0 -> 8704 bytes 1.3/Assemblies/CompSlotLoadable.dll | Bin 0 -> 38400 bytes 1.3/Assemblies/CompToggleDef.dll | Bin 0 -> 13312 bytes 1.3/Assemblies/PawnShields.dll | Bin 0 -> 35328 bytes 1.3/Assemblies/ThinkNodes.dll | Bin 0 -> 8192 bytes 1.3/Defs/AbilityDefs/Abilities_Base.xml | 11 + 1.3/Defs/DamageDefs/AbilityUser_Damages.xml | 23 + 1.3/Defs/JobDefs/AbilityUser_Jobs.xml | 20 + 1.3/Defs/JobDefs/CompDeflector_Jobs.xml | 12 + 1.3/Defs/JobDefs/CompInstalledPart_Jobs.xml | 17 + 1.3/Defs/JobDefs/CompSlotLoadable_Jobs.xml | 10 + 1.3/Defs/PawnShields/Shields.xml | 212 ++++ 1.3/Defs/RulePackDefs/JT_DeflectionRules.xml | 198 +++ 1.3/Defs/RulePackDefs/JT_GrappleRules.xml | 55 + 1.3/Defs/Stats/CompDeflection_StatWorkers.xml | 18 + 1.3/Defs/Stats/CompSlotLoadable_Stats.xml | 8 + .../ThingDefs_Projectiles/JT_Projectiles.xml | 35 + .../CompSlotLoadable_Slots.xml | 15 + .../CompSlotLoadable_ThingDefExample | 138 +++ .../InsertHook_AbilityUserAI.xml | 15 + 1.3/Defs/WorldObjectDefs/WorldObjects.xml | 19 + .../DamageDef/AbilityUser_Damages.xml | 8 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 8 + .../DefInjected/JobDef/CompDeflector_Jobs.xml | 7 + .../JobDef/CompInstalledPart_Jobs.xml | 8 + .../JobDef/CompSlotLoadable_Jobs.xml | 7 + .../RecipeDef/Recipes_Add_Make.xml | 14 + .../StatDef/CompDeflection_StatWorkers.xml | 8 + .../ThingDef/CompSlotLoadable_Slots.xml | 7 + .../CompSlotLoadable_ThingDefExample.xml | 8 + .../WorldObjectDef/WorldObjects.xml | 8 + .../ChineseSimplified/Keyed/AbilityUser.xml | 25 + .../Keyed/CompActivatableEffect.xml | 6 + .../ChineseSimplified/Keyed/CompDeflector.xml | 19 + .../Keyed/CompInstalledPart.xml | 9 + .../Keyed/Eng_WorldObjectMods.xml | 8 + 1.3/Languages/English/Keyed/AbilityUser.xml | 29 + .../English/Keyed/CompActivatableEffect.xml | 6 + 1.3/Languages/English/Keyed/CompDeflector.xml | 20 + .../English/Keyed/CompInstalledPart.xml | 9 + 1.3/Languages/English/Keyed/CompShield.xml | 18 + .../English/Keyed/Eng_WorldObjectMods.xml | 9 + 1.3/Languages/English/Keyed/Grapple.xml | 12 + 1.3/Languages/English/Keyed/Misc.xml | 10 + .../DamageDef/AbilityUser_Damages.xml | 8 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 8 + .../DefInjected/JobDef/CompDeflector_Jobs.xml | 7 + .../JobDef/CompInstalledPart_Jobs.xml | 8 + .../JobDef/CompSlotLoadable_Jobs.xml | 7 + .../RecipeDef/Recipes_Add_Make.xml | 14 + .../StatDef/CompDeflection_StatWorkers.xml | 8 + .../ThingDef/CompSlotLoadable_Slots.xml | 7 + .../CompSlotLoadable_ThingDefExample.xml | 8 + .../WorldObjectDef/WorldObjects.xml | 8 + 1.3/Languages/French/Keyed/AbilityUser.xml | 25 + .../French/Keyed/CompActivatableEffect.xml | 6 + 1.3/Languages/French/Keyed/CompDeflector.xml | 20 + .../French/Keyed/CompInstalledPart.xml | 9 + 1.3/Languages/French/Keyed/CompShield.xml | 18 + .../French/Keyed/Eng_WorldObjectMods.xml | 8 + 1.3/Languages/French/Keyed/Grapple.xml | 12 + 1.3/Languages/French/Keyed/Misc.xml | 10 + .../DamageDef/AbilityUser_Damages.xml | 7 + .../DefInjected/HediffDef/Shields.xml | 12 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 7 + .../DefInjected/JobDef/CompDeflector_Jobs.xml | 6 + .../JobDef/CompInstalledPart_Jobs.xml | 7 + .../JobDef/CompSlotLoadable_Jobs.xml | 6 + .../RulePackDef/JT_GrappleRules.xml | 32 + .../DefInjected/StatCategoryDef/Shields.xml | 6 + .../StatDef/CompDeflection_StatWorkers.xml | 7 + .../Japanese/DefInjected/StatDef/Shields.xml | 25 + .../ThingDef/CompSlotLoadable_Slots.xml | 6 + .../DefInjected/ThingDef/JT_Projectiles.xml | 6 + .../WorldObjectDef/WorldObjects.xml | 7 + 1.3/Languages/Japanese/Keyed/AbilityUser.xml | 27 + .../Japanese/Keyed/CompActivatableEffect.xml | 6 + .../Japanese/Keyed/CompDeflector.xml | 19 + .../Japanese/Keyed/CompInstalledPart.xml | 9 + .../Japanese/Keyed/Eng_WorldObjectMods.xml | 10 + 1.3/Languages/Japanese/Keyed/Grapple.xml | 11 + 1.3/Languages/Japanese/Keyed/Misc.xml | 11 + 1.3/Languages/Japanese/LanguageInfo.xml | 13 + .../DamageDef/AbilityUser_Damages.xml | 8 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 8 + 1.3/Languages/Spanish/Keyed/AbilityUser.xml | 25 + .../DamageDef/AbilityUser_Damages.xml | 8 + .../DefInjected/JobDef/AbilityUser_Jobs.xml | 8 + .../DefInjected/JobDef/CompDeflector_Jobs.xml | 7 + .../JobDef/CompInstalledPart_Jobs.xml | 8 + .../JobDef/CompSlotLoadable_Jobs.xml | 7 + .../RulePackDef/JT_GrappleRules.xml | 33 + .../StatDef/CompDeflection_StatWorkers.xml | 8 + .../ThingDef/CompSlotLoadable_Slots.xml | 7 + .../DefInjected/ThingDef/JT_Projectiles.xml | 7 + .../WorldObjectDef/WorldObjects.xml | 8 + .../SpanishLatin/Keyed/AbilityUser.xml | 25 + .../Keyed/CompActivatableEffect.xml | 6 + .../SpanishLatin/Keyed/CompDeflector.xml | 20 + .../SpanishLatin/Keyed/CompInstalledPart.xml | 9 + .../Keyed/Eng_WorldObjectMods.xml | 8 + 1.3/Languages/SpanishLatin/Keyed/Grapple.xml | 11 + 1.3/Languages/SpanishLatin/Keyed/Misc.xml | 10 + About/About.xml | 136 +- About/Changelog.txt | 104 ++ About/Description.txt | 8 +- About/Manifest.xml | 28 +- About/PatreonURL.txt | 2 +- About/Version.txt | 2 +- ...e put in 1.0 folder due to 1.0 limitations | 0 Languages/English/Keyed/AbilityUser.xml | 4 +- LoadFolders.xml | 18 +- README.md | 40 +- Source/.editorconfig | 171 +++ ...ityDecisionConditionalNode_CasterHealth.cs | 12 +- ...ecisionConditionalNode_EnemyTargetCover.cs | 20 +- ...sionConditionalNode_EnemyTargetDistance.cs | 19 +- ...isionConditionalNode_EnemyTargetIsArmed.cs | 23 +- ...yDecisionConditionalNode_HasEnemyTarget.cs | 11 +- ...AbilityDecisionConditionalNode_InCombat.cs | 11 +- ...ecisionConditionalNode_UsingMeleeWeapon.cs | 17 +- ...cisionConditionalNode_UsingRangedWeapon.cs | 11 +- .../AI/AbilityDecision/AbilityDecisionNode.cs | 11 +- ...ecisionNode_PickAbilityWithMatchingTags.cs | 138 +-- .../AI/JobGiver_AIAbilityUser.cs | 184 ++- .../AbilityUserAI/AI/TagWeight.cs | 16 +- .../AbilityUserAI/AIDefOf.cs | 6 +- .../AbilityUserAI/AbilityUserAI.csproj | 82 +- .../AbilityUserAI/Defs/AbilityAIDef.cs | 21 +- .../Defs/AbilityUserAIProfileDef.cs | 21 +- .../AbilityUserAI/Utility/AbilityMaths.cs | 4 +- .../AbilityUserAI/Utility/AbilityUtility.cs | 62 +- .../Workers/AbilityProfileWorker.cs | 6 +- .../AbilityUserAI/Workers/AbilityWorker.cs | 19 +- .../Workers/AbilityWorker_AreaOfEffect.cs | 19 +- .../Workers/AbilityWorker_HealAlly.cs | 8 +- .../CompAbilityUser/AbilityButtons.cs | 4 +- .../CompAbilityUser/AbilityDefOf.cs | 4 +- .../CompAbilityUser/AbilityUserUtility.cs | 135 +- .../CompAbilityUser/AoEProperties.cs | 2 +- .../CompAbilityUser/ApplyHediffs.cs | 6 +- .../CompAbilityUser/ApplyMentalStates.cs | 6 +- .../CompAbilityUser/CompAbilityItem.cs | 92 +- .../CompAbilityUser/CompAbilityUser.csproj | 89 +- .../CompProperties_AbilityItem.cs | 4 +- .../CompProperties_AbilityUser.cs | 2 +- .../Controller/AbilityContext.cs | 2 +- .../Controller/AbilityEffectUtility.cs | 139 +-- .../Controller/JobDriver_CastAbilitySelf.cs | 27 +- .../Controller/JobDriver_CastAbilityVerb.cs | 61 +- .../CompAbilityUser/Controller/PawnAbility.cs | 295 +++-- .../Controller/Projectile_Ability.cs | 37 +- .../Controller/Projectile_AbilityBase.cs | 98 +- .../Controller/Projectile_AbilityLaser.cs | 48 +- .../Controller/Verb_UseAbility.cs | 259 ++-- .../Controller/Verb_UseAbility_TrueBurst.cs | 35 +- .../CompAbilityUser/ExtraDamage.cs | 8 +- .../CompAbilityUser/FlyingObject.cs | 202 +-- .../CompAbilityUser/FlyingObject_Equipable.cs | 43 +- .../CompAbilityUser/Model/AbilityData.cs | 47 +- .../CompAbilityUser/Model/AbilityDef.cs | 98 +- .../CompAbilityUser/Model/CompAbilityUser.cs | 222 ++-- .../Model/VerbProperties_Ability.cs | 2 +- .../PassiveEffectProperties.cs | 4 +- .../CompAbilityUser/PassiveEffectWorker.cs | 28 +- .../PawnAbilityTargetCategory.cs | 2 +- .../CompAbilityUser/PawnSummoned.cs | 19 +- .../CompAbilityUser/ProjectileDef_Ability.cs | 2 +- .../ProjectileDef_LaserProjectile.cs | 2 +- .../CompAbilityUser/SpawnThings.cs | 17 +- .../CompAbilityUser/StringsToTranslate.cs | 4 +- .../View/Command_PawnAbility.cs | 89 +- .../CompAbilityUser/_HarmonyPatches.cs | 645 +++++----- .../ActivatableEffectUtility.cs | 21 + .../CompActivatableEffect.cs | 180 +-- .../CompActivatableEffect.csproj | 59 +- .../CompProperties_ActivatableEffect.cs | 2 +- .../HarmonyCompActivatableEffect.cs | 298 +---- .../CompAnimated/CompAnimated.cs | 67 +- .../CompAnimated/CompAnimated.csproj | 57 +- .../CompAnimated/CompAnimatedOver.cs | 29 +- .../CompAnimated/CompProperties_Animated.cs | 16 +- .../CompProperties_AnimatedOver.cs | 23 +- .../CompBalloon/CompBalloon.cs | 60 +- .../CompBalloon/CompBalloon.csproj | 55 +- .../CompBalloon/CompProperties_Balloon.cs | 2 +- .../CompBigBox/BigBoxUtility.cs | 23 + .../CompBigBox/DefModExtension_BigBox.csproj | 62 +- .../CompBigBox/HitBoxHolder.cs | 19 +- .../CompBigBox/_HarmonyCompBigBox.cs | 46 +- .../CompDeflector/CompDeflector.cs | 387 +++--- .../CompDeflector/CompDeflector.csproj | 60 +- .../CompDeflector/CompDeflectorDefOf.cs | 5 +- .../CompDeflector/CompProperties_Deflector.cs | 55 +- .../CompDeflector/DeflectorUtility.cs | 21 + .../CompDeflector/HarmonyCompDeflector.cs | 175 ++- .../JobDriver_CastDeflectVerb.cs | 24 +- .../StatWorker_DeflectionChance.cs | 149 +-- .../CompDeflector/Verb_Deflected.cs | 86 +- .../CompDelayedSpawner/CompDelayedSpawner.cs | 30 +- .../CompDelayedSpawner.csproj | 59 +- .../CompProperties_DelayedSpawner.cs | 6 +- .../CompExtraSounds/CompExtraSounds.cs | 4 +- .../CompExtraSounds/CompExtraSounds.csproj | 58 +- .../CompProperties_ExtraSounds.cs | 2 +- .../DefModExtension_ExtraSounds.cs | 7 +- .../CompExtraSounds/ExtraSoundsUtility.cs | 37 + .../CompExtraSounds/HarmonyCompExtraSounds.cs | 98 +- .../CompInstalledPart/CompInstalledPart.cs | 74 +- .../CompInstalledPart.csproj | 73 +- .../CompInstalledPartDefOf.cs | 14 + .../CompProperties_InstalledPart.cs | 2 +- .../HarmonyCompInstalledPart.cs | 193 +-- .../InstalledPartFloatMenuPatch.cs | 98 +- .../CompInstalledPart/InstalledPartUtility.cs | 26 + .../JobDriver_InstallPart.cs | 36 +- .../JobDriver_UninstallPart.cs | 32 +- .../CompLumbering/CompLumbering.cs | 24 +- .../CompLumbering/CompLumbering.csproj | 55 +- .../CompLumbering/CompProperties_Lumbering.cs | 2 +- .../CompOverlays/CompOverlays.cs | 44 +- .../CompOverlays/CompOverlays.csproj | 55 +- .../CompOverlays/CompProperties_Overlays.cs | 6 +- .../CompOversizedWeapon.cs | 68 +- .../CompOversizedWeapon.csproj | 56 +- .../CompOversizedWeaponUtility.cs | 26 + .../CompProperties_OversizedWeapon.cs | 35 +- .../HarmonyCompOversizedWeapon.cs | 291 ++--- .../CompProperties_SlotLoadable.cs | 2 +- .../CompProperties_SlottedBonus.cs | 45 +- .../CompSlotLoadable/CompSlotLoadable.cs | 387 +++--- .../CompSlotLoadable/CompSlotLoadable.csproj | 79 +- .../CompSlotLoadable/CompSlotLoadableDefOf.cs | 6 +- .../CompSlotLoadable/CompSlottedBonus.cs | 80 +- .../JobDriver_GatherSlotItem.cs | 56 +- .../SlotBonusProps_DefensiveHealChance.cs | 8 +- .../SlotBonusProps_VampiricEffect.cs | 9 +- .../CompSlotLoadable/SlotLoadable.cs | 172 +-- .../CompSlotLoadable/SlotLoadableDef.cs | 2 +- .../SlotLoadableFloatMenuPatch.cs | 100 +- .../CompSlotLoadable/SlotLoadableUtility.cs | 106 +- .../CompSlotLoadable/StringOf.cs | 16 +- .../_HarmonyCompSlotLoadable.cs | 499 +------- .../CompToggleDef/CompProperties_ToggleDef.cs | 45 +- .../CompToggleDef/CompToggleDef.cs | 79 +- .../CompToggleDef/CompToggleDef.csproj | 50 +- .../CompToggleDef/ITab_ToggleDef.cs | 72 +- .../CompToggleDef/ToggleDefCardUtility.cs | 194 ++- .../CompToggleDef/ToggleDefUtility.cs | 26 + .../JecsTools/ApparelExtension.cs | 38 +- .../JecsTools/Backstories/BackstoryDef.cs | 94 +- .../JecsTools/BuildingExtension.cs | 32 +- .../JecsTools/CaravanJobs/CaravanJob.cs | 121 +- .../JecsTools/CaravanJobs/CaravanJobDef.cs | 12 +- .../JecsTools/CaravanJobs/CaravanJobDriver.cs | 113 +- .../JecsTools/CaravanJobs/CaravanJobGiver.cs | 39 +- .../JecsTools/CaravanJobs/CaravanJobQueue.cs | 6 +- .../CaravanJobs/CaravanJobsUtility.cs | 24 +- .../JecsTools/CaravanJobs/CaravanToil.cs | 23 +- .../CaravanJobs/CaravanToils_Effects.cs | 13 +- .../CaravanJobs/CaravanToils_GoTo.cs | 18 +- .../CaravanJobs/Caravan_JobTracker.cs | 272 ++-- .../CaravanJobs/HarmonyCaravanJobs.cs | 67 +- .../JecsTools/CaravanJobs/QueuedCaravanJob.cs | 6 +- .../CaravanJobs/StuffCategoryCountClass.cs | 43 +- .../JecsTools/CaravanJobs/StuffDefCount.cs | 77 +- .../CaravanJobs/WorldObjectBlueprint.cs | 285 ++--- .../CaravanJobs/WorldObjectRecipeDef.cs | 7 +- .../CaravanJobs/WorldObject_ProgressBar.cs | 22 +- .../JecsTools/DamageDefCleave.cs | 2 +- .../JecsTools/DamageWorker_Cleave.cs | 37 +- .../JecsTools/GrappleUtility.cs | 160 +-- .../JecsTools/HarmonyPatches.cs | 1099 ++++++++--------- .../JecsTools/HarmonyPatches_GUI.cs | 89 +- .../JecsTools/HediffCompDamageOverTime.cs | 7 +- .../HediffCompProperties_DamageOverTime.cs | 2 +- .../HediffCompProperties_DamageSoak.cs | 6 +- .../HediffCompProperties_ExtraMeleeDamages.cs | 16 +- .../HediffCompProperties_Knockback.cs | 95 +- .../JecsTools/HediffComp_DamageSoak.cs | 12 +- .../JecsTools/HediffComp_ExtraMeleeDamages.cs | 13 +- .../JecsTools/HediffComp_Knockback.cs | 31 +- .../JecsTools/HediffExpandedDef.cs | 10 +- .../JecsTools/HediffGiver_StartWithHediff.cs | 11 +- .../JecsTools/HediffWithComps_Expanded.cs | 18 +- .../JecsTools/Hediff_InjuryCustomLabel.cs | 2 +- .../JecsTools/JecsTools.csproj | 123 +- .../JobGiver_AIFirelessTrashColonyClose.cs | 4 +- .../JobGiver_AIFirelessTrashColonyDistant.cs | 2 +- .../JecsTools/PatchOperationModLoaded.cs | 8 +- .../JecsTools/PlaceWorker_OnTopOfWalls.cs | 24 +- .../JecsTools/PlaceWorker_Outline.cs | 2 +- .../JecsTools/PlaceWorker_UnderCeiling.cs | 21 +- .../JecsTools/ProjectileExtension.cs | 14 +- .../JecsTools/Projectile_Laser.cs | 266 ++-- .../JecsTools/ThingDef_LaserProjectile.cs | 2 +- .../JecsTools/TransformedPart.cs | 31 +- .../Utility/DefModExtensionUtility.cs | 50 + .../JecsTools/Utility/FirelessTrashUtility.cs | 77 ++ .../JecsTools/Utility/HarmonyExtensions.cs | 256 ++++ .../JecsTools/Utility/HediffCompUtility.cs | 51 + .../JecsTools/Utility/ListExtensions.cs | 85 ++ .../JecsTools/Utility/MiscDefOf.cs | 15 + .../JecsTools/Utility/ReflectionExtensions.cs | 36 + .../JecsTools/Utility/TexButton.cs | 11 + .../JecsTools/_HumanlikeOrdersUtility.cs | 185 ++- .../PawnShields/HarmonyPatches.cs | 579 +++------ .../ShieldPawnGeneratorProperties.cs | 11 +- .../PawnShields/PawnShields.csproj | 63 +- .../PawnShields/Shields.cs | 6 +- .../PawnShields/ThingComps/CompShield.cs | 82 +- .../Properties/CompProperties_Shield.cs | 75 +- .../Properties/ShieldRenderProperties.cs | 2 +- .../ThingComps/Properties/StuffedSound.cs | 8 +- .../PawnShields/Utility/HarmonyExtensions.cs | 256 ++++ .../PawnShields/Utility/ListExtensions.cs | 85 ++ .../Utility/PawnShieldGenerator.cs | 176 +-- .../PawnShields/Utility/ShieldHediffDefOf.cs | 6 +- .../PawnShields/Utility/ShieldStatsDefOf.cs | 6 +- .../PawnShields/Utility/ShieldUtility.cs | 61 +- .../Workers/StatPart_ShieldStatFactor.cs | 44 + .../PawnShields/Workers/StatWorker_Shield.cs | 77 +- .../ThinkNodes/JobGiver_Capture.cs | 26 +- .../JobGiver_GoToClosestThingDef.cs | 28 +- .../ThinkNodes/ThinkNode_ConditionalDelay.cs | 7 +- .../ThinkNodes/ThinkNode_ConditionalHediff.cs | 14 +- .../ThinkNodes/ThinkNode_ConditionalHunter.cs | 4 +- .../ThinkNode_ConditionalMissingWeapon.cs | 2 +- .../ThinkNode_ConditionalWorkTypesDef.cs | 8 +- .../ThinkNodes/ThinkNodes.csproj | 81 +- Source/JecsTools.sln | 135 +- Source/Shared/!Shared.projitems | 17 + Source/Shared/!Shared.shproj | 13 + _PublisherPlus.xml | 25 + updateinfo | 14 +- 494 files changed, 11306 insertions(+), 8115 deletions(-) create mode 100644 1.1+1.2/Defs/AbilityDefs/Abilities_Base.xml create mode 100644 1.1+1.2/Defs/DamageDefs/AbilityUser_Damages.xml create mode 100644 1.1+1.2/Defs/JobDefs/AbilityUser_Jobs.xml create mode 100644 1.1+1.2/Defs/JobDefs/CompDeflector_Jobs.xml create mode 100644 1.1+1.2/Defs/JobDefs/CompInstalledPart_Jobs.xml create mode 100644 1.1+1.2/Defs/JobDefs/CompSlotLoadable_Jobs.xml create mode 100644 1.1+1.2/Defs/JobDefs/CompVehicle_Jobs.xml create mode 100644 1.1+1.2/Defs/PawnShields/Shields.xml create mode 100644 1.1+1.2/Defs/RulePackDefs/JT_DeflectionRules.xml create mode 100644 1.1+1.2/Defs/RulePackDefs/JT_GrappleRules.xml create mode 100644 1.1+1.2/Defs/Stats/CompDeflection_StatWorkers.xml create mode 100644 1.1+1.2/Defs/ThingDefs_Projectiles/JT_Projectiles.xml create mode 100644 1.1+1.2/Defs/ThingDefs_Slots/CompSlotLoadable_Slots.xml create mode 100644 1.1+1.2/Defs/ThingDefs_WeaponMelee/CompSlotLoadable_ThingDefExample create mode 100644 1.1+1.2/Defs/ThinkTreeDefs/CompVehicles_ThinkTree.xml create mode 100644 1.1+1.2/Defs/ThinkTreeDefs/InsertHook_AbilityUserAI.xml create mode 100644 1.1+1.2/Defs/WorldObjectDefs/WorldObjects.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompDeflector_Jobs.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompInstalledPart_Jobs.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompSlotLoadable_Jobs.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompVehicle_Jobs.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/RecipeDef/Recipes_Add_Make.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/StatDef/CompDeflection_StatWorkers.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_Slots.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/DefInjected/WorldObjectDef/WorldObjects.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/Keyed/AbilityUser.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/Keyed/CompActivatableEffect.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/Keyed/CompDeflector.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/Keyed/CompInstalledPart.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/Keyed/CompVehicle.xml create mode 100644 1.1+1.2/Languages/ChineseSimplified/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.1+1.2/Languages/English/Keyed/AbilityUser.xml create mode 100644 1.1+1.2/Languages/English/Keyed/CompActivatableEffect.xml create mode 100644 1.1+1.2/Languages/English/Keyed/CompDeflector.xml create mode 100644 1.1+1.2/Languages/English/Keyed/CompInstalledPart.xml create mode 100644 1.1+1.2/Languages/English/Keyed/CompShield.xml create mode 100644 1.1+1.2/Languages/English/Keyed/CompVehicle.xml create mode 100644 1.1+1.2/Languages/English/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.1+1.2/Languages/English/Keyed/Grapple.xml create mode 100644 1.1+1.2/Languages/English/Keyed/Misc.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/JobDef/CompDeflector_Jobs.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/JobDef/CompInstalledPart_Jobs.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/JobDef/CompSlotLoadable_Jobs.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/JobDef/CompVehicle_Jobs.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/RecipeDef/Recipes_Add_Make.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/StatDef/CompDeflection_StatWorkers.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/ThingDef/CompSlotLoadable_Slots.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml create mode 100644 1.1+1.2/Languages/French/DefInjected/WorldObjectDef/WorldObjects.xml create mode 100644 1.1+1.2/Languages/French/Keyed/AbilityUser.xml create mode 100644 1.1+1.2/Languages/French/Keyed/CompActivatableEffect.xml create mode 100644 1.1+1.2/Languages/French/Keyed/CompDeflector.xml create mode 100644 1.1+1.2/Languages/French/Keyed/CompInstalledPart.xml create mode 100644 1.1+1.2/Languages/French/Keyed/CompShield.xml create mode 100644 1.1+1.2/Languages/French/Keyed/CompVehicle.xml create mode 100644 1.1+1.2/Languages/French/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.1+1.2/Languages/French/Keyed/Grapple.xml create mode 100644 1.1+1.2/Languages/French/Keyed/Misc.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/HediffDef/Shields.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompDeflector_Jobs.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompInstalledPart_Jobs.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompSlotLoadable_Jobs.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompVehicle_Jobs.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/RulePackDef/JT_GrappleRules.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/StatCategoryDef/Shields.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/StatDef/CompDeflection_StatWorkers.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/StatDef/Shields.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/ThingDef/CompSlotLoadable_Slots.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/ThingDef/JT_Projectiles.xml create mode 100644 1.1+1.2/Languages/Japanese/DefInjected/WorldObjectDef/WorldObjects.xml create mode 100644 1.1+1.2/Languages/Japanese/Keyed/AbilityUser.xml create mode 100644 1.1+1.2/Languages/Japanese/Keyed/CompActivatableEffect.xml create mode 100644 1.1+1.2/Languages/Japanese/Keyed/CompDeflector.xml create mode 100644 1.1+1.2/Languages/Japanese/Keyed/CompInstalledPart.xml create mode 100644 1.1+1.2/Languages/Japanese/Keyed/CompVehicle.xml create mode 100644 1.1+1.2/Languages/Japanese/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.1+1.2/Languages/Japanese/Keyed/Grapple.xml create mode 100644 1.1+1.2/Languages/Japanese/Keyed/Misc.xml create mode 100644 1.1+1.2/Languages/Japanese/LanguageInfo.xml create mode 100644 1.1+1.2/Languages/Spanish/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.1+1.2/Languages/Spanish/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.1+1.2/Languages/Spanish/Keyed/AbilityUser.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompDeflector_Jobs.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompInstalledPart_Jobs.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompSlotLoadable_Jobs.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompVehicle_Jobs.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/RulePackDef/JT_GrappleRules.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/StatDef/CompDeflection_StatWorkers.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/ThingDef/CompSlotLoadable_Slots.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/ThingDef/JT_Projectiles.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/DefInjected/WorldObjectDef/WorldObjects.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/Keyed/AbilityUser.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/Keyed/CompActivatableEffect.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/Keyed/CompDeflector.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/Keyed/CompInstalledPart.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/Keyed/CompVehicle.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/Keyed/Grapple.xml create mode 100644 1.1+1.2/Languages/SpanishLatin/Keyed/Misc.xml create mode 100644 1.1/Assemblies/0JecsTools.dll create mode 100644 1.1/Assemblies/AbilityUser.dll create mode 100644 1.1/Assemblies/AbilityUserAI.dll create mode 100644 1.1/Assemblies/CompActivatableEffect.dll create mode 100644 1.1/Assemblies/CompAnimated.dll create mode 100644 1.1/Assemblies/CompBalloon.dll create mode 100644 1.1/Assemblies/CompBigBox.dll create mode 100644 1.1/Assemblies/CompDeflector.dll create mode 100644 1.1/Assemblies/CompDelayedSpawner.dll create mode 100644 1.1/Assemblies/CompExtraSounds.dll create mode 100644 1.1/Assemblies/CompInstalledPart.dll create mode 100644 1.1/Assemblies/CompLumbering.dll create mode 100644 1.1/Assemblies/CompOverlays.dll create mode 100644 1.1/Assemblies/CompOversizedWeapon.dll create mode 100644 1.1/Assemblies/CompSlotLoadable.dll create mode 100644 1.1/Assemblies/CompToggleDef.dll create mode 100644 1.1/Assemblies/CompVehicle.dll create mode 100644 1.1/Assemblies/PawnShields.dll create mode 100644 1.1/Assemblies/ThinkNodes.dll create mode 100644 1.2/Assemblies/0JecsTools.dll create mode 100644 1.2/Assemblies/AbilityUser.dll create mode 100644 1.2/Assemblies/AbilityUserAI.dll create mode 100644 1.2/Assemblies/CompActivatableEffect.dll create mode 100644 1.2/Assemblies/CompAnimated.dll create mode 100644 1.2/Assemblies/CompBalloon.dll create mode 100644 1.2/Assemblies/CompBigBox.dll create mode 100644 1.2/Assemblies/CompDeflector.dll create mode 100644 1.2/Assemblies/CompDelayedSpawner.dll create mode 100644 1.2/Assemblies/CompExtraSounds.dll create mode 100644 1.2/Assemblies/CompInstalledPart.dll create mode 100644 1.2/Assemblies/CompLumbering.dll create mode 100644 1.2/Assemblies/CompOverlays.dll create mode 100644 1.2/Assemblies/CompOversizedWeapon.dll create mode 100644 1.2/Assemblies/CompSlotLoadable.dll create mode 100644 1.2/Assemblies/CompToggleDef.dll create mode 100644 1.2/Assemblies/CompVehicle.dll create mode 100644 1.2/Assemblies/PawnShields.dll create mode 100644 1.2/Assemblies/ThinkNodes.dll create mode 100644 1.3/Assemblies/0JecsTools.dll create mode 100644 1.3/Assemblies/AbilityUser.dll create mode 100644 1.3/Assemblies/AbilityUserAI.dll create mode 100644 1.3/Assemblies/CompActivatableEffect.dll create mode 100644 1.3/Assemblies/CompAnimated.dll create mode 100644 1.3/Assemblies/CompBalloon.dll create mode 100644 1.3/Assemblies/CompBigBox.dll create mode 100644 1.3/Assemblies/CompDeflector.dll create mode 100644 1.3/Assemblies/CompDelayedSpawner.dll create mode 100644 1.3/Assemblies/CompExtraSounds.dll create mode 100644 1.3/Assemblies/CompInstalledPart.dll create mode 100644 1.3/Assemblies/CompLumbering.dll create mode 100644 1.3/Assemblies/CompOverlays.dll create mode 100644 1.3/Assemblies/CompOversizedWeapon.dll create mode 100644 1.3/Assemblies/CompSlotLoadable.dll create mode 100644 1.3/Assemblies/CompToggleDef.dll create mode 100644 1.3/Assemblies/PawnShields.dll create mode 100644 1.3/Assemblies/ThinkNodes.dll create mode 100644 1.3/Defs/AbilityDefs/Abilities_Base.xml create mode 100644 1.3/Defs/DamageDefs/AbilityUser_Damages.xml create mode 100644 1.3/Defs/JobDefs/AbilityUser_Jobs.xml create mode 100644 1.3/Defs/JobDefs/CompDeflector_Jobs.xml create mode 100644 1.3/Defs/JobDefs/CompInstalledPart_Jobs.xml create mode 100644 1.3/Defs/JobDefs/CompSlotLoadable_Jobs.xml create mode 100644 1.3/Defs/PawnShields/Shields.xml create mode 100644 1.3/Defs/RulePackDefs/JT_DeflectionRules.xml create mode 100644 1.3/Defs/RulePackDefs/JT_GrappleRules.xml create mode 100644 1.3/Defs/Stats/CompDeflection_StatWorkers.xml create mode 100644 1.3/Defs/Stats/CompSlotLoadable_Stats.xml create mode 100644 1.3/Defs/ThingDefs_Projectiles/JT_Projectiles.xml create mode 100644 1.3/Defs/ThingDefs_Slots/CompSlotLoadable_Slots.xml create mode 100644 1.3/Defs/ThingDefs_WeaponMelee/CompSlotLoadable_ThingDefExample create mode 100644 1.3/Defs/ThinkTreeDefs/InsertHook_AbilityUserAI.xml create mode 100644 1.3/Defs/WorldObjectDefs/WorldObjects.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompDeflector_Jobs.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompInstalledPart_Jobs.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompSlotLoadable_Jobs.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/RecipeDef/Recipes_Add_Make.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/StatDef/CompDeflection_StatWorkers.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_Slots.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml create mode 100644 1.3/Languages/ChineseSimplified/DefInjected/WorldObjectDef/WorldObjects.xml create mode 100644 1.3/Languages/ChineseSimplified/Keyed/AbilityUser.xml create mode 100644 1.3/Languages/ChineseSimplified/Keyed/CompActivatableEffect.xml create mode 100644 1.3/Languages/ChineseSimplified/Keyed/CompDeflector.xml create mode 100644 1.3/Languages/ChineseSimplified/Keyed/CompInstalledPart.xml create mode 100644 1.3/Languages/ChineseSimplified/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.3/Languages/English/Keyed/AbilityUser.xml create mode 100644 1.3/Languages/English/Keyed/CompActivatableEffect.xml create mode 100644 1.3/Languages/English/Keyed/CompDeflector.xml create mode 100644 1.3/Languages/English/Keyed/CompInstalledPart.xml create mode 100644 1.3/Languages/English/Keyed/CompShield.xml create mode 100644 1.3/Languages/English/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.3/Languages/English/Keyed/Grapple.xml create mode 100644 1.3/Languages/English/Keyed/Misc.xml create mode 100644 1.3/Languages/French/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.3/Languages/French/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.3/Languages/French/DefInjected/JobDef/CompDeflector_Jobs.xml create mode 100644 1.3/Languages/French/DefInjected/JobDef/CompInstalledPart_Jobs.xml create mode 100644 1.3/Languages/French/DefInjected/JobDef/CompSlotLoadable_Jobs.xml create mode 100644 1.3/Languages/French/DefInjected/RecipeDef/Recipes_Add_Make.xml create mode 100644 1.3/Languages/French/DefInjected/StatDef/CompDeflection_StatWorkers.xml create mode 100644 1.3/Languages/French/DefInjected/ThingDef/CompSlotLoadable_Slots.xml create mode 100644 1.3/Languages/French/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml create mode 100644 1.3/Languages/French/DefInjected/WorldObjectDef/WorldObjects.xml create mode 100644 1.3/Languages/French/Keyed/AbilityUser.xml create mode 100644 1.3/Languages/French/Keyed/CompActivatableEffect.xml create mode 100644 1.3/Languages/French/Keyed/CompDeflector.xml create mode 100644 1.3/Languages/French/Keyed/CompInstalledPart.xml create mode 100644 1.3/Languages/French/Keyed/CompShield.xml create mode 100644 1.3/Languages/French/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.3/Languages/French/Keyed/Grapple.xml create mode 100644 1.3/Languages/French/Keyed/Misc.xml create mode 100644 1.3/Languages/Japanese/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.3/Languages/Japanese/DefInjected/HediffDef/Shields.xml create mode 100644 1.3/Languages/Japanese/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.3/Languages/Japanese/DefInjected/JobDef/CompDeflector_Jobs.xml create mode 100644 1.3/Languages/Japanese/DefInjected/JobDef/CompInstalledPart_Jobs.xml create mode 100644 1.3/Languages/Japanese/DefInjected/JobDef/CompSlotLoadable_Jobs.xml create mode 100644 1.3/Languages/Japanese/DefInjected/RulePackDef/JT_GrappleRules.xml create mode 100644 1.3/Languages/Japanese/DefInjected/StatCategoryDef/Shields.xml create mode 100644 1.3/Languages/Japanese/DefInjected/StatDef/CompDeflection_StatWorkers.xml create mode 100644 1.3/Languages/Japanese/DefInjected/StatDef/Shields.xml create mode 100644 1.3/Languages/Japanese/DefInjected/ThingDef/CompSlotLoadable_Slots.xml create mode 100644 1.3/Languages/Japanese/DefInjected/ThingDef/JT_Projectiles.xml create mode 100644 1.3/Languages/Japanese/DefInjected/WorldObjectDef/WorldObjects.xml create mode 100644 1.3/Languages/Japanese/Keyed/AbilityUser.xml create mode 100644 1.3/Languages/Japanese/Keyed/CompActivatableEffect.xml create mode 100644 1.3/Languages/Japanese/Keyed/CompDeflector.xml create mode 100644 1.3/Languages/Japanese/Keyed/CompInstalledPart.xml create mode 100644 1.3/Languages/Japanese/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.3/Languages/Japanese/Keyed/Grapple.xml create mode 100644 1.3/Languages/Japanese/Keyed/Misc.xml create mode 100644 1.3/Languages/Japanese/LanguageInfo.xml create mode 100644 1.3/Languages/Spanish/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.3/Languages/Spanish/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.3/Languages/Spanish/Keyed/AbilityUser.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/DamageDef/AbilityUser_Damages.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/JobDef/AbilityUser_Jobs.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/JobDef/CompDeflector_Jobs.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/JobDef/CompInstalledPart_Jobs.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/JobDef/CompSlotLoadable_Jobs.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/RulePackDef/JT_GrappleRules.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/StatDef/CompDeflection_StatWorkers.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/ThingDef/CompSlotLoadable_Slots.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/ThingDef/JT_Projectiles.xml create mode 100644 1.3/Languages/SpanishLatin/DefInjected/WorldObjectDef/WorldObjects.xml create mode 100644 1.3/Languages/SpanishLatin/Keyed/AbilityUser.xml create mode 100644 1.3/Languages/SpanishLatin/Keyed/CompActivatableEffect.xml create mode 100644 1.3/Languages/SpanishLatin/Keyed/CompDeflector.xml create mode 100644 1.3/Languages/SpanishLatin/Keyed/CompInstalledPart.xml create mode 100644 1.3/Languages/SpanishLatin/Keyed/Eng_WorldObjectMods.xml create mode 100644 1.3/Languages/SpanishLatin/Keyed/Grapple.xml create mode 100644 1.3/Languages/SpanishLatin/Keyed/Misc.xml create mode 100644 Languages/!NOTE - this folder is for 1.0 only and cannot be put in 1.0 folder due to 1.0 limitations create mode 100644 Source/.editorconfig create mode 100644 Source/AllModdingComponents/CompActivatableEffect/ActivatableEffectUtility.cs create mode 100644 Source/AllModdingComponents/CompBigBox/BigBoxUtility.cs create mode 100644 Source/AllModdingComponents/CompDeflector/DeflectorUtility.cs create mode 100644 Source/AllModdingComponents/CompExtraSounds/ExtraSoundsUtility.cs create mode 100644 Source/AllModdingComponents/CompInstalledPart/CompInstalledPartDefOf.cs create mode 100644 Source/AllModdingComponents/CompInstalledPart/InstalledPartUtility.cs create mode 100644 Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeaponUtility.cs create mode 100644 Source/AllModdingComponents/CompToggleDef/ToggleDefUtility.cs create mode 100644 Source/AllModdingComponents/JecsTools/Utility/DefModExtensionUtility.cs create mode 100644 Source/AllModdingComponents/JecsTools/Utility/FirelessTrashUtility.cs create mode 100644 Source/AllModdingComponents/JecsTools/Utility/HarmonyExtensions.cs create mode 100644 Source/AllModdingComponents/JecsTools/Utility/HediffCompUtility.cs create mode 100644 Source/AllModdingComponents/JecsTools/Utility/ListExtensions.cs create mode 100644 Source/AllModdingComponents/JecsTools/Utility/MiscDefOf.cs create mode 100644 Source/AllModdingComponents/JecsTools/Utility/ReflectionExtensions.cs create mode 100644 Source/AllModdingComponents/JecsTools/Utility/TexButton.cs create mode 100644 Source/AllModdingComponents/PawnShields/Utility/HarmonyExtensions.cs create mode 100644 Source/AllModdingComponents/PawnShields/Utility/ListExtensions.cs create mode 100644 Source/AllModdingComponents/PawnShields/Workers/StatPart_ShieldStatFactor.cs create mode 100644 Source/Shared/!Shared.projitems create mode 100644 Source/Shared/!Shared.shproj create mode 100644 _PublisherPlus.xml diff --git a/1.1+1.2/Defs/AbilityDefs/Abilities_Base.xml b/1.1+1.2/Defs/AbilityDefs/Abilities_Base.xml new file mode 100644 index 00000000..477dd882 --- /dev/null +++ b/1.1+1.2/Defs/AbilityDefs/Abilities_Base.xml @@ -0,0 +1,11 @@ + + + + + + + + UI/Glow_Corrupt + + + diff --git a/1.1+1.2/Defs/DamageDefs/AbilityUser_Damages.xml b/1.1+1.2/Defs/DamageDefs/AbilityUser_Damages.xml new file mode 100644 index 00000000..4d662397 --- /dev/null +++ b/1.1+1.2/Defs/DamageDefs/AbilityUser_Damages.xml @@ -0,0 +1,23 @@ + + + + + Laser + DamageWorker_AddInjury + + true + false + + false + true + {0} has been shot to death. + Burn + Heat + 15 + Mote_BlastFlame + (1, 0.7, 0.7) + (1, 1, 0.7) + Explosion_Flame + + + diff --git a/1.1+1.2/Defs/JobDefs/AbilityUser_Jobs.xml b/1.1+1.2/Defs/JobDefs/AbilityUser_Jobs.xml new file mode 100644 index 00000000..b39575ae --- /dev/null +++ b/1.1+1.2/Defs/JobDefs/AbilityUser_Jobs.xml @@ -0,0 +1,20 @@ + + + + + CastAbilityVerb + AbilityUser.JobDriver_CastAbilityVerb + Using an ability + true + false + + + + CastAbilitySelf + AbilityUser.JobDriver_CastAbilitySelf + Using an ability + true + false + + + \ No newline at end of file diff --git a/1.1+1.2/Defs/JobDefs/CompDeflector_Jobs.xml b/1.1+1.2/Defs/JobDefs/CompDeflector_Jobs.xml new file mode 100644 index 00000000..ec1ca382 --- /dev/null +++ b/1.1+1.2/Defs/JobDefs/CompDeflector_Jobs.xml @@ -0,0 +1,12 @@ + + + + + CastDeflectVerb + CompDeflector.JobDriver_CastDeflectVerb + Deflecting + true + false + + + \ No newline at end of file diff --git a/1.1+1.2/Defs/JobDefs/CompInstalledPart_Jobs.xml b/1.1+1.2/Defs/JobDefs/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..183535d5 --- /dev/null +++ b/1.1+1.2/Defs/JobDefs/CompInstalledPart_Jobs.xml @@ -0,0 +1,17 @@ + + + + CompInstalledPart_InstallPart + CompInstalledPart.JobDriver_InstallPart + installing TargetA. + false + + + + CompInstalledPart_UninstallPart + CompInstalledPart.JobDriver_UninstallPart + uninstalling TargetA. + false + + + diff --git a/1.1+1.2/Defs/JobDefs/CompSlotLoadable_Jobs.xml b/1.1+1.2/Defs/JobDefs/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..98af40fc --- /dev/null +++ b/1.1+1.2/Defs/JobDefs/CompSlotLoadable_Jobs.xml @@ -0,0 +1,10 @@ + + + + + GatherSlotItem + CompSlotLoadable.JobDriver_GatherSlotItem + equipping TargetA. + + + \ No newline at end of file diff --git a/1.1+1.2/Defs/JobDefs/CompVehicle_Jobs.xml b/1.1+1.2/Defs/JobDefs/CompVehicle_Jobs.xml new file mode 100644 index 00000000..e69311a1 --- /dev/null +++ b/1.1+1.2/Defs/JobDefs/CompVehicle_Jobs.xml @@ -0,0 +1,13 @@ + + + + CompVehicle_LoadPassenger + CompVehicle.JobDriver_LoadPassenger + entering TargetA. + + + CompVehicle_Assemble + CompVehicle.JobDriver_AssembleVehicle + assembling TargetA. + + diff --git a/1.1+1.2/Defs/PawnShields/Shields.xml b/1.1+1.2/Defs/PawnShields/Shields.xml new file mode 100644 index 00000000..b9c36f40 --- /dev/null +++ b/1.1+1.2/Defs/PawnShields/Shields.xml @@ -0,0 +1,212 @@ + + + + Shield + + 35 + + + + Shield_BaseMeleeBlockChance + + Shield users melee block chance is multiplied by this. The higher the better. + Shield + 5 + PawnShields.StatWorker_Shield_BaseMeleeBlockChance + 1 + 0.05 + PercentZero + false + + + + Shield_BaseRangedBlockChance + + Shield users ranged block chance is multiplied by this. The higher the better. + Shield + 4 + PawnShields.StatWorker_Shield_BaseRangedBlockChance + 0.5 + 0.05 + PercentZero + false + + + + Shield_DamageAbsorbed + + How much percent of damage the shield's hit points absorbs from a blocked attack. Note: a blocked attack deals no damage to the shield wielder. + Shield + 3 + PawnShields.StatWorker_Shield_DamageAbsorbed + 1 + 0.05 + PercentZero + false + + + + + ShieldFatigue + + HediffWithComps + Shield Fatigue + 1.0 + +
  • + -48.0 +
  • +
    + +
  • + + +
  • + Manipulation + -0.02 +
  • +
  • + Moving + -0.02 +
  • + + +
  • + 0.5 + + +
  • + Manipulation + -0.06 +
  • +
  • + Moving + -0.06 +
  • + + +
  • + 0.8 + + +
  • + Manipulation + -0.1 +
  • +
  • + Moving + -0.1 +
  • + + +
  • + 1.0 + + +
  • + Manipulation + -0.1 +
  • +
  • + Moving + -0.1 +
  • + + +
    +
    + + + + MeleeShieldBlockChance + + Chance to block with a shield a melee attack that would've otherwise hit. + PawnCombat + 99 + false + 0 + PercentZero + FloatOne + 0 + +
  • + Melee + 35 + 7 +
  • +
    + +
  • + Shield_BaseMeleeBlockChance +
  • +
    + +
  • + Moving + 18 +
  • +
  • + Sight + 8 + 1.4 +
  • +
    + + +
  • (0, 0.0)
  • +
  • (5, 0.10)
  • +
  • (20, 0.30)
  • +
  • (60, 0.50)
  • +
  • (100, 0.80)
  • +
  • (140, 0.90)
  • +
    +
    +
    + + + + RangedShieldBlockChance + + Chance to block with a shield a ranged attack that would've otherwise hit. + PawnCombat + 98 + false + 0 + PercentZero + FloatOne + 0 + +
  • + Melee + 15 + 3 +
  • +
    + +
  • + Moving + 18 +
  • +
  • + Sight + 8 + 1.4 +
  • +
    + +
  • + Shield_BaseRangedBlockChance +
  • +
    + + +
  • (0, 0.0)
  • +
  • (5, 0.05)
  • +
  • (20, 0.10)
  • +
  • (60, 0.30)
  • +
  • (100, 0.60)
  • +
  • (140, 0.80)
  • +
    +
    +
    +
    diff --git a/1.1+1.2/Defs/RulePackDefs/JT_DeflectionRules.xml b/1.1+1.2/Defs/RulePackDefs/JT_DeflectionRules.xml new file mode 100644 index 00000000..36125c88 --- /dev/null +++ b/1.1+1.2/Defs/RulePackDefs/JT_DeflectionRules.xml @@ -0,0 +1,198 @@ + + + + + Combat_RangedDamage + +
  • Combat_WoundIncludes
  • +
  • Combat_MeleeIncludes
  • +
    + + + +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets].
  • +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets] [to] [destroyed_suffix].
  • +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets] [expertly].
  • +
  • r_logentry(p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets].
  • +
  • r_logentry(p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite], [destroyed_present] [RECIPIENT_definite]'s [destroyed_targets].
  • +
  • r_logentry->[RECIPIENT_definite]'s [destroyed_targets] was [destroyed_past] by [INITIATOR_definite]'s [WEAPON_projectile_label].
  • +
  • r_logentry->[RECIPIENT_definite]'s [destroyed_targets] was [destroyed_past] by [INITIATOR_definite]'s [expert] [WEAPON_projectile_label].
  • +
  • r_logentry->[RECIPIENT_definite]'s [destroyed_targets] was [destroyed_past] into [destroyed_suffix] by [INITIATOR_definite]'s [WEAPON_projectile_label].
  • +
  • r_logentry->[INITIATOR_definite] [expertly] returned the incoming fire. It [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets].
  • +
  • r_logentry(p=0.7)->[INITIATOR_definite], wielding [INITIATOR_possessive] [WEAPON_label] [expertly], [damaged_past] [RECIPIENT_definite] in the [damaged_targets].
  • + + +
  • r_logentry(recipient_partDestroyed_count==0)->[INITIATOR_definite]'s [WEAPON_projectile_label] [damaged_past] [RECIPIENT_definite]'s [damaged_targets].
  • +
  • r_logentry(recipient_partDestroyed_count==0)->[INITIATOR_definite]'s [WEAPON_projectile_label] [damaged_past] [RECIPIENT_definite]'s [damaged_targets] [expertly].
  • +
  • r_logentry(recipient_partDestroyed_count==0,p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and [damaged_past] [RECIPIENT_definite]'s [damaged_targets].
  • +
  • r_logentry(recipient_partDestroyed_count==0,p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite], [damaged_present] [RECIPIENT_definite]'s [damaged_targets].
  • +
  • r_logentry(recipient_partDestroyed_count==0)->[RECIPIENT_definite]'s [damaged_targets] was [damaged_past] by [INITIATOR_definite]'s [WEAPON_projectile_label].
  • +
  • r_logentry(recipient_partDestroyed_count==0)->[RECIPIENT_definite]'s [damaged_targets] was [damaged_past] by [INITIATOR_definite]'s [expert] [WEAPON_projectile_label].
  • +
  • r_logentry(recipient_partDestroyed_count==0)->[RECIPIENT_definite]'s [damaged_targets] was [damaged_past] by [INITIATOR_definite]'s shot.
  • + + +
  • r_logentry(p=3)->[INITIATOR_definite]'s [WEAPON_projectile_label] [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets] and [damaged_past] [RECIPIENT_possessive] [damaged_targets].
  • +
  • r_logentry(p=6)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite], [destroyed_present] [RECIPIENT_definite]'s [destroyed_targets] and [damaged_present] [RECIPIENT_possessive] [damaged_targets].
  • +
  • r_logentry(p=6)->[INITIATOR_definite] sent a wild ricochet - [destroyed_present] [RECIPIENT_definite]'s [destroyed_targets] and [damaged_present] [RECIPIENT_possessive] [damaged_targets].
  • + + +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite] with a [WEAPON_projectile_label].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite]'s [WEAPON_projectile_label] hit [RECIPIENT_definite].
  • +
  • r_logentry(p=0.4)->[INITIATOR_definite] [missed] [ORIGINALTARGET_definite] and hit [RECIPIENT_definite] with a [WEAPON_projectile_label].
  • +
  • r_logentry(p=0.4)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and hit [RECIPIENT_definite].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite] with a [WEAPON_projectile_label] intended for [ORIGINALTARGET_definite].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite] with a projectile.
  • + + +
  • WEAPON_projectile_label(p=0.05)->shot
  • +
  • WEAPON_projectile_label(p=0.05)->projectile
  • +
  • WEAPON_projectile_label(p=0.05)->blast
  • + +
  • destroyed_past->shattered
  • +
  • destroyed_past->crushed
  • +
  • destroyed_past->obliterated
  • +
  • destroyed_past->annihilated
  • +
  • destroyed_past->pierced
  • +
  • destroyed_past->perforated
  • +
  • destroyed_past->punctured
  • + +
  • destroyed_present->shattering
  • +
  • destroyed_present->crushing
  • +
  • destroyed_present->obliterating
  • +
  • destroyed_present->annihilating
  • +
  • destroyed_present->piercing
  • +
  • destroyed_present->perforating
  • +
  • destroyed_present->puncturing
  • + +
  • destroyed_suffix->pieces
  • +
  • destroyed_suffix->bits
  • +
  • destroyed_suffix->a fine mist
  • +
  • destroyed_suffix->fragments
  • +
  • destroyed_suffix(p=0.5)->a holey mess
  • +
  • destroyed_suffix(recipient_flesh!=Mechanoid,p=0.2)->ground beef
  • + +
  • damaged_past->wounded
  • +
  • damaged_past->injured
  • +
  • damaged_past->pierced
  • +
  • damaged_past->damaged
  • +
  • damaged_past->shot
  • + +
  • damaged_present->wounding
  • +
  • damaged_present->injuring
  • +
  • damaged_present->piercing
  • +
  • damaged_present->damaging
  • +
  • damaged_present->shooting
  • + +
  • damaged_suffix->in an ugly fashion
  • +
  • damaged_suffix(recipient_flesh!=Mechanoid)->with visible blood
  • +
  • damaged_suffix(recipient_flesh!=Mechanoid)->with the flesh visible
  • + +
  • to->to
  • +
  • to->into
  • + +
  • missed->missed
  • +
  • missed->narrowly missed
  • +
    +
    +
    + + + Combat_RangedDeflect + +
  • Combat_DeflectIncludes
  • +
    + + +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [damaged_past] [RECIPIENT_definite][damaged_target] [deflected_result].
  • +
  • r_logentry(p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and [damaged_past] [RECIPIENT_definite][damaged_target_possessive_opt] [deflected_result].
  • +
  • r_logentry->[RECIPIENT_definite][damaged_target_possessive_opt] was [damaged_past] by [INITIATOR_definite]'s [WEAPON_projectile_label] [deflected_result].
  • + +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite][damaged_target_possessive_opt] with a shot [deflected_result].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite]'s projectile hit [RECIPIENT_definite][damaged_target_possessive_opt] [deflected_result].
  • +
  • r_logentry(p=0.4)->[INITIATOR_definite] [missed] [ORIGINALTARGET_definite] and hit [RECIPIENT_definite][damaged_target_possessive_opt] with a [WEAPON_projectile_label] [deflected_result].
  • +
  • r_logentry(p=0.4)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and hit [RECIPIENT_definite][damaged_target_possessive_opt] [deflected_result].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite][damaged_target_possessive_opt] with a [WEAPON_projectile_label] intended for [ORIGINALTARGET_definite] [deflected_result].
  • + + +
  • WEAPON_projectile_label(p=0.05)->shot
  • +
  • WEAPON_projectile_label(p=0.05)->projectile
  • +
  • WEAPON_projectile_label(p=0.05)->blast
  • +
  • ORIGINALTARGET_definite(p=0.5)->someone else
  • + +
  • damaged_target_possessive_opt->
  • +
  • damaged_target_possessive_opt(recipient_part_damaged0_outside==True)->'s [RECIPIENT_part_damaged0_label]
  • + +
  • deflected_result-> [adverb_deflected]
  • +
  • deflected_result->, [deflected_consequence]
  • + +
  • adverb_deflected_opt(p=4)->
  • +
  • adverb_deflected_opt->[adverb_deflected]
  • + +
  • adverb_deflected->harmlessly
  • +
  • adverb_deflected->uselessly
  • + +
  • deflected_consequence->but it [scraped_past] off [adverb_deflected_opt]
  • +
  • deflected_consequence->[scraped_present] off [RECIPIENT_possessive] armor [adverb_deflected_opt]
  • + +
  • scraped_past->ricocheted
  • + +
  • scraped_present->ricocheting
  • + +
  • missed->missed
  • +
  • missed->narrowly missed
  • +
    +
    +
    + + + + Combat_RangedMiss + + +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed].
  • + +
  • r_logentry->[INITIATOR_definite] missed [ORIGINALTARGET_definite].
  • +
  • r_logentry->[ORIGINALTARGET_definite] [avoidance], [INITIATOR_definite]'s [WEAPON_projectile_label] [missing].
  • + +
  • WEAPON_projectile_label(p=0.05)->shot
  • +
  • WEAPON_projectile_label(p=0.05)->projectile
  • +
  • WEAPON_projectile_label(p=0.05)->blast
  • +
  • missed(p=4)->missed
  • +
  • missed(p=2)->missed by a small margin
  • +
  • missed(p=2)->missed by a wide margin
  • +
  • missed->went wide
  • +
  • missed->flew into the air
  • +
  • missed->flew high into the air
  • +
  • missed->dug into the ground
  • +
  • missed->skipped off the ground and was lost
  • +
  • missed->dug a divot out of the ground
  • +
  • missed(p=0.2)->passed within millimeters of [ORIGINALTARGET_definite]
  • +
  • missed->passed within centimeters of [ORIGINALTARGET_definite]
  • +
  • missed->passed within a meter of [ORIGINALTARGET_definite]
  • +
  • missed->was blown offcourse
  • + +
  • missing->missing
  • +
  • missing->missing by a small margin
  • +
  • missing->missing by a wide margin
  • +
  • missing->going wide
  • +
  • missing->flying into the air
  • +
  • missing->flying high into the air
  • +
  • missing->digging into the ground
  • +
  • missing->skipping off the ground and becoming lost
  • +
  • missing->digging a divot out of the ground
  • +
  • missing(p=0.2)->passing within millimeters of [ORIGINALTARGET_definite]
  • +
  • missing->passing within centimeters of [ORIGINALTARGET_definite]
  • +
  • missing->passing within a meter of [ORIGINALTARGET_definite]
  • +
  • missing->blowing offcourse
  • + +
  • avoidance(ORIGINALTARGET_mobile==True)->jerked aside at the last second
  • +
  • avoidance(ORIGINALTARGET_mobile==True)->stumbled in an attempt to escape
  • +
  • avoidance(ORIGINALTARGET_mobile==True)->threw [ORIGINALTARGET_objective]self to the ground
  • +
  • avoidance(ORIGINALTARGET_mobile==True,p=0.3)->ducked behind [COVER_definite]
  • +
  • avoidance(ORIGINALTARGET_mobile==True,p=0.3)->leaped behind [COVER_definite]
  • +
    +
    +
    + + +
    diff --git a/1.1+1.2/Defs/RulePackDefs/JT_GrappleRules.xml b/1.1+1.2/Defs/RulePackDefs/JT_GrappleRules.xml new file mode 100644 index 00000000..f0f93fdf --- /dev/null +++ b/1.1+1.2/Defs/RulePackDefs/JT_GrappleRules.xml @@ -0,0 +1,55 @@ + + + + JT_GrappleSuccess + +
  • Transition_Include
  • +
    + + +
  • r_logentry->[INITIATOR_nameDef] [grappled] [SUBJECT_definite].
  • + +
  • grappled->grappled
  • +
  • grappled->seized
  • +
  • grappled->took hold of
  • +
    +
    +
    + + + JT_GrappleFailed + +
  • Transition_Include
  • +
    + + +
  • r_logentry->[INITIATOR_nameDef] [triedtograpple] [SUBJECT_definite], [but] [failedmeta].
  • + +
  • tried->tried
  • +
  • tried->attempted
  • +
  • grappleinf->to grapple
  • +
  • grappleinf->to seize
  • +
  • grappleinf->to hold onto
  • +
  • triedtograpple->[tried] [grappleinf]
  • + +
  • but->but
  • +
  • but->however
  • +
  • but->even so
  • +
  • but->yet
  • + +
  • failed->failed
  • +
  • failed->missed
  • +
  • dodged->dodged
  • +
  • dodged->slipped away
  • +
  • spectacularly->spectacularly
  • +
  • spectacularly->miserably
  • +
  • spectacularly->completely
  • +
  • spectacularly->utterly
  • +
  • failedmeta->[INITIATOR_pronoun] [failed]
  • +
  • failedmeta->[INITIATOR_pronoun] [failed] [spectacularly]
  • +
  • failedmeta->[SUBJECT_definite] [dodged]
  • +
    +
    +
    + +
    diff --git a/1.1+1.2/Defs/Stats/CompDeflection_StatWorkers.xml b/1.1+1.2/Defs/Stats/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..9bc7b3b3 --- /dev/null +++ b/1.1+1.2/Defs/Stats/CompDeflection_StatWorkers.xml @@ -0,0 +1,18 @@ + + + + + MeleeWeapon_DeflectionChance + CompDeflector.StatWorker_DeflectionChance + + Chance to deflect ranged projectiles with melee weapon. + PawnCombat + 0 + 0 + 1 + PercentZero + 10 + true + + + \ No newline at end of file diff --git a/1.1+1.2/Defs/ThingDefs_Projectiles/JT_Projectiles.xml b/1.1+1.2/Defs/ThingDefs_Projectiles/JT_Projectiles.xml new file mode 100644 index 00000000..dc29ad63 --- /dev/null +++ b/1.1+1.2/Defs/ThingDefs_Projectiles/JT_Projectiles.xml @@ -0,0 +1,35 @@ + + + + + + Projectile + Normal + Projectile + Bullet + + False + True + + Transparent + + + + + + JT_FlyingObject + AbilityUser.FlyingObject + + + NullTex + Graphic_Single + + + true + Stun + 0 + 10 + + + + diff --git a/1.1+1.2/Defs/ThingDefs_Slots/CompSlotLoadable_Slots.xml b/1.1+1.2/Defs/ThingDefs_Slots/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..8f4c0ad0 --- /dev/null +++ b/1.1+1.2/Defs/ThingDefs_Slots/CompSlotLoadable_Slots.xml @@ -0,0 +1,15 @@ + + + + + SlotTest + CompSlotLoadable.SlotLoadable + + +
  • MeleeWeapon_Gladius
  • +
    + true + (255, 255, 255, 255) +
    + +
    diff --git a/1.1+1.2/Defs/ThingDefs_WeaponMelee/CompSlotLoadable_ThingDefExample b/1.1+1.2/Defs/ThingDefs_WeaponMelee/CompSlotLoadable_ThingDefExample new file mode 100644 index 00000000..08d6e4ed --- /dev/null +++ b/1.1+1.2/Defs/ThingDefs_WeaponMelee/CompSlotLoadable_ThingDefExample @@ -0,0 +1,138 @@ + + + + + + MeleeWeapon_TestKnife + + Never + 0 + 0 + One of humankind's oldest tools, the knife is both an everyday tool and a deadly weapon. + Normal + +
  • + +
  • SlotTest
  • + + +
    +
    + + + + Things/Item/Equipment/WeaponMelee/Knife + Graphic_Single + + InteractAutopistol + 40 + + 4000 + 0.5 + + -65 + +
  • Metallic
  • +
    + +
  • + + +
  • Blunt
  • + + 6 + 2.5 + +
  • + + +
  • Stab
  • + + 16 + 2.5 + +
  • + + +
  • Cut
  • + + 21 + 2.5 + +
    +
    + + + + + ThingWithComps + Item + true + Item + true + Never + Primary + true + 10 + true + Never + + 100 + 1.0 + 2 + 1 + -6 + 0.20 + + +
  • +
  • + CompEquippable +
  • +
    + + 35 + +
    + + + Industrial + true + +
  • Melee
  • +
    + +
  • WeaponsMelee
  • +
    + +
  • + CompQuality +
  • +
  • + ArtName_WeaponMelee + ArtDescription_WeaponMelee + Excellent +
  • +
    + +
  • ITab_Art
  • +
    +
    + + + + + +
  • Root
  • +
    + +
  • Silver
  • +
  • Gold
  • +
  • WoodLog
  • +
    +
    +
    +
    + + +
    diff --git a/1.1+1.2/Defs/ThinkTreeDefs/CompVehicles_ThinkTree.xml b/1.1+1.2/Defs/ThinkTreeDefs/CompVehicles_ThinkTree.xml new file mode 100644 index 00000000..53be174a --- /dev/null +++ b/1.1+1.2/Defs/ThinkTreeDefs/CompVehicles_ThinkTree.xml @@ -0,0 +1,126 @@ + + + + + + + + CompVehicle_Simple + + +
  • + Downed +
  • +
  • + LordDuty +
  • +
  • + Idle +
  • +
  • + + +
  • + +
  • + DraftedOrder + +
  • + +
  • +
    + + + +
  • + JoinAutoJoinableCaravan +
  • + + + +
  • + Fieldwork + +
  • + +
  • + + +
  • + +
  • + UnloadingOwnInventory + +
  • + +
  • + + + + +
  • + +
  • + Misc + +
  • + +
  • + + +
  • + + +
  • + +
  • + Misc + +
  • + Walk +
  • + + + + + + +
  • + LordDuty +
  • + + +
  • + Idle + +
  • + +
  • + +
  • + + + + + + + CompVehicle_SimpleConstant + + +
  • + + + +
  • + + +
  • + LordDutyConstant +
  • + + + +
    +
    + +
    diff --git a/1.1+1.2/Defs/ThinkTreeDefs/InsertHook_AbilityUserAI.xml b/1.1+1.2/Defs/ThinkTreeDefs/InsertHook_AbilityUserAI.xml new file mode 100644 index 00000000..dbea8898 --- /dev/null +++ b/1.1+1.2/Defs/ThinkTreeDefs/InsertHook_AbilityUserAI.xml @@ -0,0 +1,15 @@ + + + + + InsertHookTest + Humanlike_PostMentalState + 1000 + + true + +
  • + + + + \ No newline at end of file diff --git a/1.1+1.2/Defs/WorldObjectDefs/WorldObjects.xml b/1.1+1.2/Defs/WorldObjectDefs/WorldObjects.xml new file mode 100644 index 00000000..eaeee9ce --- /dev/null +++ b/1.1+1.2/Defs/WorldObjectDefs/WorldObjects.xml @@ -0,0 +1,19 @@ + + + + + WorldObject_ProgressBar + + true + This should not be visible to players. + JecsTools.WorldObject_ProgressBar + World/WorldObjects/TribalFactionBase + true + World/WorldObjects/Expanding/RoutePlannerWaypoint + 1 + true + false + false + + + diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..ad77ae87 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,8 @@ + + + + 灼伤(光剑) + {0}被击毙了。 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..8d26f05d --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,8 @@ + + + + 使用原力技 + 使用原力技 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompDeflector_Jobs.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompDeflector_Jobs.xml new file mode 100644 index 00000000..67ca2bd1 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompDeflector_Jobs.xml @@ -0,0 +1,7 @@ + + + + 偏转了 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompInstalledPart_Jobs.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..b704c3e8 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompInstalledPart_Jobs.xml @@ -0,0 +1,8 @@ + + + + 安装TargetA。 + 卸载TargetA。 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompSlotLoadable_Jobs.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..dafa94e2 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompSlotLoadable_Jobs.xml @@ -0,0 +1,7 @@ + + + + 装备TargetA。 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompVehicle_Jobs.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompVehicle_Jobs.xml new file mode 100644 index 00000000..ef16a564 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/JobDef/CompVehicle_Jobs.xml @@ -0,0 +1,8 @@ + + + + 搭载TargetA。 + 装配TargetA。 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/RecipeDef/Recipes_Add_Make.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/RecipeDef/Recipes_Add_Make.xml new file mode 100644 index 00000000..30b216a8 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/RecipeDef/Recipes_Add_Make.xml @@ -0,0 +1,14 @@ + + + + + + + + + 打造[SW]开槽刀 + 打造一把开槽刀。 + 正在打造开槽刀中。 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/StatDef/CompDeflection_StatWorkers.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/StatDef/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..f670f100 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/StatDef/CompDeflection_StatWorkers.xml @@ -0,0 +1,8 @@ + + + + 偏转几率 + 以近战武器偏转远程抛射物的几率。 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_Slots.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..bf4304e2 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_Slots.xml @@ -0,0 +1,7 @@ + + + + 测试 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml new file mode 100644 index 00000000..36d751d1 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml @@ -0,0 +1,8 @@ + + + + [SW]开槽刀 + 一件人类早期使用的原始工具,既可以当日常工具也可以当武器使用。 + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/DefInjected/WorldObjectDef/WorldObjects.xml b/1.1+1.2/Languages/ChineseSimplified/DefInjected/WorldObjectDef/WorldObjects.xml new file mode 100644 index 00000000..6943461d --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/DefInjected/WorldObjectDef/WorldObjects.xml @@ -0,0 +1,8 @@ + + + + progress bar + This should not be visible to players. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/Keyed/AbilityUser.xml b/1.1+1.2/Languages/ChineseSimplified/Keyed/AbilityUser.xml new file mode 100644 index 00000000..f344b80a --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/Keyed/AbilityUser.xml @@ -0,0 +1,25 @@ + + + + 禁用 + + 类型: + 有效范围 + 以自己为目标 + 以其他为目标 + 目标位置 + 冷却: + 附加 + 精神影响几率 + 影响几率 + {0}需要时间恢复能量 + + + 有效范围属性 + 目标: + 角色 + 误伤: + 最大目标数: + 从施法者开始: + + diff --git a/1.1+1.2/Languages/ChineseSimplified/Keyed/CompActivatableEffect.xml b/1.1+1.2/Languages/ChineseSimplified/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..20831c8f --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + 警告:{0}当前装备武器是无效的! + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/Keyed/CompDeflector.xml b/1.1+1.2/Languages/ChineseSimplified/Keyed/CompDeflector.xml new file mode 100644 index 00000000..a9cd358f --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/Keyed/CompDeflector.xml @@ -0,0 +1,19 @@ + + + + 没有配备导流板 + + 偏转几率 + 决定该武器反射袭击者的抛射物或子弹的偏转几率。 + + 最大偏转几率 + 每点{0}技能能提供角色{1}的反射目标抛射物的偏转几率。理论上最大的偏转几率为{2}。 + + 每点{0}技能增加的偏转百分比 + 每点{0}技能提供角的偏转抛射物的几率。 + + 偏转几率=(基础偏转几率+(原力等级*每级加成))×操作能力 + 基础偏转几率 + 每点技能增加的偏转百分比 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/ChineseSimplified/Keyed/CompInstalledPart.xml b/1.1+1.2/Languages/ChineseSimplified/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..b3fa95f5 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + + 安装在{2}上 + 卸下{0} + {0}将{1}安装在{2}上 + {0}将{1}从{2}上卸下 + + diff --git a/1.1+1.2/Languages/ChineseSimplified/Keyed/CompVehicle.xml b/1.1+1.2/Languages/ChineseSimplified/Keyed/CompVehicle.xml new file mode 100644 index 00000000..f895e1e7 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/Keyed/CompVehicle.xml @@ -0,0 +1,33 @@ + + + + + 殖民者在载具中无法和商队交易。 + + + + {0}{0}当前无法移动。 + + + + 燃料告急 + {0}的燃料({1})即将耗尽。{0}的行进速度将降低四分之三。 + {0}由于需要{2}而离开了载具({1})。 + 携带了可用{0}天的燃料 + 完全不用担心燃料耗尽 + 燃料消耗预计\n\n一个考虑到所有商队载具的燃料消耗和最坏情况影响的预算天数,这意味着超过预计天数之后你的商队将出现载具燃料紧张的情况。 + 你的商队没有携带任何燃料,行进速度将大大降低。\n\n你确定要组织这次行商? + 你的商队只携带了可用{0}天的燃料,可能不足以支撑这次的消耗。\n\n你确定要组织这次行商? + 燃料耗尽 + 商队载具必须装满油。 + + 载具 + 搭载/卸载{0} + 卸载{0} + 搭载{0} + 搭载或强行卸载{0}。 + 搭载一名{0} + 卸载一名{{0} + 载具由于被禁用,被摧毁,或损伤严重而无法装载。 + + diff --git a/1.1+1.2/Languages/ChineseSimplified/Keyed/Eng_WorldObjectMods.xml b/1.1+1.2/Languages/ChineseSimplified/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..e3666220 --- /dev/null +++ b/1.1+1.2/Languages/ChineseSimplified/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,8 @@ + + + + 该位置没有可交易的商队 + 资源:{0} + 失败。需要材料{0}:{1} 。 + + diff --git a/1.1+1.2/Languages/English/Keyed/AbilityUser.xml b/1.1+1.2/Languages/English/Keyed/AbilityUser.xml new file mode 100644 index 00000000..1e3b7cd6 --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/AbilityUser.xml @@ -0,0 +1,29 @@ + + + +No line of sight + +No targets available + +DISABLED + +Type: +Area of Effect +Targets Self +Targets Other +Targets Location +Cooldown: +Extra +Mental State Chance +Effect Chance +{0} needs time to recharge + + +Area of Effect Properties +Targets: +Characters +Friendly Fire: +Max Targets: +Starts from caster: + + diff --git a/1.1+1.2/Languages/English/Keyed/CompActivatableEffect.xml b/1.1+1.2/Languages/English/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..3142c3bf --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + WARNING: {0}'s current weapon is deactivated! + + \ No newline at end of file diff --git a/1.1+1.2/Languages/English/Keyed/CompDeflector.xml b/1.1+1.2/Languages/English/Keyed/CompDeflector.xml new file mode 100644 index 00000000..2051f04d --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/CompDeflector.xml @@ -0,0 +1,20 @@ + + + + No deflector equipped + + Deflect chance + Determines how often this weapon returns projectiles back at the attacker. + + Max deflect chance + For each point in {0}, the user gains a {1} chance of deflecting the projectile back the target. {2} is the maximum possible deflection chance. + + + Deflect % per {0} skill + For each level in {0}, the user gains this much % chance to deflect a projectile. + + Deflection chance = (Base deflect chance + (Skill Level * % per Skill Level)) * Manipulation + Base deflect chance + Deflect % per skill level + + \ No newline at end of file diff --git a/1.1+1.2/Languages/English/Keyed/CompInstalledPart.xml b/1.1+1.2/Languages/English/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..fa0df1f3 --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + +Install on something +Uninstall {0} +{0} installed the {1} onto {2} +{0} uninstalled the {1} from {2} + + diff --git a/1.1+1.2/Languages/English/Keyed/CompShield.xml b/1.1+1.2/Languages/English/Keyed/CompShield.xml new file mode 100644 index 00000000..ad7bf608 --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/CompShield.xml @@ -0,0 +1,18 @@ + + + + no shield equipped + + shield never blocks melee attacks + shield never blocks ranged attacks + shield never absorbs damage from a blocked attack + + Discard threshold + The hit points percentage threshold when the shield is automatically discarded by the wielder + shield is never automatically discarded by the wielder + + Damage to fatigue factor + How much percent of the damage is converted to fatigue damage on a blocked attack. + shield wielder never gets fatigued from a blocked attack + + \ No newline at end of file diff --git a/1.1+1.2/Languages/English/Keyed/CompVehicle.xml b/1.1+1.2/Languages/English/Keyed/CompVehicle.xml new file mode 100644 index 00000000..f547976a --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/CompVehicle.xml @@ -0,0 +1,33 @@ + + + + + Cannot split caravan while colonists are in vehicles. + + + + {0} is currently incapable of movement. + + + + Low Fuel + {0} has run out of fuel ({1}). {0} will now move at a quarter of normal speed. + {0} has left the vehicle ({1}) due to {2} needs. + Carrying {0} days worth of fuel +Will never run out of fuel + An approximate number of days before the caravan runs out of fuel.\n\nThis takes into account all vehicles in the caravan and shows the worst case scenario. This means that after this many days, at least one vehicle will be out of fuel. + Your caravan isn't carrying fuel and will be unable to travel at full speed.\n\nAre you sure you want to form this caravan? + Your caravan is only carrying {0} days worth of fuel and will run out of fuel very quickly.\n\nAre you sure you want to form this caravan? + Out of fuel + Vehicles in the caravan must be fueled. + +Vehicles +Load/Unload {0} +Unload {0} +Load {0} +Load or eject one {0}. +Load one {0} +Unload one {0} +The vehicle disabled, destroyed, or simply too damaged and cannot be loaded. + + diff --git a/1.1+1.2/Languages/English/Keyed/Eng_WorldObjectMods.xml b/1.1+1.2/Languages/English/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..ff1c8a5f --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,9 @@ + + + +because no caravan is available at this location +Resources: {0} +Missing Specific Items. Need {1}x {2}, have only {0} +Missing {2} Stuff. Need {1}x, have only {0} +Failed to build {0} due to lack of resources + diff --git a/1.1+1.2/Languages/English/Keyed/Grapple.xml b/1.1+1.2/Languages/English/Keyed/Grapple.xml new file mode 100644 index 00000000..10f65ea4 --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/Grapple.xml @@ -0,0 +1,11 @@ + + + +Grapple Success +Grapple Failed +Downed Attack: Grapple Success +Sneak Attack: Grapple Success +Restrained Victim: Grapple Success +Sleeping Victim: Grapple Success + + diff --git a/1.1+1.2/Languages/English/Keyed/Misc.xml b/1.1+1.2/Languages/English/Keyed/Misc.xml new file mode 100644 index 00000000..2a10068e --- /dev/null +++ b/1.1+1.2/Languages/English/Keyed/Misc.xml @@ -0,0 +1,10 @@ + + +Must be placed under a ceiling. +Must be placed on a wall. +{0} absorbed +Soak Amount: {0} +Knockback Chance: {0} +Extra Damages: +Explosive + diff --git a/1.1+1.2/Languages/French/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.1+1.2/Languages/French/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..ccff4a2d --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,8 @@ + + + + brûlé + {0} a été abattu + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.1+1.2/Languages/French/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..96c0d2e5 --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,8 @@ + + + + utiliser une capacité + utilise une capacité + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/JobDef/CompDeflector_Jobs.xml b/1.1+1.2/Languages/French/DefInjected/JobDef/CompDeflector_Jobs.xml new file mode 100644 index 00000000..33627009 --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/JobDef/CompDeflector_Jobs.xml @@ -0,0 +1,7 @@ + + + + renvoit + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/JobDef/CompInstalledPart_Jobs.xml b/1.1+1.2/Languages/French/DefInjected/JobDef/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..543ab396 --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/JobDef/CompInstalledPart_Jobs.xml @@ -0,0 +1,8 @@ + + + + installe TargetA. + désinstalle TargetA. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/JobDef/CompSlotLoadable_Jobs.xml b/1.1+1.2/Languages/French/DefInjected/JobDef/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..e09b3bf3 --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/JobDef/CompSlotLoadable_Jobs.xml @@ -0,0 +1,7 @@ + + + + équipe TargetA. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/JobDef/CompVehicle_Jobs.xml b/1.1+1.2/Languages/French/DefInjected/JobDef/CompVehicle_Jobs.xml new file mode 100644 index 00000000..9b73e508 --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/JobDef/CompVehicle_Jobs.xml @@ -0,0 +1,8 @@ + + + + entre dans TargetA. + assemble TargetA. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/RecipeDef/Recipes_Add_Make.xml b/1.1+1.2/Languages/French/DefInjected/RecipeDef/Recipes_Add_Make.xml new file mode 100644 index 00000000..14bb1bd4 --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/RecipeDef/Recipes_Add_Make.xml @@ -0,0 +1,14 @@ + + + + + + + + + faire un couteau d'entraînement + faire un couteau d'entraînement + fait un couteau d'entraînement + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/StatDef/CompDeflection_StatWorkers.xml b/1.1+1.2/Languages/French/DefInjected/StatDef/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..cc66a243 --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/StatDef/CompDeflection_StatWorkers.xml @@ -0,0 +1,8 @@ + + + + chance de renvoi + Chance de dévier des projectiles à distance avec une arme de mêlée + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/ThingDef/CompSlotLoadable_Slots.xml b/1.1+1.2/Languages/French/DefInjected/ThingDef/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..73ce1273 --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/ThingDef/CompSlotLoadable_Slots.xml @@ -0,0 +1,7 @@ + + + + test + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml b/1.1+1.2/Languages/French/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml new file mode 100644 index 00000000..027fc41f --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml @@ -0,0 +1,8 @@ + + + + [SW]Couteau d'entraînement + Outil primitif utilisé par l'humanité à ses débuts, il peut être utilisé comme outil quotidien ou comme arme. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/DefInjected/WorldObjectDef/WorldObjects.xml b/1.1+1.2/Languages/French/DefInjected/WorldObjectDef/WorldObjects.xml new file mode 100644 index 00000000..ed041cfe --- /dev/null +++ b/1.1+1.2/Languages/French/DefInjected/WorldObjectDef/WorldObjects.xml @@ -0,0 +1,8 @@ + + + + barre de progression + Cela ne devrait pas être visible pour les joueurs. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/Keyed/AbilityUser.xml b/1.1+1.2/Languages/French/Keyed/AbilityUser.xml new file mode 100644 index 00000000..7da0f2ca --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/AbilityUser.xml @@ -0,0 +1,25 @@ + + + +DISABLED + +Type: +Zone d'effet +Cibler (moi) +Cibler (autres) +Emplacement de la cible +Recharge: +Extra +probabilit d'tat mental +probabilit d'effet +{0} a besoin de temps pour recharger + + +Proprits de la zone d'effet +Cibles: +Personnages +Tir amie: +Nombre de cibles maximal: +Se dclenche a partir du sorcier: + + diff --git a/1.1+1.2/Languages/French/Keyed/CompActivatableEffect.xml b/1.1+1.2/Languages/French/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..845d8675 --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + Attention: L'arme de {0} est dsactive! + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/Keyed/CompDeflector.xml b/1.1+1.2/Languages/French/Keyed/CompDeflector.xml new file mode 100644 index 00000000..364534f5 --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/CompDeflector.xml @@ -0,0 +1,20 @@ + + + + Aucun déflecteur équipé + + probabilité de renvoyer + Détermine à quelle fréquence cette arme renvoie des projectiles à l'agresseur. + + Probabilité maximale de renvoi + Pour chaque point {0}, l'utilisateur a une probabilité de détourner le tir de {1}. La probabilité maximale de renvoi est de {2}. + + + Détournement % par {0} compétence + Pour chaque niveau en {0}, l'utilisateur gagne tel % de probabilité de renvoyer un projectile. + + Probabilité de détournement = (probabilité de détournement + (Niveau * % par Niveau)) * Manipulation + Probabilité de renvoi de base + Renvoit % par Niveau + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/Keyed/CompInstalledPart.xml b/1.1+1.2/Languages/French/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..3e9dabcd --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + +Installer sur quelque chose +Retirer {0} +{0} a install {1} sur {2} +{0} a retir {1} de {2} + + diff --git a/1.1+1.2/Languages/French/Keyed/CompShield.xml b/1.1+1.2/Languages/French/Keyed/CompShield.xml new file mode 100644 index 00000000..7dcd3f87 --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/CompShield.xml @@ -0,0 +1,18 @@ + + + + pas de bouclier équipé + + le bouclier ne bloque jamais les attaques de mêlée + le bouclier ne bloque jamais les attaques à distance + le bouclier n'absorbe jamais les dégâts d'une attaque bloquée + + Seuil de défausse + Le seuil de pourcentage de points de vie nécessaire pour que le bouclier soit automatiquement défaussé par le porteur + Le bouclier n'est jamais automatiquement rejeté par le porteur + + Facteur de dommages de fatigue + Quel pourcentage des dégâts est converti en dégâts de fatigue lors d'une attaque bloquée. + Le porteur du bouclier ne se fatigue jamais d'une attaque bloquée + + \ No newline at end of file diff --git a/1.1+1.2/Languages/French/Keyed/CompVehicle.xml b/1.1+1.2/Languages/French/Keyed/CompVehicle.xml new file mode 100644 index 00000000..96a3c536 --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/CompVehicle.xml @@ -0,0 +1,33 @@ + + + + + Impossible de diviser le convoi lorsque des colons se trouvent dans des vhicules. + + + + {0} est immobilis en ce moment. + + + + Le niveau de carburant est bas + {0} est court de carburant ({1}). {0} avancera dornavant 25% de sa vitesse normale. + {0} a quitt le vhicule ({1}) d au besoin de {2}. + {0} jours de carburant restants +Ne sera jamais court de carburant + Estimation du nombre de jours restant avant que le convoi soit court de carburant.\n\nCeci prend en compte tous les vhicules faisant partie du convoi et montre le pire scnario possible. Ceci veut dire qu'aprs ce nombre de jours, au moins un vhicule sera court de carburant. + Votre convoi ne transporte pas de carburant et sera donc incapable de se dplacer sa vitesse maximale.\n\nEtes vous sr de vouloir former ce convoi? + Votre convoi ne transporte que {0} jours d'autonomie en carburant et sera court de carburant trs vite.\n\nEtes vous sr que vous voulez former ce convoi? + A court de carburant + + +Vhicules +Charger / dcharger {0} +Dcharger {0} +Embarquer {0} +Embarquer ou jecter {0}. +Embarquez un {0} +Dcharger {0} +Ce vhicule est neutralis, dtruit ou simplement trop endommag et ne peut pas tre embarqu. + + diff --git a/1.1+1.2/Languages/French/Keyed/Eng_WorldObjectMods.xml b/1.1+1.2/Languages/French/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..4c5b9b13 --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,8 @@ + + + +car aucun convoi n'est prsent cet endroit +Ressources: {0} +chou construire {0} en raison d'un manque de ressources. + + diff --git a/1.1+1.2/Languages/French/Keyed/Grapple.xml b/1.1+1.2/Languages/French/Keyed/Grapple.xml new file mode 100644 index 00000000..3596c7fd --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/Grapple.xml @@ -0,0 +1,11 @@ + + + +Succès du grappin +Echec du grappin +Attaque abattue: succès du grappin +Attaque furtive: succès du grappin +Victime retenue: succès du grappin +Victime endormie: succès du grappin + + diff --git a/1.1+1.2/Languages/French/Keyed/Misc.xml b/1.1+1.2/Languages/French/Keyed/Misc.xml new file mode 100644 index 00000000..30aba2a1 --- /dev/null +++ b/1.1+1.2/Languages/French/Keyed/Misc.xml @@ -0,0 +1,10 @@ + + +Doit être placé sous un plafond. +Doit être placé sur un mur. +{0} absorbé +Quantité de trempage: {0} +Chance de recul: {0} +Dégâts supplémentaires: +Explosif + diff --git a/1.1+1.2/Languages/Japanese/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.1+1.2/Languages/Japanese/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..2fb18e0d --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,7 @@ + + + + 火傷 + {0}はレーザーに焼かれて死んだ。 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/HediffDef/Shields.xml b/1.1+1.2/Languages/Japanese/DefInjected/HediffDef/Shields.xml new file mode 100644 index 00000000..3c37f56f --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/HediffDef/Shields.xml @@ -0,0 +1,12 @@ + + + + + + シールド損耗 + 少し + かなり + 厳しい + 枯渇 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..4f4d3f89 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,7 @@ + + + + 能力を使用中 + 能力を使用中 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompDeflector_Jobs.xml b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompDeflector_Jobs.xml new file mode 100644 index 00000000..07662d64 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompDeflector_Jobs.xml @@ -0,0 +1,6 @@ + + + + 逸らしている + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompInstalledPart_Jobs.xml b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..753833c7 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompInstalledPart_Jobs.xml @@ -0,0 +1,7 @@ + + + + TargetAを装着中 + TargetAを取り外し中 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompSlotLoadable_Jobs.xml b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..9534d0cd --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompSlotLoadable_Jobs.xml @@ -0,0 +1,6 @@ + + + + TargetAをスロットに装着中 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompVehicle_Jobs.xml b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompVehicle_Jobs.xml new file mode 100644 index 00000000..9d316c70 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/JobDef/CompVehicle_Jobs.xml @@ -0,0 +1,7 @@ + + + + TargetAに乗り込む + TargetAを組み立てる + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/RulePackDef/JT_GrappleRules.xml b/1.1+1.2/Languages/Japanese/DefInjected/RulePackDef/JT_GrappleRules.xml new file mode 100644 index 00000000..0e83ea9d --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/RulePackDef/JT_GrappleRules.xml @@ -0,0 +1,32 @@ + + + + r_logentry->[INITIATOR_nameDef]は、[SUBJECT_definite][grappled]。 + grappled->と取っ組み合った + grappled->を抑えつけた + grappled->を手で掴みました + + r_logentry->[INITIATOR_nameDef]は、[SUBJECT_definite]を[triedtograpple]、[but][failedmeta]。 + tried->試みた + tried->attempted + grappleinf->捕まえようと + grappleinf->捕らえようと + grappleinf->抑えつけようと + triedtograpple->[grappleinf][tried]が + but->しかし + but->またしても + but->それでも + but->すでに + failed->失敗しました + failed->逃げられました + dodged->避けました + dodged->外しました + spectacularly->見事に + spectacularly->無様に + spectacularly->完全に + spectacularly->ことごとく + failedmeta->[INITIATOR_pronoun]は[failed] + failedmeta->[INITIATOR_pronoun]は[spectacularly][failed] + failedmeta->[SUBJECT_definite]は[dodged] + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/StatCategoryDef/Shields.xml b/1.1+1.2/Languages/Japanese/DefInjected/StatCategoryDef/Shields.xml new file mode 100644 index 00000000..099e37f5 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/StatCategoryDef/Shields.xml @@ -0,0 +1,6 @@ + + + + シールド + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/StatDef/CompDeflection_StatWorkers.xml b/1.1+1.2/Languages/Japanese/DefInjected/StatDef/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..8def147d --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/StatDef/CompDeflection_StatWorkers.xml @@ -0,0 +1,7 @@ + + + + 逸らす確率 + 近距離武器で遠距離攻撃の発射物を逸らす確率 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/StatDef/Shields.xml b/1.1+1.2/Languages/Japanese/DefInjected/StatDef/Shields.xml new file mode 100644 index 00000000..595ebda9 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/StatDef/Shields.xml @@ -0,0 +1,25 @@ + + + + 近接防御補正 + シールドを構えた者の近接攻撃を防ぐ確率はこの値で補正乗算されます。より高いほど防御率が高い。 + + 遠距離防御補正 + シールドを構えた者の遠距離攻撃を防ぐ確率はこの値で補正乗算されます。より高いほど防御率が高い。 + + ダメージ吸収 + 防御した攻撃からシールドがどれだけのダメージを吸収できるか。 + + + + + 近接防御率 + 近接攻撃を阻止する確立で、失敗すると攻撃が命中します。 + + + + + 遠距離防御率 + 遠距離攻撃を阻止する確立で、失敗すると攻撃が命中します。 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/ThingDef/CompSlotLoadable_Slots.xml b/1.1+1.2/Languages/Japanese/DefInjected/ThingDef/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..f0c19f89 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/ThingDef/CompSlotLoadable_Slots.xml @@ -0,0 +1,6 @@ + + + + テスト + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/ThingDef/JT_Projectiles.xml b/1.1+1.2/Languages/Japanese/DefInjected/ThingDef/JT_Projectiles.xml new file mode 100644 index 00000000..ebe7213a --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/ThingDef/JT_Projectiles.xml @@ -0,0 +1,6 @@ + + + + 飛翔体 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/DefInjected/WorldObjectDef/WorldObjects.xml b/1.1+1.2/Languages/Japanese/DefInjected/WorldObjectDef/WorldObjects.xml new file mode 100644 index 00000000..f17fe8e5 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/DefInjected/WorldObjectDef/WorldObjects.xml @@ -0,0 +1,7 @@ + + + + 進展度 + これはプレーヤーには見えないはずです。 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/Keyed/AbilityUser.xml b/1.1+1.2/Languages/Japanese/Keyed/AbilityUser.xml new file mode 100644 index 00000000..4713458f --- /dev/null +++ b/1.1+1.2/Languages/Japanese/Keyed/AbilityUser.xml @@ -0,0 +1,27 @@ + + + + 指定可能な目標がありません。 + + 機能停止 + + タイプ: + 目標(範囲) + 目標(自分) + 目標(他者) + 目標(場所) + クールダウン: + 特殊 + 精神状態変化率 + 影響確率 + {0}は回復する時間が必要 + + + 影響範囲の詳細 + 目標: + キャラクター + 味方への誤射: + 最大目標数: + 使用者から開始: + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/Keyed/CompActivatableEffect.xml b/1.1+1.2/Languages/Japanese/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..5bf0cc6d --- /dev/null +++ b/1.1+1.2/Languages/Japanese/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + 警告:{0}の現在所持している武器は不活性です! + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/Keyed/CompDeflector.xml b/1.1+1.2/Languages/Japanese/Keyed/CompDeflector.xml new file mode 100644 index 00000000..bf49557f --- /dev/null +++ b/1.1+1.2/Languages/Japanese/Keyed/CompDeflector.xml @@ -0,0 +1,19 @@ + + + + デフレクターなし + + 反射率 + この武器が発射体を攻撃者に跳ね返す頻度を決定します。 + + 最大反射率 + {0}ヵ所の各射撃地点に対して、使用者は攻撃してきた目標に対して発射された攻撃を反射する可能性が{1}回あります。反射可能な最大回数は{2}回です。 + + {0}スキルLv毎の反射率(%) + 使用者は{0}の各レベルごとに、この反射率(%)を加算して発射体を跳ね返すことができます。 + + 反射率=(基本反射率+(スキルレベル×スキルLvごとの反射率(%)))×指の機能 + 基本反射率 + スキルLvごとの反射率(%) + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/Keyed/CompInstalledPart.xml b/1.1+1.2/Languages/Japanese/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..f3783cb8 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + + 何かを装着します + {0}を取り外す + {0}は{2}に{1}を装着しました + {0}は{2}から{1}を取り外しました + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/Keyed/CompVehicle.xml b/1.1+1.2/Languages/Japanese/Keyed/CompVehicle.xml new file mode 100644 index 00000000..730bcef9 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/Keyed/CompVehicle.xml @@ -0,0 +1,33 @@ + + + + + 入植者が乗り物に乗車している間は、キャラバン隊を分割することはできません。 + + + + {0}は現在移動できません。 + + + + 燃料が残り少ない + {0}の燃料が不足しています({1})。 {0}は現在、通常速度の4分の1で移動しています。 + {0}には{2}が必要なので、車両({1})を降りました。 + {0}日分の燃料を積んでいます + 燃料が足りなくなることは無いでしょう + このキャラバン隊の燃料がなくなるまでのおよその日数です。\n\nキャラバン隊に属するすべての車両を考慮して、最悪の場合のシナリオを示します。 これは、この日数が経過した後、少なくとも1台の車両が燃料切れになることを意味します。 + このキャラバン隊は燃料を搭載しておらず、最高速度で移動することができません。\n\nこのキャラバン隊を編成してもよろしいですか? + このキャラバン隊は{0}日分の燃料しか運んでおらず、すぐに燃料が枯渇します。\n\nこのままキャラバン隊を編成しますか? + 燃料切れ + キャラバン隊の乗り物に燃料を供給する必要があります。 + + 乗り物 + {0}を積み下ろす + {0}を下ろす + {0}を積む + {0}を載せるか1つ取り出します。 + {0}を1つ積み込む + {0}を1つ取り出す + 乗り物が無効になっているか、破壊されているか、または単に損傷しており、荷物を搭載できません。 + + diff --git a/1.1+1.2/Languages/Japanese/Keyed/Eng_WorldObjectMods.xml b/1.1+1.2/Languages/Japanese/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..57c5c404 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,10 @@ + + + + この場所にキャラバン隊がありません + 必要な資源:{0} + 特定のアイテムが足りません。{2}が{1}が必要ですが、{0}しかありません + {2}が不足しています。{1}が{1}が必要ですが、{0}しかありません + 資源不足のために、{0}の建設に失敗しました + + diff --git a/1.1+1.2/Languages/Japanese/Keyed/Grapple.xml b/1.1+1.2/Languages/Japanese/Keyed/Grapple.xml new file mode 100644 index 00000000..986a776d --- /dev/null +++ b/1.1+1.2/Languages/Japanese/Keyed/Grapple.xml @@ -0,0 +1,11 @@ + + + + 捕縛に成功 + 捕縛に失敗 + 倒れている相手:捕縛に成功 + 奇襲攻撃の相手:捕縛に成功 + 拘束中の相手:捕縛に成功 + 睡眠中の相手:捕縛に成功 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/Keyed/Misc.xml b/1.1+1.2/Languages/Japanese/Keyed/Misc.xml new file mode 100644 index 00000000..012588fb --- /dev/null +++ b/1.1+1.2/Languages/Japanese/Keyed/Misc.xml @@ -0,0 +1,11 @@ + + + 天井の下に置く必要があります。 + 壁に置く必要があります。 + {0}ダメージ吸収した + 貫通量:{0} + ノックバック率:{0} + 追加ダメージ: + 炸裂 + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Japanese/LanguageInfo.xml b/1.1+1.2/Languages/Japanese/LanguageInfo.xml new file mode 100644 index 00000000..d74dc636 --- /dev/null +++ b/1.1+1.2/Languages/Japanese/LanguageInfo.xml @@ -0,0 +1,13 @@ + + + 日本語 + Japanese + true + LanguageWorker_Japanese + +
  • + Translator + Proxyer +
  • + + diff --git a/1.1+1.2/Languages/Spanish/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.1+1.2/Languages/Spanish/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..57fca9f6 --- /dev/null +++ b/1.1+1.2/Languages/Spanish/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,8 @@ + + + + Quemadura + {0} Fue fusilado por armas laser. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Spanish/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.1+1.2/Languages/Spanish/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..5ce0b377 --- /dev/null +++ b/1.1+1.2/Languages/Spanish/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,8 @@ + + + + Usando una abilidad + Usando una abilidad + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/Spanish/Keyed/AbilityUser.xml b/1.1+1.2/Languages/Spanish/Keyed/AbilityUser.xml new file mode 100644 index 00000000..9085a1a7 --- /dev/null +++ b/1.1+1.2/Languages/Spanish/Keyed/AbilityUser.xml @@ -0,0 +1,25 @@ + + + +DISABLED + +Type: +Area de efecto +Concentar en ti mismo +Concentar en otro +Localizacion del objetivo +Cooldown: +Extra +Chance de Estado Mental +Chance de efecto +{0} Necesita tiempo para recargar + + +Propiedades del Area de Efecto +Objetivos: +Personajes +Fuego Amigo: +Max Targets: +Empieza desde el caster: + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..5a92f877 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,8 @@ + + + + quemadura + {0} fue disparado hasta morir. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..30592e33 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,8 @@ + + + + Usando una habilidad + Usando una habilidad + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompDeflector_Jobs.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompDeflector_Jobs.xml new file mode 100644 index 00000000..daff1817 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompDeflector_Jobs.xml @@ -0,0 +1,7 @@ + + + + Desviando + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompInstalledPart_Jobs.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..1aa92b6c --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompInstalledPart_Jobs.xml @@ -0,0 +1,8 @@ + + + + instalando TargetA. + desinstalando TargetA. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompSlotLoadable_Jobs.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..c43a6051 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompSlotLoadable_Jobs.xml @@ -0,0 +1,7 @@ + + + + equipando TargetA. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompVehicle_Jobs.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompVehicle_Jobs.xml new file mode 100644 index 00000000..3568e001 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/JobDef/CompVehicle_Jobs.xml @@ -0,0 +1,8 @@ + + + + entrando a TargetA. + montando TargetA. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/RulePackDef/JT_GrappleRules.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/RulePackDef/JT_GrappleRules.xml new file mode 100644 index 00000000..3512ff9d --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/RulePackDef/JT_GrappleRules.xml @@ -0,0 +1,33 @@ + + + + r_logentry->[INITIATOR_nameDef] [grappled] [SUBJECT_definite] with [SUBJECT_possessive] [culpritHediff_originaltarget_label]. + grappled->grappled + grappled->seized + grappled->took hold of + + r_logentry->[INITIATOR_nameDef] [triedtograpple] [SUBJECT_definite] with [SUBJECT_possessive] [culpritHediff_originaltarget_label], [but] [failedmeta]. + tried->tried + tried->attempted + grappleinf->to grapple + grappleinf->to seize + grappleinf->to hold onto + triedtograpple->[tried] [grappleinf] + but->but + but->however + but->even so + but->yet + failed->failed + failed->missed + dodged->dodged + dodged->slipped away + spectacularly->spectacularly + spectacularly->miserably + spectacularly->completely + spectacularly->utterly + failedmeta->[INITIATOR_pronoun] [failed] + failedmeta->[INITIATOR_pronoun] [failed] [spectacularly] + failedmeta->[SUBJECT_definite] [dodged] + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/StatDef/CompDeflection_StatWorkers.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/StatDef/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..637577a5 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/StatDef/CompDeflection_StatWorkers.xml @@ -0,0 +1,8 @@ + + + + chance de desvío + Chance de desviar un proyectil de rango largo con una arma. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/ThingDef/CompSlotLoadable_Slots.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/ThingDef/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..bdfa1aee --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/ThingDef/CompSlotLoadable_Slots.xml @@ -0,0 +1,7 @@ + + + + Test + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/ThingDef/JT_Projectiles.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/ThingDef/JT_Projectiles.xml new file mode 100644 index 00000000..3199d6c4 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/ThingDef/JT_Projectiles.xml @@ -0,0 +1,7 @@ + + + + objeto volando + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/DefInjected/WorldObjectDef/WorldObjects.xml b/1.1+1.2/Languages/SpanishLatin/DefInjected/WorldObjectDef/WorldObjects.xml new file mode 100644 index 00000000..af48a3e2 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/DefInjected/WorldObjectDef/WorldObjects.xml @@ -0,0 +1,8 @@ + + + + barra de progreso + Esto no debe ser visible a los jugadores. + + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/Keyed/AbilityUser.xml b/1.1+1.2/Languages/SpanishLatin/Keyed/AbilityUser.xml new file mode 100644 index 00000000..6b73110d --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/Keyed/AbilityUser.xml @@ -0,0 +1,25 @@ + + + + DESABILITADO + + Tipo: + Área de efecto + Dirige así mismo + Dirige a Otros + Locación a donde se dirige + Enfriamiento: + Extra + Chance del Estado Mental + Chance de efecto + {0} Necesita tiempo para recargar + + + Propiedades del Área de Efecto + Objetivo: + Personajes + Fuego Amigo: + Objetivos Máximos: + Comienza desde el emisor: + + diff --git a/1.1+1.2/Languages/SpanishLatin/Keyed/CompActivatableEffect.xml b/1.1+1.2/Languages/SpanishLatin/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..011e0b58 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + PELIGRO: el arma de {0} está desactivada! + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/Keyed/CompDeflector.xml b/1.1+1.2/Languages/SpanishLatin/Keyed/CompDeflector.xml new file mode 100644 index 00000000..5713efa7 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/Keyed/CompDeflector.xml @@ -0,0 +1,20 @@ + + + + Sin deflector equipado + + Chance de desvío + Determina que tan seguido esta arma devuelve los proyectiles a los atacantes. + + Chance de desvío máximo + Por cada punto en {0}, el usuario recibe un {1} de chance de desviar el proyectil devuelta al objetivo. {2} es la chance máxima posible de desviar. + + + Desvío en % por {0} de habilidad + Por cada nivel en {0}, el usuario recibe esta cantidad en % de chance para desviar un proyectil. + + Chance de Desvío = (Chance base para desviar + (Nivel de Habilidad * % por Nivel de Habilidad)) * Manipulación + Chance base para desviar + Desvío en % por nivel de habilidad + + \ No newline at end of file diff --git a/1.1+1.2/Languages/SpanishLatin/Keyed/CompInstalledPart.xml b/1.1+1.2/Languages/SpanishLatin/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..c8fb3c08 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + + Instalar en algo + Desinstalar {0} + {0} Instalo el/la {1} en el/la {2} + {0} Desinstalo el/la {1} desde {2} + + diff --git a/1.1+1.2/Languages/SpanishLatin/Keyed/CompVehicle.xml b/1.1+1.2/Languages/SpanishLatin/Keyed/CompVehicle.xml new file mode 100644 index 00000000..305d4693 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/Keyed/CompVehicle.xml @@ -0,0 +1,33 @@ + + + + + No se pueden dividir las caravanas mientras los colonistas están en los vehículos. + + + + {0} es incapaz de moverse. + + + + Poco Combustible + {0} se le acabo el combustible ({1}). {0} ahora se moverá a un cuarto de la velocidad normal. + {0} se fue del vehículo ({1}) debido a que necesita {2}. + Lleva {0} cantidades de días en combustible + Nunca se le acabara el combustible + Un numero cercano de días antes de que se acabe el combustible.\n\nEsto toma en cuenta todos los vehículos en la caravana y muestra lo peor que pueda suceder. Esto significa que después de esta cantidad de días, por lo menos uno de los vehículos se le acabará el combustible. + Tu caravana no lleva combustible y será incapaz de viajar a velocidad máxima.\n\n¿Estas seguro que quieres formar esta caravana? + Tu caravana solo lleva {0} días de uso de combustible y se le acabará muy rápido.\n\n¿Estas seguro que quieres formar esta caravana? + Sin combustible. + Falta de combustible en los vehículos de la caravana. + + Vehículos + Cargar/Descargar {0} + Descargar {0} + Cargar {0} + Cargar o expulsar uno {0}. + Cargar uno {0} + Descargar uno {0} + El vehículo esta deshabitado, destruido, o simplemente muy dañado y no puede ser cargado. + + diff --git a/1.1+1.2/Languages/SpanishLatin/Keyed/Eng_WorldObjectMods.xml b/1.1+1.2/Languages/SpanishLatin/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..f13cc1b4 --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,8 @@ + + + + porque no hay caravana disponible en esta locación + Recursos: {0} + Fallido. {1} de los {0} materiales es requirido. + + diff --git a/1.1+1.2/Languages/SpanishLatin/Keyed/Grapple.xml b/1.1+1.2/Languages/SpanishLatin/Keyed/Grapple.xml new file mode 100644 index 00000000..b0f508bb --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/Keyed/Grapple.xml @@ -0,0 +1,11 @@ + + + + Se aferro exitosamente + Fallo en aferrarse + Ataque a un caído: Se aferro exitosamente + Ataque sigiloso: Se aferro exitosamente + Victima Contenida: Se aferro exitosamente + Victima Durmiendo: Se aferro exitosamente + + diff --git a/1.1+1.2/Languages/SpanishLatin/Keyed/Misc.xml b/1.1+1.2/Languages/SpanishLatin/Keyed/Misc.xml new file mode 100644 index 00000000..be63353a --- /dev/null +++ b/1.1+1.2/Languages/SpanishLatin/Keyed/Misc.xml @@ -0,0 +1,10 @@ + + + Debe ser colocado en la pared. + {0} absorbido + Monto absorbido: {0} + Chance de Retroceso: {0} + Daño extra: + Explosivo + + diff --git a/1.1/Assemblies/0JecsTools.dll b/1.1/Assemblies/0JecsTools.dll new file mode 100644 index 0000000000000000000000000000000000000000..f9c4478d1429fd113a2bdc0df81030648eabc187 GIT binary patch literal 122368 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 DC4$`( literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/AbilityUser.dll b/1.1/Assemblies/AbilityUser.dll new file mode 100644 index 0000000000000000000000000000000000000000..afa008fed08c19631a489547d8fa27d47ec858ed GIT binary patch literal 68096 zcmc${34B!56+eF8GVjg2nJkl;%w!`AA>lDINl4fd)_}MmsDP;828gJL@*n{fhlv41 zMNvU$r?dSjb{eGjIch9-! zo_p@O=kE8t9CPwYp$Q>${QL1oA)dgKe$5Pj9<(DmyX?tq@u+WG#S_Z7Z55Nwnblf8 zx5YWTW%~K$Gp5g(DyR$mnOQ z9#YIeB@mvh2X~@OTD2z7f~dI>y8*CrVC8XEDU zNFbioiF%`x176A1@F%1ij8rw7cV*{^{SluK#ZC?gAI224c~w~Auww-51v>J58&41N z)tg=?4V)pAb>jwvA!jJ%9tqgP@HCTIh#z39T5YbUMvKP19!+&7L77BYHIopin@QxO z+rz;f4R{krs?G=mon`>l8Oe~GKr%aMc2-LTjA$Q*P}@36N+EkR06ePwIs0&g;>DS1 z+wKHgS0r>i0z8Aq|M=sNvbg@P;tE;bEb;h@>GGOlF{%yyBFcL)Lb`J#l3R@v5r!-@ z_|Ecrq=Il&si5YJK`d+70!Nd?EHeq4>Z4FU!b}DcY&#lU{f<(dv3MrO0Tk2?*3{a( zY_z0k+?TDVt#(=z4fz=2Iu@YqH~=4)JsJr|obf=b<4uQ5S=lY6%=f^gKWBc@^S?I# z;7s$&yberDb#kbxgGDEx7=zdEPuC7yDD8}}*hqAGXf*;-=U1ZN$nvSFDL~rb7rN@4jNtgH8m&5R`0P`F_`(iar-kIF;ZgGh98K9D zfvdYkG07VaiK6M^l!3 zz=w6W_`g;c!8&>iTHsuiy8XF`jb0+IE~1v!f^su;grvqUP>E+mijufN;&Wx)t}ddQ zZ#kRthbE9h&f6(FE#+u8DMh+T8`R{PD8zgysK&UwA=r5&%1u8tN#;w=Bybi$4SLW{ zNFI_Cf6P7^gFtV=kw=9FE5&K-`CK9@2nF={u zR-Pz}*s~Ezod=MopzNZ#3)trqRo$Q82ep%@8Wbb!IUw2&fN9SKY?}w*l^HrM2uJKz zz!=4g*>FFS~#K47#w*2$0= zeGyXl)$pYo3!X8Om@;+4r3! z4qq$%@o2TR4Xmj=uGC8qjJ>M1wiAg;qS}iQRJWs;(rHsm7%%R`BjAdip62UxZsv;} zttL@Jqj~UWSJQzmNOPJk>@kjVEeMXE~@@@m!yC zB?2Mc2BeC+N$|tm*qB*;V3d#M8iPEr8wBm@7n6SjZ+4LUXD-RS2}lpz2%;)`WrqekB6Vsx)>T1p;cR zb3Fo){YqSkVzfiCEoU`F^-$$>suz%cxoSC0yt{ZKe#4yB^bmTsa3GS^_*;}lc>B5;7W50T_@QgPx$_+yd$X^ruS5 z44R2vL6eJ6Q>+F}`&Psy(9qW688k88+=f7P%uFCsV zD)ueg{lKvkmW-@H5~Lg z_W}!9K`U`u&`RD1#6kPDYK|+b4EckW{Q!`J8T6OsP7C?fpg-(#(Hs-0I7RY7gzbj_ z=EFCXP#_pc~fZrti(!*%RX~d3jqtX2tPBT%? zQu9-#;8R;4fuvM91?6D(@K4348kxjM!4kTvrO^5?)N!9V17-=3e;y>W)el#;3@!C! zX9lW~B!ryTm6bto&~Rv09ze3z#}KyB7snSMFI8sv#=&_=y`d2+rl)#PR(f(09;p(5 z*b+5K%3?%Nlf>irAd|((2w0Knv7W9FB9Ig&Z~z1{QS25qNg~7c6VMI5EBU(elF^i& zjLYdcaHZ0ja6|nY@9_l zPNJgqnz5POPm!T`DnY#n7F}JLrJhC{2pH`QEXJrXNy;HbPN^Cx5++5)PS>2#;8JP+ zXV}jmKEa*nTk0YzL(3=7CqH6aFrK=I?AX#np`j5y69^=^Wf%xHJRweNK~2EjsN;vu z6kAoJSBK-lhd94TtoBbZ-b!lSnHJV-UU zlIT~>=oD!|^q$q87EI#iPKcu4)WvY*kGV&XX;zMEZ>ByRbc8IWyXbL5wRWI2!MIF1LCA0|o z;}m*D3ywpr*M1QoQQ|7Z-6Iy@0Yi35z z>Xe=HGD+=YCSRdvg-hHDBw%{UvQ|yNOumMv*LfXKjqpm#sE+&8s2e1^Y2q#9na5?N zN>QbuTYryit7N65&=KfWvRZi}&TEF$Hb_O`xw29lz|#5#D1PiCQ2q0qfmZl1Dr9oy zQh!COGDFf~f$fM-?Enb-GyOFQovhT`0BI_>@10E8ZyW&;t?v-ay8v9@0X2fooo!`e z!h%tajY{Qv7UiR#E}ccIiAi;m)L6Pk%Gwa-spQe`fy^bG5OFyjGOHYJ6C*O3mF#P_G3o_ z9qMO@j9sbH?u|~{PxRykJ!V6_5w4aG*={`I9^{qJK1_@?@IlE$>ucIg`6H>2{2b8! z0syI*Lgm9WCeLH<>5M{0jQN-9{0S7Ep9k_Z(8_6^-%jhm@@6^D*WG!(0Ij)Mt_XC) z?3(ZUy5{>q-7Ba0s{JM8qTN{nU4+0CH;9GGiO^C@EL7!!<|}Y;W?|>g2tx6{;Nj21 z_=AzcN>Y6CuK>pE42qlLYtU8a8^EkQ&Hfv)o=2qQ-vPrW?EWnRn%DUbk7|taW05y6 zuxNeN1f8PLNlWzClK%ilBB9#Hf`dm<^xZuS8p(`AzI;k1=X>Jh;RCbaDI^ffH_DKE zJ5&Pt6lZqZ2)Jmc{T~zd^pu#+Q%SKS$5li;B=*?w5$$eA=B?cRl>qV!e=pm6v-)hzV z7om0)AkT)Ox1`zs=7{5|(CNgJWnz0jqGCsD2`|k2BZXDkTA&6(YrK_;5QXfsWB^&K z*s!${^JG3r1&GYV!4^FF+Qdml5~~F(aa=~dCq`u;N$g2miN2ZYMp`|fMQj5QV@FqB z#A@0mU`$P7kJ`!{uFg;w5sAl8u0-sv4fV+KisDt?NLpoS2Av(uzpkP?=P^$AJbRf;t56szWiU4ftn6LXJT=A|{2YrP@L$VEzk1Yx3q z`tpcAgy5&?o@`8?4b-HD*%Y~3m^L?zU0FPy$?bz(g8C+sMZe-=k%a+3q4nJrz%kOI zjg8URw5Zq-s(lIP(4Y2T3>74fNRsEPN%CphiGt_-Y_hbt zL#KUK%{Eh13N_oCV!_$I6lZ zJ0)PkiuQn1Qgn23iqzkghkmx3RBlA+HuUn#A`cCc+t5yw8skY&wWo8z4jAA4*rvjA z#p-$1S!a!~OA)f<4kIeD9W%H?uv7O1U!up9R#d%}N|5q!pPnn!Tx1`7ZBI_m5fHdrDN%k@hr_;DefKnCCKILRLEuBM+QnCNdzJ7pd(l(jp zH(cwm6)zav2 z*YG!Z86`K0N2Ks{M?yJ9z+9Hoi?T5zA#dYx#AgP*yz3P51$`{YsRBbmzav#l>Z%d! zdCQtL&k`7J_a>B@%K%&gQ9*@%p?9w(oKH4$hw5LP<*W5n1@t*}fbJaG=V0!N%B1c&(Ua?q zHD-5GlhlI`^lLQR8D`g0GU*;@5=}Rtj$w|@P7rgNGrPJg*%%sFIQtzF+WLVYGr-|G z4&;vKRT!oL7?Q2b$y~^28vu@=!E-p*=ME_&GtQwFzyzb_e2dyWFH#vlIr@6Z-?uK>C;a6I8q8mwR zt7-z(bOcj@iGVj=%Kb`rnw1<1zE(0IefQeGKVO!zvEV5NYoZJuK@@>`6bR31TWS3bFQKhhi~_rQQ`n{*@dJ zHs^2vY|CO|ZL}UiiSsZ4u|oj<#!twnGjhR*tZ#oC!?HYhJPPbJ6$de3yv|@qI6svo zX72}OX*y#dG^EGN@^t%X3VQOe*KdzSP?`=i`*A=JeGDEo?_nya?~h^SnOvo43Gz_5{jDn&&Ox7@a19 zk|>ahrrBCach)&*qTj_~iMOtI(DZTN+wf2<(<9h9)Ff3Rr*Q97^j8wolx$Q6w}p*( z!iBM4Nv*^=9?UgrB$lJtle&VN5rxYqGx3n)SuO6ZFm?i%u;0^#I48QvjIIr`etELi z_@a${5;0)8!X_<-NGA8IG`gY_5rg|edEMw*@ZiWKMkjSxQIXy{?wkox$$FEVnjS4n z;o+)18NyqxMUeNgvd4xT>kilM#y6Mz9Dug=jf$H*hMD1WJzq$3d5p$l-nD z-)Kq$8>#1q<)KX+zRZmT)2XCx4JqQI|ac6)E+X`_QYB){gJdQ=@&gG9o zc@2k)Gr(F?(&E!Iw-MXU1T|{U1cXkqPs1vR&VV};J7*zQ#YNX8n2~dj!aY)LZ`QXOJYDq zbdB8-|0&yaS2N;o#9*4XHg)WYb75^Z2VqjE>C8o#CL=}w=AQ?o3A|!q(=$jIu^NBPl}tUdlpZqj44axx$b;PiC+LymJKAj1RbUO8 zvPRq@&p*1qSJc3jx9r1DOzOng=Q<8l$sn0EMaPLN=NHoOZ*D< zM_(CKbJYD2tj`oV^IJfAXSlA8F_Zj0?X27~5^hzsA|g>{{D(Fn+rdcKIG{n=d?a!+ zK>nCUEC69Xw((RPNU%AkLEBUXK$<}Ik$V=>MJ_-JzEFdm-p)prDU&zF>V^K_&sXIyNzJh64?x;(>FFJoY1aC%q z?qc0FitZ}{;~}ie*~!XsFsCxSx-aaOd^!s11~XiZitn5R&S>m9+SRxK!GsxYO(Og5 z?O&3x#9V|ZIwO_c3D#Oxibx<(vrn~AIGUm!R<$ny#9=~fJH?QD;Z6pTu#>V7ImP~{ zE}{*cmI*LO=b0h8IK5>mwf20Bmg=Hmgtw+m=3XCygo&^UpF?4lE2?=cIFhnRjsoP> z6V1|SU9KjN0tps>Wz;FB*h@gc5nLUbG;cQ(d+SnC3vy^|IUdj6ERUkpBuQm?kU*ON zV}Q?A={k!s`;;l}E&+2HycqoHMLaI0uyz?T?MtOWoJ+_coIiCWoWG3~E%vY}|CYrt z0PaZU+h|Wl#E!6ONWYeA4;4c?w)_$??k_%SkD&)oS#5#DKE_dPrjCmPYS1 z!(_=IIe244o)XBdGVJTHyo?Bz8|jPQtPM7GW!{8_!N&|lbB`IWkS2!>Jpzs^>n2I2 zNz7OI$)i)ky+TMOP!O8b!C6}`tvGLw=Md!e)Q0{h8hvmwSi?&E3 z_LXE4d5{GiXe~AqPxuPvpUtGp3G&IhV0XL8u&+Xr1Xdbct6fdoUI98PX#L1R8K(vV z>C|936%`gGfiB__InRjrJDzaUpjK0xxkToxN$P$BgR?uUFNDXZRnd%GMO{QbWnYb~ zn^r+c#2?2*mYNaWdM9JL9M^zDo|DD%u!F#K1XO zlQdE7RS*!1Y0_|*Z=-&6F%`v(bN#Td;QWY-d59d6)cj~4m!4^>l^MzFAT|+|>1Z!p z!K~h^;<)o_auL_FIj^P23%i+^Q}WFgD|tPVM(YdoPyUk*={EBcI!u&;WHMxzT#}D&nzZA$cqDxUL{J z++jC&98yIy^rzo{nFgzmHBc`#mZWIT-N-L>48nAZoqkdr;gmn`e{cW<(t-&b0D*L2 z0tY(V7VATIyY-qAUA+iV?dy>p-Ky)toLiucN{5sg5rnxB=-M(O2$K;kg0m)BXjq}X zrf}F2u*D)OO3MU{52{VY&D;g_^N2!aY?*fmhH%72*MJ!S6}sj6LvR#CuMWVYsv_!o zdg~(|o1^lD2Ip4f)bcn|aLE3crV3}M_F5|8e&a6a-g+Ct_U!=Zx7E&fdo;|=pf&!{ z2!`>8kAC94+BE2(+jkIu8(98Rm}J5+L=Cka`%YwtPH`O`{?<33OaN=Rb&%!WXW>g3 z_MIRkyk7T`i`k86N=`4Ek8P|A>;;Hg$Y(~hedMS6&8C4Mo4oJD8>Vi4Z7UJ$UaR5A zBrKcwKnu_Is;xu%VhC*Mx@MuWyl&$qEs2olC@ruFt z3c4GN{!U(Mkunzfke7WIqIqxFEoYY+E|*DM8;ENW(s$#+oB$_-X9F(scFOAFa#e-1 z>4}J21bDBWnH`sbcH8K@cD*4)-NAOf8sxMwZ$x@?5e6^4<@Z#?yQy@aP>Awv`Mg`P z`36tg^t2w%^0AkZhc)2e(fCIm7eC$GhW4hnVU3olUHk}_zUBaWtxLb<0D8ow-`bsS z(uEGa={aO&@^)#{qn$zC?rhr79Y;T#-e8Xm#|%PvTNJ!{#1(o_UDD#3rDUYSdifAl z+a-f7M*hI%X3vnC$y1%bQcaHnuzx`nkCDf%cr!VRO7aPN`ZNl@*BNwv3EpV)1Eg-- zTExkExe$rFw6_oGjwC7K+=KMIEIG(2|AV+gmZnQ4pI{%dIE_UIXg?gQmj6-vw0}{4 ze0(1AH2xAcz-d+(1qvCi=XY6zJ+-qgq(u%<1YCv~K{5|j5C4_Sif)ZQXdKeEP%|HD z4n9V{9p%{{Dev5cHIuWUK$F5onnA&TpkQW_g3d;&?S9j|ZMOlFPDxcQV=FWM$amT!?G>C);8=1z+k6I`^|JPV~0jjtDbJ(GlkX zvH-gIL+a3t3Ay})1*RX6$8c<6!#^pTv=JyXej_jBYm6W^&&RLi;j|Oh6Li|iN+hv4 zWF;H(*=TK?QjjzA`jcggpZC8f zmpuygTihq*`RzxcQAYotlkO$CRb_NsunMNf*5F;(U_;gV_D3)*xrYrVpHW5YE4*!Y zz?dw~Ttw$qvLmAQDy=PN0em<#5_2vU27VskNjxvsy5378dOyrnXg}jJJmCcVBYL9; z>uyxjbPQ@~`jzVT97yBoKnm`st8I@V_tYc`+P_AS?#Q12%zhk54c#jwENVZIW}^w% zNg&nWmRl=k97c*TNux>iFF+z8lZl7!#ZN(@c(ITol8m4;yE8$b58J4*6S0NhY(P4C z6UERy_I)Iyi%JvGgQ+)VP-!kk<7{7y=~|KsCU3!0Vd)ktDdi*p49%&fbcVAD1yXGc zk4Eg+Zu#2}cBfJ92hu2SNu#;2CQuepkGxy4;mU70JOdSUoRj6z`O%Ze$}Yj^PwOIV z9X|ye%kRz-gD-R-A8ssn#-~$AZSigbzrBVjBIYuRKyN{1#~k!&DiYaSufb)V$Dm^Z zTlJgplvFH1rBKW=@LEm=;yi<-Ry=@xfM*e+SAOYE$8!kRd?{~F_389tWGwH&jS_{Y zNY|nlo-hW{3s0MoJ??=S;zj7ykMvqZ8nx7*!5p+cNbgFK3$;u=1V_f~zXuHH-gI&@ zjMKWA6qfoAclGz1yf?~@VDb{o{tdVirK*gu?f$>6=1AJE&QDOl5|4T?I-!1VZ9WY{h zX^7!$LEip&AvTI%Mkt{1t2bU~-adj~4oAc*h^X0xTF0BT@b2`{aN5s%i0Z>+z0;-W zmywG+BU42?^2Qt=`%E}fl#(sHOA?70{OSmWPUD;b8f86Nr&tTP9zsc^zVn)6jQobO2!R73EhDpv(7iD+CpR zjYnA#8~`DiCU5`*>_PIz1_m`9ow+2W2%}?&ZO8+ z&UQRgL_;lgzy>(cB<2K;Es3hyJAm150XT01NNRE?f)VE(!1;UOBFT3VLeJixT}rjL zvv#D)6dWNCh9d;Lcw_$-d?~DAEV@x5o=d%tAdRM!6}_cLPv>_aqJ#f{;>b3-7zt+j zsrH8yw}|Z9av}Ok?E6Pind&0StK}+5v6w=(Z@B}Maxdyu-V((r4Pz;aRPEnW4rgI& z@Df7#7F?>GV|Gyts`@>s?&@#?YXBV zUjoMogwzd=-c5h*y@;)IpG^_yjriB1m||}GN=h++LaQh=hC*vHmugdD&n});oE_N2$7aW4_rU_-q6I${M@M+0C#H~Aj!ULXv<0$(}gz&Dh{S}^x zK-Ay%X9VoO0I12G$R^-*->WoudKxg={z?pA0~l@JQ1EZW>-?R9l+0-T77#mb-{ApY zo-zWrVE=)zn*5$9RMfEj1A_Km0+c3#Ls=}ctQx$Pht@|yXCDAvOHIsc`xk<^l=pAq zn1Ol4egq(AUGrohKV~ABol{Kt$SHs;N48SwaOqV6*;WD4qBMl7-HddEQSvO?gMecI z;Ka`)qKd;}$BPi%DUh@9c|i~Iq-<;-Mc{=7DpB(k+&_?t;b9>rXpjocBS}SK4;rjY zRhysElKHxdAGHI-;b9dcjC4hIg;XaCZ1~iHlT9*m07AG(kW0j))nt%}yi^#LXBJel+IXiJt)%w1nq(6%0~vc9UYr2;zz>#K@n!u56tY$@V3@D_L&Pk!ZE zck1Cy`L&}mFgJ(^mr)l}=>=_iNq`!XL$ukaguF)3+opohrT|3je2Bv=JA#MQu+EMm z>=XbbqFv!dg&-Jq5nv5oKa~lJf%y_=x&=k8brlp7K0-3C?nJ|_C7{Gqrw1N(DSO#b0W9Ki5hkicvNR5%C|ZbWuzHG zR5#5b5;=!V#MA>5!8)#b*LNk#RPT|DtkUYu>P+;>p%dl!yYxFa(O8N-*bun7*;%M` zqH{ZQdg{=LKKa>1#eqZSbR>}vFnO+$HpJ4dL>VT(BO^_x$+0GOt+x%)g;!&ufKFoj z*=eoOPi)6JS@NK>*#76vn1jo|CnJY+`7!HtGsw?^d)B}`GIXj0EnSXIosR5G(sYO< z#~mt3S1#CUIw+Uxe?G}(L>Hw?j*&iH*y#2QB(vmIg$J1-qf8$ioEzGhhu+f=XiGtr zzam0Qk!TEWqTxn{gVliH&-R!TBe97xI$>ekWh+`2UOkRtD#&RPIhcc>ZCiYNz%h_X z>x*(chi1r5gbfFEXgGaIvYGH`CbQG|N(0*ZFz{;QZM5MyUY^v(w{1a>QB@PIZhHxV z{YC|CdDzIQs-0q-I#inlX?R42e~XU1wFDd(nd?CbApOhT)A#I3PcfXnij!xVtqn*+ zZ{X|ZexnC5_5;D`58%eVh&Th0rQITZHRGfP(SC=SN#be4>?>32O5z^?IaTcxWA{e! z&^=)3m1jhpL6nORB~JTeoB7_Ci2GaG+^xFFUu zG!u!87>3~tx0nYb4)_1)(SWPl&JYA_m@iJRW;DU1@`abzVNiVT#On-0e0AdkMDLb( zC}z4M=xIa6XO^p1SGg#L%M~=*UhU3R)x||I%r&q#)aud(FWV#r$g z@v3f0()Zhb1bJ8C`!Zdgdq7T~yNAqDaEB)kR$E44pIpT;pj#{$%<`3QEw84!}Yc5y$ibY z`hQ*L_hwk&|3RJqT>1YG)%mY7O8kGV&Q)PzoESmvoIm@*gL%_;@M_f_10UdNzH>A} z^huyNwnhgSd_{_;{#L)9hEqfxNRd4bEQWIoU?R(X!=oG=wOASP#sEuiqCtdNF+O7) zw47r}G8P7wl!trKU1XL_tHv%8$wzO+BIDy#{uoW-DEZ`mHxRGDt$pftvwTuDAKrn< zOtz~K4BW-Oi-v`J=v`eb_kOY;eOc6gm)^721co-z+}%c&(exOo?iaI8K^ImtG(%Ir zoa97I`L!)fYK-c(PoGw)-JMb;g55k|$76Pmtk>6dt2G$K#n8*@oUh z$NjiTz~~)?6NsAaW{45|Kj!7WE2D~KD8a}B%avGQ@Jwz&37h~Ew6je9l9(K@A_hu9mE2TqNWnI<-1nS{^z_SE9A+-ru*Fo& zYeQ!W63-{JolKv>?$7RA*lfqjGn1Xrb~1nGp7ub@d(m?7MhLx$bgqll=4f4C^9}FU z@Pbl$6Z{C3%&E&ca5EL`8kaH)Nb(HCC34l|LwM4M0k~n%=hk=&9eaTth*0g5p?vBQ z1bH)@=J0iB$D_C|i32+#kK*As4)?$oD*i!ru>${S%C{f?aKw-=g|%YhXr$oH*te6A zlBP%lHEN$iIX%o_X2;tI)vm^UOU1JUQ&T$=7XEC)fBtmBqV5T)T9Q;a9DYrM^o!G|T)PZ{oet}? zY1#gMc$AJ??>+nrfVUa{xc*q4TSu5j(#aW-xQ-}b+S5@g>Lezi zn@%inYby@F!UtBmVh=;?fi)?YbErwnJ_AA$xOsvlxZB~OmFYFr(MV4|51WDbkd6%K!H9AQ*Won9-P5oKP(+3Y zFiLCJL9qAXo%JH?pX#lv{<#9U{x#Gz)jw5TiU8NYkLo|&^znf_nh>k<`-PY~8$2QI zjOYEk>BtjPwxGO^j4Ss1eh`}GQL@+0Xad%^!M`^f(!J5eRS%PwCR#gW?qs+cG`Rxw>2 z?r@Dy_0{Avh(RBHAl}urV#=RxozIh$&T~fUH;-UHAQn{MW<2~fG(~HV;D*RaBdOnj z9v^FVU6)XkL~>?QEA%=|sB#QqUS~K0spk-b21`k~!LkhI&r%V(!)Dw`Zul_n>LXvypl7 z8~|q)0PbtxFEPM2N0GmFMPiAFo-5AlL4UlL$sfd()5#$iTlsri&bcH79Z@`Bcqij; z2VjwC)$Gh%uBp6}qM^s3yyU#BK=eIIu2*VX%b{aChO@50n95!ReWKicFe{)5D`rM$ zrEY_)WZ>WxqI{xTU*wsWX@^3y|(7(2CZNI+#>ft=}mHYDm-@{;D*@iJ=2yBn} zUgh!gTV~BUyOlUrTqML~>;P1raJ={w6A0KqCCTi`m3Q#tB9`X~?oR4frs zDqHXOSwR1(^rH{RQSR7h!|GTF>}&{Zbco;Mi6{Yc(RcBvJ@DOllHY)TP=o1EiPNJU zaz&wv@hgQx(a#VALdW(t#N`a9q;AgmbfFI!ucA7zqexLhA2^qCpSuzz5Qe5mS``d@QwM6K|`F3 zFLzB9E!Cvq$>1?WP2RD+Epd8zV=!Bc(^uzM;+8PUd@W3||H#=^lqVL&26>k9eL72g z5GQF*vP_Xp;qxHb62~(186>AnTb+|Fjt8{Fc$?&u7n4?Nd#%$Ap+E;ijAVEz=k6;a z`nOrziVX2=l^Hk0$5{lQf|V>WC71O1z(cuA=(A3@L;|@RB8N+w^bqCC${foOzbk)s zV78c7NcmQPCtF-nOyQCUrQONewo5(B#)E%T57KISABvq_N3b0{hOi+SWmhP+o=bXV z4#j>Cn^@vsEa9j;3je*1beqIHI!bDZB^5+@oB7|VB+6sVe}6gA=LLxJJC-x4FNMEK zkml1$wiV$mtp23!yav+z3zcm6mpX#Q0is`ANc<};(lDTrZs!#=;?(%zra>M{eBF~` z?~akQ4`5q(1yhusl<&?$f=^Ua>?SVVYs@nzO!R(338tz^!f42cU$J*pvbM9i#$PWX zde%UKpA8|uy19bjX&!O<1@Rxt{#nD4tA-LK&bqBIVg8|PrK4EFOjs4Z>LoaxwOz{g*#hfX;vM#- z7g)pHO!4~QQHDLar2j&yeIf^ap(W0TCBIZpK}TeW&l{;+MO0pxlAZzYt%TM4`uQDaUu`2uaR<7C8nKBXnX^C%!kp7k23SwM$ zOJHY9+`~59+(5Ap!d8Zu!k#wBCdvgt;`xB!QQfkEwh{{+qqA>v6%QxwnG@b zlO-0jhQDF?@1oYS#n1@Zb`;mn<=jgQUud=6I3w}c++4HN=7a3w9d(qKs z&vOzazm4JOEDFEepJ2U8@Cvp-1xrpce2d%lYS!vVlqez|LeH5k_T-X2eS4FI7uRxH zE?o!8TO^KSJN%Zt?n%^Usko4R`zh9N4SSt7h*FJU_%F`oO}1FFfUNOK5w+h?*^?!C z;&;{{k0JKuK3QUktJ$7Y*bg7)HZ>Tzpg%;8cPYQac7`SX&2{<(bj}mQgM&N~@l6hC zn~S_KE(FOY+5O0WE;1;un+K7Xo>WIL5upD0F7%c(k`2-c(n#HosmUB1an&=XV8k63 zUs6dJ{iT*%aebID4S#)suw#c3<^e{WU-u@=#Mk)=tL{Ts7QTf}*y}c7x!8sx?1`c! zl~?1d%DIf)25ck7+bCmwDhZ3?Tc}uXiZ2E(seAxfA;*o6EUE0ktVm*8JQ6GAxGRQG z4n?Axu{#DYsT?gT#F2~{!6lU*r9vFb*e%FmG}a|2Go~S352Xp;=O)eOBENAM|1W0j zi2%tQCX$R5_FYoBTr}g&V&dGIwWM+~{+hxH#)_azJ+NyT`&0gs$^ps*v6itp$Zwc( zqS(OL*}%?0-p@1k3iLc&Ia&OMv8imO^Ti8{UEGsowqloqEYSqc2gH1wWl-*`%_Wsh zVxfyYjJPS{60E5y?qTF`saPW3XKW?c!&UeeBGuRoSfXC66d!WjRFr+Dau?=9lx~@Y z@+tR=PlX1~GI&J2_?7sMF-*3AJt%%)>{5-e4zVu-`!&Lp?rG+HQurCe#T0NpC9)XX z!Pqk*$QYLMhM4TMi;*W^!o-O`? zqQ3at+7*2Y5mLy_l;!I+Vha za$0_lYKV7wFNK_M`(A|u{*M~3MfjcGs{!}dAg%GH{;+mpdvVp;+!Nb>p|1t~no8pA zDE%!K%fZqYJecrC)`4i{eIYyy1Q-VAtEpRIr^ z`(6zV_jnG2R`pzpXIQsq8{a}~b`PRooJDYR?r%ZKiV}Zm36-&U7?t7+=6{f515DSL z{sz-;XL@fgd#_%UDy4r2Ilsty6FRT(eFmLR50I5EWS%^>o|4~c=wcb`R&L&;>*A|o z(&3q63V#+M9rgzHDrvP3`n%q8c;rWTixMUHYB9m9^dC{` zU6nnMc5*qD%QKkZrh2l~wkCrA@KPBs8ca4E$2D?qHfhp}edFMIKe)!Doa(6TBqZcS zCgA0_d-LaFF7d~37^UkufFx7C1I0(ZliEO$Q%mrJ1i|6C1aD%>QN1YqY$?HYIRvlJ z366>o+|TgkVhVrB^g(_KpTe+a0EJItITx|a6TxGMHnbW;^pBAatA~7sFtwC=aksB$ zuwHEP^#|PMYX*GRdko;;d?y30w$1{4)S3%xUt8J+NU035v(Hjk@^?Y9+pqdxj_~aU zNtX1r%8H+eT?GjZ>`^=WketOmZUBWms!Q6M3~AKT7po-s&Dz_+`7Gc-5zz0!JmF~Z z0N^x*U~la)z|$Ds#PC^$pE1nUUkZ*dM;9n=#Kn#`ApcPpn_2o^P!r!)$hbe3eICRe z-JTM=(Ec{)7hkwobstY&j(D$9#=UOm=Y_3zU1ZR;5xY#oT{A!Wd$(YovNPON6E9%4f zacPT0gT%Za4jh8DWybsY2y*K`A)%BMH{m5OLhTITG$GBK91Exyr}t$7vVJQ?S$DZSoPA?CZ-z|tnA zLePhrsaBo}UzFEVEOW6J!YN?axY&;P9=%fB=weFg(!5IXjEh}ezf7wXFS*!V^$Na2 z_XcBIluOKsqL=u_jr)6_Wm=U8)XMzGW>unvu|F#3#I68#rHhegRg32(rx;sESid?- zw?#R+tQgop7c=Uw$*UI4F6JGwCa;fJ;bIqg*5t*7PTM)+GO=#RhP)bak&BHidmyh) zOs@`i{n+&I#6 zgrJXYldZLazvMNG`x$#tJXsgf#)$KHCr|2mw4ftM$P~wv|I$2Ktdw!$Osqr32_M$B z6i0fF6a8I`^c*J=w9y7#>iZEE!1{wQf%oOciDnloWo!{+mx_@+DDKtal5-0B@Nwcj zi3!qroOq~N#yPd&&@tj+iE%v~Cq86MYJHseRASzb2A7166JNR5mxC*Sedl7wCVGd) z3w5Nx?=o*e{`S1_BJ5%>mbC(_VC+Tjl>?V)<3(S_wun3WCXnt^8K*2q&o@B~rR__x zSiDjCp*}%;%h+Y2XJJEVq8N7s=OE?|Xb7Ds&Sh+ivS`5Y(8vis8?%oMO%)DfTf}D=$EJ(B7?YNmE`Hq& zdzLXdB1{)Qbc^FZBPTBPu7S@_7tLci2k*$DeULexu`Ry39%%Mo{hSngssA?^aPnlV{_7mA$YNy--P!7dbW z7yHn_ykCrF>@snY=i$(W;$|7AZ13S$7m6QTEP+09p%{Mx>mv456E^Nt#&{H6DCm!J zl3(A75pSVb$=DWO#PdvOp}1divRxL6M_p`m<@KJ0;vE;uPy7a)e~_4H9r7};A6#rO zutg&KG?{w{*d?MDV~fS5g>QzIh%?-{B|}nqmx&8pY%H+L#g#5r1?&p3&P{hy;qODs zMegY&Q_fMY5+yD+6#dc)vBAZ@)%S!}h(}$FW-Kej>ZwwfH*o^6LgY_lDaxeMVqgU> z_Ezn1bA>2N$5j$%g^T5d39EFm2xATDxIW(^za|&UE!+?6Fc+hd>l$&ii_yq+t(YJ& z-<*o!=CxunW75m771Ly#AkD57GrGl{*A3e$G4HWGjqtT%U$;1Gy1N?(2EI zXSKN1#mvekWwqGgVtbm3#SP+q7yG_xBCy9??8&BO+Ku8F7rO-Wmm9@PjLGrnM)85f zl%{e++$=tJ<7foBS?rp@nu(iAH<>q!f4LZqRcpkUGbv8$xkjAY4ZENl*3Ou0acjix zZgF2TCgZ- zcCln*Tli6Nsf(RZd`0-z;vpA1rt!M)6ZnI`GM!bhF8rhz>SDhev@!g&7}_f1B8?lv z&x*eDCHCx~N5apGz6&Jw1F+wSUKdDgocEdVi{hvYCAMMEGvSv+`9%^N*!W_2i+I$< zW;DJQep&2rvHKHK@?H_&GA7HuRZLw->0}*k6=yTHROBl+d$x)NF7}+VGW4ognZfy* zxY>=X$GrSCaj%QL$=Dm6oC@N;U~IS21LNlF;wu+>Y+y04-bu=Rw@>N+R`_*MCoyGW zJ#h|nHqq?HQGVORQWvBAwu!44lQ!EXu4inis8T)w=Y1J*Z-__TxY4lS8=_Ym z<-Sz>0oa?O-NlxxD?{6batXyrnLC7!v87_KxFTSy5`8*375vTf!x)p+ z-6@W8F)Hm&@v+2whxPwcc>njU(&s6n}N&sI)u94{ls`_1EAW(oVYUR;aW)#bJy| z&31~hj4c(nsZGjGai)uX4eTB9F=NuR-W6XlCeytuzI8dz5jT6@6-A2$eoI9g{Oq@) z%EkI>`@-*uS{FMD*!yCTi>(9pJJIZ7F9Z8PjB&BQ0Q*o(a9&y z=+zazs|0^%i7C2x%-cn$uqNIB#Me!k|0=9kW!f}d^6$jHf0|wa9$jq9COMh(mys{_ z`ts?dUdCQnPCTy|1m~GuaB2mGzbGTv;32rJlH_B<7U8!-2f{HHQO@C1-w!0t;dsME z6aVZ%^fcw?!zxlq{=nE0++3en3rnWcUJ7fduB~LgQd%|Z_Ety*r^R*j zDeFm46@LcQ#Fhfei~bmnB7TZ~4&LukMXG^#`e1FWhdgGmy~vTb93=d71yjR#jA~!R)#}d%YR}$uR-`wbuDZEY-mWeOg!J^=jN*7 zh(Wozn)re(_TN!R!WejqhO|_QbXqC1JCvMhU;Q4h40ZPwsg>0EV3_H#>3Yn?9$<>? z*2bm&%@ERLSd8-h3@t(xHzTZxM@n+BD?Yau+3hfs{A54ZQ5JMo#D%Z`zL|*nRm51- zlq!CUSWR5QC7KK95xu!x3}u_YjkUfaZt@c+d4k3sqO*tK8@I4L?w_!H$@BB!P0&zv z`KhI-;)$Ft`3t#qOF5b04-30^y24Vc?vUCb%E)pg{9TYJ5=zhcdHCOR9!icWR^ji} zufi8T=wCL@6jxzKbQSilR^j{07XD%EgvI*cWT_8s!pA_1fffTT23icXTHFk(1+5n6 zleM7Lg60!6CIJ8Pj??#*nj$Np2Xqt=p z>DeXo@fUgXtBS>D_4%B+VzKsp(L%9YJF@gT&_69)3!a-x?i8!E1!Wt>8ttLdUxDte zBKp~7Pm7IWetfgos4Xekg0K19Q2n0h&~9wng*P23yheOmvQKQ%PQ#(=X6*~BP`MNI za%HRbwNB6P=*!)n1F7peXtWMW-v2@0rSI zXud)j$E6r2sO*!Naw=1N`rV<&m7sq2(5IAn;upPMQVR85Ce6WVzhIVna@h`LtN5bi zUBIG-T}p-i*1%7dQ(4ZLEayCy(?|an`^feB357Z8Jkbw#?BCZO^cNv~ZLmxoso&GH z7h;Qg<)~xyr-FUd^H{=kuAK?`Z^{R%Q}pe*Lm7@%=d*~0q)f{`McbqgD44DlDzr-7tdAU))K-hE0n4<_`k8gh5hnYu z<+99D-zZFKTlHxJZ{*lpwY9AO2DU>Xd);bj6An*MzQtMSbmbDy1KJMdSezr>&#}`L zIt2|XM&bjlL;G{Xm)fJqWiU>H$ye`Z`%ITUEY9~>`VQqAbdmGK17@+9C+74XpzqMn z9!%lMg9n3tqB%l;Un{9B7JKv`{72}EQR8FvZ}i^1C+Ta%Z@f>7y?V{SQ}q|c>Y};2 z;@Mq#0aCqN-KP6Ij~6V}H!6P()oDS`lzvx(hsr)rYz&h8HNjPSp(iJjqt+{@<2-Gi z*l*vWS9l6???Cw5%3tVxJSP+p=LC4>JaL!jKD|TflXz5LuHIcxEb2WUHf=(92u=={ ztH%H~c~0-~yuMi}YS;-0Ule?(uV9-5mA%+qe;wiX#6tbBhJWip<>Rsf&jio1!KI#g zVso|anc|5Q)p(Yxe}Yvzl)1gG);H_R1~+=9d&U=z@^mQuurghxzYQyGRyIdY2me^l z49^bbuf|Qtan;}j2)E$ObCvda!wUa>i!@**Js!koDiHK2q|gXR-Pf z_7)d=&I`T={g2Gq6xXD$2s8|-ZP)2#tVM%-04}_u+Otb zyk7pWw$W4Cqe<)V+*4*69on*j62qs`S+P&0vt^%3XUHR!`$~>77Kq`yHKFEiGN z7XxbzMa_xaYkVr6i#-lbTGQ|Lj2!lYu?Kd31C)Qko<5cKF4qX9M>!LyA#3M$r7^w{NzNU;+@|(6ohbxN- zegS*#(N;pAkw!@SyGiY6AM`n_PWN_*`vW=N#bUn+yXi+}<%4qE;9{>&rM=q;#sh`r z-uE?6xDIu+88)wnCPTcdw3nh|y;F=YjS1fOJ#R-Rd*>Ne?o@Auepu`*?>E}^0Ta+O z?+-fO#l}19dxgUA= zie-cMdvQL8UalA0a5G{fT3Df8x)Ssp#Iutq&S|jd6tL#ud3Qhv0u>M2z32)&}!7BZay{7m! z8yd!}4rNQhP3S#(4AtPT#(}ea?;E9AbA5&SoScQe-Nvoe zOMKrLPlqn|?KN^^t9*)iL-mcm9eSJpPUJ%S^&JYGE`$~8)51z!)@EN=p*}Fd7E7?j zmaEsrZ_=lzPy6A|7;`^BiL`+%yLvcD7pKD~ z3-$4JSr&~%M_GN$>vN}A6O1R!a&Lduv%hk8$QDheUD|4lG&_pVha8^aU`2Je)gh`I z9!4J$g;%T*p-6`{MysuQ9I&Y0*cPWJoI^F1-a ztTSJ+rkFE5Z(6g|k9s6Ax~)RLN;8Kqt?4H9c(WMJ11#_py@&r_JW~9N$CNWUd?tst z>Mu7``zJAF5>xspIf=NxkMdqwf55}52K$$rWwBBIRp!(|4{Ljkg5F2^NizJzoP}FU zv)FoD^&!K?`G+dw`%dw1;NEyNO8p*gg?$lv+$dCN$9V($?Kt+^aqO!b&GCh+z)xPf zSFD0>f68rPA`1se_gu8KT=QO#>y(aDTl^E>O8`XzOKlV?6Z~PJPT<>4}cdCaMeoL@;zyDPBuC1n>mlLQkCoADVhk6#;X@~l< zUZ>ru_C!0H$9typ_zY(r>(;?=E9-WqLUW|^7|v(7h~cFS7aO-U<(uy-?KrDh!PfXj zeYLSp`$nbN&SG^;!Igo%kaKNdhk04An*tr4B~`Zv-Z$^6x+}2IGXu7L-~251-oRp` z0sYJ#^St6mL0?t%ET?)A;ma{bFZ9&JUqiUL_x8XyW{&rrzy$r<;6RLedmH~0*lYf| z@vi~JTUz&BV6{SH#9np$pyB3T_5DVIrxXk~x9T@!d9%JTUn$JVT8*9rJmweui^XpB zss7Qd-74K#`o;`r_sCl4Il0WQ2EBXhtFrd0Cqho4_Xhn1Ptbc_RUEOaan8NaGYGr( zKCP&sA#1UE4sKU1R=WJSEqQ38Wv zp4S_%%$nd?g&D|RRd1lujrNQC0OD?@vfKJFYo7Op>Mubl zF8D4>Q7-IdWv}rL8FoVUPLW+S9gzB>Cha45#aeE~8@L{Kiha?=+4pmJp$jA zBAzD^ruM#;`?0l3e%;I29op9oZ)dMns4eVde}0txxx-sveV+X&d-YE4x7YHBuvh%C zsK0-V_FZ{6=V`2x2IGv6M$8FJ*^IkGBXTx-eby0xTSEn&RobJ~$K*`M_;-BHJP*x| z78?}>`R42J!yDAy>b{)WIlI*!rOUMUm20Bdbp*XFXR|`R*$(fz$jY3Jo2#%8|0rj% zcrg4KIIrvRRnB5=#Hn2@Lunp(&{jAOEn;0e6!p918H+y$mHMt+6w;X{TrfK3B zz%#|f+&t`S9|Ks(um{5mh8=)j=uYrGWg_5*%1MA9E2m<|WsfpFHz5A3%s}`%4)5i# zq7vPs&cKevboCraPN^h+F~enmwYbx}HosPc#NB|!;zhtpu?;XTiX*l7#%%&{h!_NT z7{jqlKOS&~m;s%airIkeTB{fxQS?&~F4tSdl1Mv;*D?Hrq2{63N`{9qoWXD@!@C&1 z!0=;+pD@%6N;Tai_`H|kZXZF#BDmOkO6-e#9H6ksA~-#p;N~2H(}D!o?I;l~U` zh-1S9n&9}|o-pjqWdmDY@eE0a?@EKOvs<9fZ>DF!5 zz1HunKUjaaruk?3FYsUHztexO|5g7Ef1kjGfj6^4*@fBV*SEco_*{r&wYD@`OgQ`@-KW;0b@_EOgxht@jc=)TaiAc|JhYD$6bI?L0qXEAc4n zkRf)o6U^hRMFu+OfuCSa^zAWwcpkD__)qc75)0bP^9b^ucnX`bt}n#EWA7|&lKewKB= zjP}U7f5ct;jQbUySx$C84*aV;v+gsl2>g$EX4&sd0{;`9S^TAGo^LX`tosc&!}If8 zOwsq<%<=phW6To4d!F+DiD#BmwRzy*=b3f?#hnBGuROEv58Qd4-*hkX{A<2NI7`s- zC7wf>MV=$vRLQz~Gs`^pW+LYIzcUAT{$=Jto`02ji05Bt9^vV-AL5zKijxPjk3#p6 z>;azJvJdjiWgp@>ntg=lE=qpH6)5=;cMm1U-A5=n?jED$xEs$N;`t;c$K6wu9CwGa zPxJgJB@aNypJ2Q%Gv2>&H#4tizL5E?%=?*v>?g9z*>?7|?9Xob#V!A0%O7m{%PrY~ z%D{IAeq-?M!7mQIG#m|ocKFwaKQr>xk^eR_wDs++AK&);_S*J;xczsx59gl9{dn#t zbLVr*xq9wza?R1T(NB;5$>@QdAKJOJ^U}_b?iyHE95(|6wji1McbzEsfCue4wQGWt zA7ARB{eN`IXT47pd-K06F=xe|GkqCfI@*^A;Gc6MwYiV#u3O9Pwf4k&ABN8l@&}dS zzn$>4tf8?L@rvA3CyNCEYxb0fz z`y(~}zE1n!%Y1EHjla&8U)%n++namaJ;2|?xv#m;?)aMfJbz#0@3;ATYsX6i-*&Zu zFOIJ9-kG_7=Vy3-X5hQ9A^)1yQaw8Kq&s#dZY)PhGE;B1ThA>mE*?6x2==+<#l@*g zLaDXMYAH!>k33>Uk1j46Fju-5or_rUQco7oG?Lcw%GGY} z=5DNt3e7f3WtIAuJNBjcSd{QE{nK zt+du=>a8fQm#WI9^n8<1YNR1OzT9fW0p2`2il1winb|@qz7Vx+#!otkRck(Z2m%^a z05;bqdVkIwX4?A*qZPoPjMiQ#Roie_ zB_=sDRk1Ob;x$q)L|VeTHTkq}@@cowU}TgRQYa(%I9?plo8=Z>aD0q!zna_1W5 zb~Sp=!SRcp@r!ODy4q^T(Nj~dcy4iOX1+KvJ3ZxC`*ZcmrFJAy=Ck!_yMRGrij8U2 z2+fc<5tr7~*u)9eEl#5G;*2xtJzeMH`D%eD1$e@23uotDV`U|YT0iYBivboF-5K=N z>3TH3+Gw4wPnN{s>cZF$7T(N}PO4`5YO|3~aaf$Igtnkcj8>T|)k_zm^1^By!7F73UR_+Q)GMt@soF(~ic{pfmFk)XzbZJ6 z66tK{R$M`qi`Q&X4G<9)8pU#1)^06|k2m7wsO+$OWnS}@3uu1Bood9jQgyx=fllmM zF4Y*(Yzb|%3Uc~twA^k*=U1aT8nBWGhe?7=8&KyP@x_JGg_#7?DP>xA2GnvxIjRO5=!bEONArCp9rHsZ=B(a8)O)eYlW zjWeZo0vMW~ik8~YWrYO=Ig`vsT3f)bf}3BhK(?}*ic4357$2{+gz?l)T5)5|>dyGp zsC+Wy)s1A9#5Al_;@W(xQmvwiE57nf(g)WOQ1E9Pjg=EIK%4>#t1O+NT3rafGmM4+ zpTPx<`bpG1zew4aQ0`o*X&JTf_RJo|-fHzPjoFJ}Hlz5ti;IgBh!uT@3^8kRD;nqM zcIbtu)@;OBm}0XD?W<=RSI}3tR_~TOAC;Po`kjgeHn^q!#_9NxrZ@>a94#{#WIT!& zOxDko;!-W~Im?>X#zJ!qSj4o-YRwF~S~y#&!Mgwmsh0e7dvry<{gc?DvLsIs}WGT@V8U-CG*1%-?v#*v&d<%}C~5wk5l?OKfn zm7Cc8D~RkXvS8J2UZobn%AsV%_7Wk1_*T~fT=p%Q&YWXIq-HT4@IHWd#XVfB)IGoo zc_6kj^RQFBOi%FDs+Pefb+V1DR4W%*tNP^zuQIAu>$6;{vaVE-?)9mKhX0nLvsgBn z57%Po5S8LyqrFgyE0$5b48Iw4yt+pA=_Sp1ar#ob(lm6Rd+&lVl4qQtLPNg19s{S# z74!VvM7z~$)EQ<>rxJ)y!uJs@~Mt{C&W-16*fSnT0Jl< znVY_h)LW)z&{8SvV~liT#pGkIO6@5HxlIMS$xD@?GuW))ZZ z6QydkaYgOm7ob#A*AkeTn!eN}TLveW2NSRDgP1D?n{h;=kSh2jviurTA0~)VT7bC2 zd;=E)|FsdPNU>ZBqX6**F*VLxhKUkjk7H6-%+O)LeeyEyMJMuh4l1GP*r0f$7?gN; zO`)?cpwqD>8ZY{Q()FY&l(-%$0%_v7!S%9F!WIG2>hzfy<1i`0uF=sF*-G@|Y?tJl zI`-V5#l^%r5x=#YshYN?uB=w*UDi;gE6Z~YlDOE7E212pZP;)ya?7eIUoD_dW7`lg z`Z5fI&BP%_iV{fChcNwlL5ihUsF);CZK=ApP-*p}XK-Lj?9Of6b8sM{(yQbx+i`rE z=n8IiFT?i`#V0G}a#Zi((_SzY5rj_g8gI>P^u*2@(y;6%5BB`L|HCV`-cWZi@Z zE?Ztug>tE6jf3HGlEZnNb>ji~KbBZR2D%B!UeC$5t!1=wdc~RhHf5lOF6+r1o<5g zoT?l~PbkAHe_ZDP%p~H=uD8y5HJZJY1~-%R(lT!57g&SxHqPOSRb@GaIp1iMXZd<; zRhuZaP^wCyWE#sA)UzT;LM&5UZQ?WpprsTMk7>x{yr)Hg?Xu!!v26eriT&cmkt=Uv zQA^^IG}9IZ&R=!y$_$RH+&w9y^OZ6{t#s7`8r2m;VK3NkU?efi7Ck=0p4)pO24T^W z==eD9!jf`S^E}efxB@$e^h{!#09)FNvVHx@q#ZZoO4!a`bd#&m@L1-2;`dD8A82q!xUJBA4AdNcMmK_5ASasX#bOHq}GmYyLP;n;90C}HG0 zy`qpP#sH&8^d9c@La3=ND5cGv?c|HqsuNf09R?sPGF~RFh0%`D`#S~+r9EAxZdS01 zV@)yQ=h?2AL#J2-+r~K2p5dozv;hB{VYh~gL&K+3F^rnTC#V^L(Z0N|PbDDYcl)5Eo_bM1d&X)1-z^1e$LzG1yST?{u5ub%fcehBX zArCy(md6k1M5ER4DkvZb;?B35#2In8r>`zYO(T$w@R&P0H@1X5H0#Qe6Up+W(D*$# zgrJEkBv6=ulU|yUX*<8`_ijLdm4|mvFaVBhhqA1bxm;Q>sV;j%din5nx+~>sTOE1W zmTOCFkXqE_BI1fv?UW%i$N~> zT_Z*e)dyCtjZWgm6|`;I;fg<`KvdIolSTDO#LBnSsw`vllUB?|NCzLr>|{lkQs0TS zxP;~LC(>wN^zKsX;o^rhE^xM!2(OK3e_A7pZT8Cs8IR0Nood&XB3iL+w>kBsX3Pkm zgjYz2{sew8gaP55gdn8wh$<+!hwZTAJXdZ^5F!p$W$67$RgA^8lOf9Yw=vJamWiq$ zC;@1+lvKxxkr6`08LF&Qz)9D46S%?JlgD;+=poJ8LpB8uN=R%SddWq(&?raMHWwwp zm*uVmSk)H&@@_x{k6{DO_)a^B4Ok1MY;3Jz;%@zFemeVN2;C8C4;FAvEP*r&ZlwsDEaP240_q%QU<+6#k>)fO{8w4!($GY1V!6m&RH9QKlay3AJWFT2k4cF8Q6mwF;+)_;uR&EZcMl z+r{I=Y|KLWZIB)p`7^&T6;mOUz{=^2)Sa8@Zna3&IrN-8J-^VHWX(y#;j09Gfe_(~ zlkC_8+YZ`fn1m+owYfAgkwD8Z7cZa_nYMn!vMGN}LSCH?w$Z zvh;o9Icjw(we+N!`n-1<&Utzz0z1p zLKIbpL`;u#tp}PGIEA}iibR&1C~svsNl7=AqkA8V!)RD_%Mu#q3FKAx#=UhN(X)53)3T(? zbV>h-R^ORd;$Wck0E|&#Axjr%*x&W?Dupdm5X&HKLUbkqL5G~S_`;a<4?kf2{yy;qdXiElRnph?eYIP${VB(?`wO#;G*5@6k?i{i9of5JHDg$m~$ z=u&Iw*mH*$7h9_pNG1{%uL4Rv+qLp=gADaEj`e(Dt2lxS6PnboX2XTdjOMe>l1mgr7Dbyb0Y^%=?QtA=Iwy2C62Cm%CeU@D(_Q@XxdsyS693P*xg2}%$gb?priiTh9Z_Q0N!b; z0s53@$`k!4ozjYlu~Jqmm~OvY>YD?)fkXLpzgenk{F-~y1Ni$MfJtDAQ;iT0^hg=B zi8cW-h3^_|t}P_CWHJbB5)JM#Rf?5etCpHRTSCZm#a3#>Ct-;GWZ*rYhbr{Ivei_c z<_X($A=)=3;d@ARgjBCdxG%1XI4^-N9@n&nyu7FrT_+Aabz7a$pO3!m`o>6Rh>k(n znR@6$u2OH(8<5^5;lc&(DzcM`X3Aq0jgk?7AN-M`XnAWc2H{TGMkl-S;|b+KVY?T8 ziv1UZtkfN{R0~~TZj7gUFIDQ|H?-Y-TUICHDk$loi zrH5^R-aqw-Qh&nk7Gcl4OxwmB{W9M+5!a!K?c!|L7y>2cnkJ4|F)gQ-%bTavZlR@8 z1X1M_ELN|S))E9qW+ReMZ7!ce^R9IH!iIFyBK8=|5I*xq2{sI^wpmo~N+8f)hSoeg zaUhe}9Su<9(ksMX}|@Dt&Y4=Mjk%GzqmToD`fcNHH`iDS~pY8=;?OH?p?K_LB1f zPYe@k)2UoOwu>o-!No+=1RdSYF|FH8*-?r~23)R~8@uOa-PDf~6iac5owqVzY{DVj zNYQX=O~l4;yyO!TQnba8g6zWm_euQl6k+91!;?#=0UXRQ1-A5fTeKVNaU!w~bT2GK zB<;?UE?WBa<1DUPoq-^jl@!IkB?S{}tDEd@P&|LxK~T{yjfK`~?Suo1%i;2U*p7$1 z4O?)y>o%sO>wiPQahaVKUR`rG zT50vxy_>?5w0M?rgJGqEZ^arHSpJfX1zV?9V#!$h*Emvy>+}jI469lhL&2jx++?Y` zd@{0ZN%pD-)mH$Cn8J$H%5tS8zjgWIEdIDHusKhsb=;_v2SPV?dXpwOaqEi_|!7hzwdcJlh!tjz_ zfyq+1lDtqMey>vT8Z1jtXSy0Gvf*kQ??4jmzg&qMb<4xb;I#Nd)ZTHbqtz9~HB+Op zpo@D}LHB;j#rOgrr=V&46TP~3UeZYPt-CU~V)L#n1d0E4wZnewE_KtLnE3E6#X_*6 zpKUh}P%QKR)Iu2K52)Wi(Eg&wo_lI>aoI;sO?FaP*LCCzisU$H_70byEhc1z(c+34 zdxUO)5;4=w0WL4u$*vW$K!<1e056-Wpl zMqoS8Jxw$#Brjaei8nXHr`Y3l`?JzPa}jDJ0_;2L1^DrcTNWc-RD&olJSi}uUn(AC z1dK(debOw5`qow}99a^PnW_7okoVkV-ZU|DDnp`f?}diFh;LR^M%~R2d-j)z(7H`- z6;`=&Vrs%7lYK7Y;zHbxY>rk@15c1JkHLTJej<&qiguy)=`<#JnO(%yu5>AyqQTqS zwj%~}z2Fj&L;}Os*a=hBW%Z%!67hP5>GT~+<{m0ZSc{@-2RO1TXi_EHh1b};W zKx*)+J=tqq)nT}sIKgPJ{$;(Ebd}9bRMDpbq^I;g&S{R`(=4k#`V#i(GuX|m+Cp~e zV9d+Fq<*fZ_X&fOiN=b`=|}6*ysi$rZEmRPueIK}?&f@N{-W528@gSZ;s~ce-Ou>p zwsWv$EFjOLhZm`sS{meJN-InWIWV_J40*b)i3+Q-a5EfWvD*|~_8vRiOg?dCn?dvS z%M)vU30!dLTruV&MTXNwN)&;E)ATA`VMlnnUR?{JLjy5=a~Q1(!Gr$z3p|qE_-5A% z>ByF@54XU(xRyV;ftjy_FhN>6L<`a+SHMi(!WmV9dq#7#TCA^G1d1D`Kt2#@BDKbk zy0Y=*qenKG;4{PdAgmwG zn9`KaXu4TJpgbpZvG}>ZCc9Ybr@nyoE*{q{vx#=H#?G%qTYQ|8OSw9ng-u}*56{%` zSA43EKSGCn0Tont8vi!ELgD7ds{+<i=Tp~Z8Yc8ZRg zRSL`2r7&tZN?}vxX~H%QY4AEKD{zozX|Z~#a73SGYUC*#hN(??ic+XPNfRO8Z#PmT zTEh!~hTV1ePuq!iTbH(3kymi@=Od=BWRe0w{I&bxrUW_7)GG@*r!S|wjlVT3t;FeY ziLFVuv2K-38PnXsqBEVqpN>sq^Ev7Rb9_SqJ5rvUMe}_V7Y*W*UoLWd$@<`rf^&mo z`o;1se3pOvvTN`Q5>0BjdrQ2Ve4oJ@-#f6%Z(MMFgIX?6nActAFQ%;)xo&@rR2{fP z>3Ms%z)bN+AG=S{=IKzQN*QW=aE4M5J&p1G21~S44Q=rgDF<$!SD}33$mdsL`6}h% zF+Sx!<}!R6Xo+8Q;M9FXI}5b8%xu}h+sM?zG9`(Jkt15T1GlevCbZ{1bf^3V{b}}L zetZe>Bz5Zi*P!*&SxJvPD8I37@tat zqDJpSMdrYVN5i-_&hsqgmTh%7ElOv$Wzo4On%3hho9Hs_t}@1$wx;;2@ppk1SnbK% zm!D-U8Y8!^y4)~lW81viw82_vmYe&$T^lE9qs(|$_>Y=LesIlxE(w&sS8J(N7LD7` zOFR|BxhKK5;EooQsTkisD?U#a$Q2)zEw8~-D<_^1A2#@AjmJ09YmBv4TdUTC%4uy^ zz}4+fGF9SF)X)m>=>}5E&`a$mF0=gw8`Bb4#}^FONvZ$DO8LGuX0@R4T;UlrBS~Zv z*vqcCV+~x@Fn$zmn~RrfLQKe)=j$h|RLQ8T+=F}*gnp<;JS2{swQ>=B%B5Q13(Sol zF4)^EvCuac)`staYw#^7qJrDO2TQwL<97F_!kX;x+!%Owhi0QbG&XmyXqQT0iT1?l z;6IqIBhgSWGp2z`P>~)jPx{5@^>eM;-{1c%BNGp(f0MD@5xg$_B`SuV_OyYO+doH_ z*J}0Zii5bG48=V~7mSO%&XA<`w3SAql}}~UJ$U>4Nm}##;2yeti8GASYZWNIXQPY< z%5K@pTAZaFjRZYBc#7}#a9iN3z4N4{x$DMRk~iO$+p&>e8_S8-ePs`A9N9Ue6sNho zXJ}dLU!iwt>Q8zK-@CC!N)5;F_ei&kf2C<+X?$?0MxG^iMQgjihtpUzPjQEI2sMVq zE!dBpsm%&>*t0^L;tjv1DVD<*@UjFwZQ!0R(pm(5j5b$zPV-y=qxxg4oBHC~4{x<+ zns9eNZ^+_6;XU30YBs8=@~qQ= z&J(X_bSdTC_MSCyAL_RX>Or#;rKDr~yoV2NT!9UFdnb@WQC4fyTSaXC-kzSGr;NT| zO>4y(+}q1JPLGmJlm7e^Tsx08pMb}w;VriXuVF_&=Qwm#kJfIlMx5$!NwikGram6& zuXWz&Q+HZvNkw95Z2Ey3^zr(o$PCn)bW!RXxgUFlku6icMLDf!f@bzOag2O}aq9Hz z7vCCdvA=&Uv^wWlducyW*gbx?TzL-CfP_RD?Nw&uxjvF0?bRQD`>hyz4J`uh0auKX?ieQ0BS?|q3U#VLJr`q&Rw z?w0m9(QRYkiK?`3(Qnw1<-Z@Y0Xs(h&f~P7?OX5y( zzvuhZ>cXv$-Z}4<5$!mKW|*N(^F8)>pKTF|>c@KS_tNRP7&&`1EqlA%bj0F*r0m`) z-kO2z#c9*qrd1zL+qixHrdE)9Sx-rl)}B)=qn%pBZ+i4@xtm&gViLKCZA6mrevP3W zk|cziWYEOx9BEw1Q=l}R4fA-a%UYq^WFFg4p|N7f+e83HiWilhU zBAG#ed|t^>frV=zvm<*7>tD$f*54W!=Wk8!fYLLmbqJ-(8BsRhDrTtrf^Ix zr1d(*P`pzd8qOA;Egac0RCt!Q3Vc~}rf{V2Y<_sKu>Na6(|ZatnZjJ*dA(7NH`UI$fuTa@54VkF_7q;qQ18f)wR3ckYWwcv zS5UH9aAJpTK+}Kc-ywNPHleKvr9EL=f^4AZJK%GlD{*4X~WUcvYg=>ZN*L?HWeDl{B z%f7-jb@1v=X!t2wd(}_;wc)YMuH80oBgAVW`ffKQE?obDdbyUreq_62jm3I2&br!y zYgs}0b-lJ@S5`$nm3_cHkQvQw>+50ruFODY*8^_!0hisfEt4C8F)Td@L#%&Rqxu39 z?#wZ>!u1&wfH}wy+3f!}VTWA)`t#YL+|byT409C;*580x^Xu>DfO4R%==(fHu@^efP<{mN865>7wkQv=P~Xb0|8ZeX)2rxFV~w);>z4+G_UDUmeZHvw;69+jxtufE^YZEk zHV0*QyAhR;NT`iZZ5`X9#QL`+I}~66Uds+;mG?_(pPmK3J~E~O6y}uEnPx$hMEex3 zzfrjUCIj;VoXf#6`So`Sb2hm3cLs-9;(uf6N@DifRxje~uVwFnB3%|TEbL(%@!BB7 zv+pF$7OsDR|22Z&lv2rN2WW4WGFyz5vQjSPK{UeE5%j`nVf|f%u`suF zOvHRQfBnnDei3e-Awa->oBah3j8YC8-w#ZP-&y8cW)3>+qJs z`mYq$zcb3z^b#d1Q0)?n*m)53IYLPTkT%J`i1~F$mB0RtQLRrj3bbW7Gm;$|W(p%C zBT$EN+~Wp}9c)x@&?wXXiWsI#o(G8Dsbqe5NZbxH8@IoiFCsVVZ}7dXmVSe$ank3u z4-bqK;QQ|*Aez@7qsd38_Z}fo!i~&`1R5^RYHFPw`Od-ojX_o}Lmp|(`W*x}r@}i}W3hSu zMt-|Ykpzom5V5%+Vz7Ju#vV=P=&rFrl`tO2clH$Kb_K<}P+0IJ^Gm+q6~e+0oX1dX z!auKO_QL@T+<08$D%?2aUs!p@J(r`a z46S$re&bmK3ol~9kcaQ_e{SdSmfW6v=aEc!GHoRu9Nt=3|E(~3|1t$B9{}NDO^hLc zwF)ybpnj%a#OJbmVPRX2E+402E_RqRJ%l~+RGz!kfACLju_4U}%}SH>e~_ zH%#>#pDi54;=wsqKKF$CfQeL&E@8)MhimZe}-|D z&<}+Ld*c+@8+R**7dz@TrW`32Wi%(<%BXJqj+9T~nv}(j-;q(y-}nXvaw9ylqcG%+ zZ{ioh`Mde{WJ&um)BFFna11$=b9pQ~GMurVj(NsAwr$w^O~(qywx#C8>#mnoRNWri zjWZ}<{dKFl{<^6{^CDlz1gzN_cIIRwI_C8 zfK@9DqlB+z3zuNm&S);*`IIP*ZW{;-y4;tHA z;m#U0I@j)TFsc=$vA9sezk&Mg5yn)oRAbe)Ayhs)?JA5g8{nl)^ZNPB-(wcA_tbmuwWDP`Gcz;<6;4A7Pw;OFtN9M0u&I2yD zZ5x6U@~z^{=Ml5rneEd2H_sWIqxY`5_X2j*l-?Zn@}XfmHoun_Ztuf|hdm%C+I(+Z zIIY@C;`)a}VSB6e&fx(j*!faASJtj@v$PL_^YUEtC6+I{PhvPLOZkrHdDc?AcQX>{ zUc-%hPafdNSa!FK86`#WX5pL+COUQiK`joe)fyXd$MygXT{w(RX6K#1xdyX%z?|V4 zTz|7;68bN93=fVJo}q2@{`y<$bN!tmJWv|l=IB?ovpFmKuf*SMUyqE)Ra-?r8Tz-S z1WGt)c^=M^uQF=B0X?HfRu6soI=`pr z-1>jaxZulP+lBCL-2HjIsvV9wd7ld<%Ug!>PlDuKm<^h0{k4#}5Z?R3dn_&RX=t(j zCR4x$S;Neq296=~GLe`nQceC^{Jl&UKND(pWJUpsarDO{oSp>EODgttD z=UCswn8+jAXUrAKdATX?nB(o|Y|pVklrT`6>M;U&+Zyk8&~yc*>v^H7FM+b zGPQ88JpEaAg~nzYFFLS>kE8YLT*9#BJ8dj&F2|g@CQ!MQ-Q^TG`W6uXXQ388nh?7R zozKFrEZY8Eg%=GH@)EzoLZhF<(~xOFaZ>^#Mghd_*VwMO0o+9!zEX@;K% z*1rezTNVr151i+t{(K0d`|TWdH8sglPU_aVxs2O4erkH5`{j0zacfK8^78EE!{Z+t ze~Ly%@9Adhs|UGBtZU}?sMc6FXUs~ot=`^u0gE4w$hg6?=MRnZYd1OcIl%Z+<4-&H zY{os)S8$wb(6@ejI3Ma*dGt2lO#j2x*6p*~*8b6qJJR2`u7vibAHDO>1)$@MXd54! zf3V{(4)jXl$~ZT+v3xhByzW1)3CB~_s_usR?{kkL`@SO;_?t&)V{@jB04;rvMd9(Dsfb!w$s zEPS}wPM5;n94ql#1JBTChB4_Lh|Zk&O1N8Ey2r{q$-Mo4hdHN$2JRVtRXk%i2XvaO zKDZFcTW7)gxA9(0dc(!JAGdmGKe|zpaBipmn~bA3zB|=_5*3^2j`IaOOY7b_qF?>8 zk^Y|I4^>Bh{L-LN#@{933%sC3Z=|>HXPi?you)g7ny0?*(Oj^aI;(3kSAW;a?sJ)n zIcfcz4tP;h{iO3$%2VbC_2=p8Pd&?=5b8{`H`+VX^{~-pW4+DP*-V>ftWJ>?&`m9! fK>C|CKd2sL`MdRRECW|MHzvmZ`+xu6QQ-dq{j!aU literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/AbilityUserAI.dll b/1.1/Assemblies/AbilityUserAI.dll new file mode 100644 index 0000000000000000000000000000000000000000..2ac43cb20248fd52247f7ca3b8b08e8d1da78f44 GIT binary patch literal 26112 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 Dp+ygU literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompActivatableEffect.dll b/1.1/Assemblies/CompActivatableEffect.dll new file mode 100644 index 0000000000000000000000000000000000000000..8751154e9d591801d471a4e17620573c1d5ff09c GIT binary patch literal 17920 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 literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompBalloon.dll b/1.1/Assemblies/CompBalloon.dll new file mode 100644 index 0000000000000000000000000000000000000000..4f540a1fb1a4fe4a138df3646e0b0f2c5a4d5381 GIT binary patch literal 6144 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 CP6k{6 literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompBigBox.dll b/1.1/Assemblies/CompBigBox.dll new file mode 100644 index 0000000000000000000000000000000000000000..0a9638640337081edc280372bccb02730f60b22a GIT binary patch literal 6656 zcmeHLYiu0V6+SaN`|x6Kvg=m@d2BEwi=8Zf1#oGIA8RM3S=+IlgrrE$czwN|WOinm znI(2YkwXO((TYa!16t9R79mtsDyT@%NR^PFw4l<05EbP|i`pLqiBkR)wX|ybojYTD z9zV@#l z1T1=sE>B;gv=gPkiTKpNpzYhRwa*t-djayJu&Zr-oU;=Cg&RX4NA5&(b25q zIt5VDw_YH;Pz`vhS}(lMI>NM}$iC81JZx(no~qVM)L%tP^dFcPH}*}XFg<%Y(K#4V zB=@s}O=7C1;BIg9X`6{1F}2BF!@XLk)eHg> zS8row2TqimGJtKZu#0Snx7N2us1I&|nRL*n?AC+*3dT?~2unQv3RX#xD95eb(2!{a zJL25WgxdtXp`pQU#(Qfk?9{hM>1Qy8a3$3W3@Y(R&!b>OP9b{nD|cvH8`{Ddh}$lS z_S_4>$^e;5q2as=!}evs>=2Y{SBu|S7Q@H3y4B*OveY{aalIC?H^NkXI2FM{Ebf*d zvk9!|DVW!GY)FQqr{Im2*(~*sh;|S{peD?Y2^& z+H#?4v|1HgidFjq)hjMkg}W<0U}~(|%)?z$Er?4&ERqZ-BS|fDC2aUpg7LPd`e;*q ztgSN{J)YUd)-wS0HMd`dS1cL(5pqLG*3>j*uu$=2bn}tJ_0eRk`KEdZFYSD>skOP4 z`X_GeSAuLs&d{yh+4gK#dsjyf2;{Q~_-{n6<#wVuxOp@DZkg~L!z#M0@jRll9U*Kv zFhTFbTi%W>dkzfeScs{dV_CmxPcw~%&?|=;RjNTC=|iQ9kWo+}xGuLQ`@kaRael#s z+=@(N_@GXGpfb(W-<6OSp*-u2K@A1pQTQ1gC~3C_#-O)_+W8&EFEk z7W7Tgw(xHF@Fpc-|E17`sf*sBU(uK7pWy5T{{?j%y?&_PMoFbTbeh&HdzEhj-a`)n3iULkN3@@k0sW`w z7OI5Kg3}v%jO>nh`C!7=du1G4Ht`Xlro34KUUQcgQh9hiAk=~I5A z)+$--fa?M4DF=8N6#!ev1Z<(WJcQxAO?&m(vqqda}! ztCdaN5*_W7GYXzzTe`Dww37~sf@eER?=Bj*y>9w)-kzzL;szR=FWauj>7Gt|b*E%o z3;T>|D!B#QF@a1hxSl9w2W-=X8Q65QdxRw%qd-OBO-+>b6PB2v8N>0#{kjWs$PnfX zjT@yyurfmfx>=~0x+f+?V5Q&D3&({wX1j(o>gxp#eh@YXpiui8glGXz&T(U-ol_&G%Nvs9pTTAs@T$H+Y-b*$sdLtMu;51Nk_j` zA_IT8xD_-y}7O(-` zT38VT!Ipf_m^Mtrbw!H6AJol?Aj@{Vxe4Q>AlI%0n9yBMvQA*}d>Jd?%54>MVwPs` zNMb3mg0Zr}tf59@x>uN^oTHz}3wKVg*$59s_Vh8DGz!OQpKTwfJeJ5Ybd%W6exulL z&u3>$6U*w(joG#tj6nM z<0C@MxH2^nOg3Vdr}}1QWE#Wu6IPH{yr#?9vSVOkPIt<3E|oG(@DK&8ClVZ1Y-iL0 z%kdy8A%Mc6<&DB&0G(wmK>6C^=;b-1;4ZnCGxVZmyD+)TS_-S59Kx9p&aFm4Kwdy1 zi>YxjD;!}l$Io&Eo;R9HeO3{PJ#PRjK-*U- zIy>tM&(DVd=ZpwY&WQlEeMJuVAQYtiLlDblmtZ*pL8%zBovATL3>ouFb!ydWPWd@d zl@6;so!V=7ND^uf%FI%M;T0UbrJ{41uMYeHPi8+?*SZo;IF~#U}G#S*H`Y^{@rD?*+R3Qc|Gf z;CeI!efY5Jv*}OK7`Cs7 z#gd1$NNVxUaJzzQCtHt2VR-Rd7$D8>L^!UX6HE5T;)>r@OH;BZoK}_E+8C)YgugI& zi)U~G1J;nL;)Q=4?#Z3aYn3P)*@Rxnoor$g)h2h=hT_TwR_KYs$YD6dt~^{vVGR5* zR1agw*wZI(KDfU7t$RX|km1hL{q3p>N_#!=&1D2%CSzwg%@5 zqRjPYa?Y_&xC-=e>qpBgv>`h(IJtZlZ4XN8E_`)do9%>=M8mQ$XSldCER5jXYT#b! zWl36UuTdzzQeW|fqfmJKP)D`{AMv<90m*h|yKu{?zNkn)gQ~s-wzs#pQZFjH*A2I?L?}`DHLEYcQV$rmU*|$siTz3GF%a=6t{$Dpv6W(6e;G0Il*NTn0T!w86-(DklbCu?{B)(!gr7Zh-5d9s@ZlzxbPCb4)@t|;Eyfx70$oMC#1s}~S zPd{oLK3VyM<(84_u@B=EWlz>GW3C*rBF(`n$x<^U#~BUy98Df)X`W2^k@>Xo{J8Q- z%BOlop3(nHT)SmlF6_5DI;&%Io$S+x`0-g=!pfSMSsGb&VN_T5lY#j>0VFj4X0?tJ L`-}E}7lHo*v8xiu literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompDeflector.dll b/1.1/Assemblies/CompDeflector.dll new file mode 100644 index 0000000000000000000000000000000000000000..64c0083c356b76dca503b552c3d26fc56ef13542 GIT binary patch literal 27648 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 bwZqW=`~Hk#qlWg2=l}N|!vARg;Vtl=Lnuzl literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompDelayedSpawner.dll b/1.1/Assemblies/CompDelayedSpawner.dll new file mode 100644 index 0000000000000000000000000000000000000000..9ef024663e3a6fa4802bf9961dc752adec938d3b GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompInstalledPart.dll b/1.1/Assemblies/CompInstalledPart.dll new file mode 100644 index 0000000000000000000000000000000000000000..d350613d5e95163ac637c4793c257d84a41e8dd0 GIT binary patch literal 18944 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 literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompOverlays.dll b/1.1/Assemblies/CompOverlays.dll new file mode 100644 index 0000000000000000000000000000000000000000..319982d917eb746bbdec160451eaf25c8f9f9a81 GIT binary patch literal 5120 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 HzhvNF7qrz3 literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompOversizedWeapon.dll b/1.1/Assemblies/CompOversizedWeapon.dll new file mode 100644 index 0000000000000000000000000000000000000000..c68e02342decc3291e35d6bcd8cb0a826384044c GIT binary patch literal 9728 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 H8G-)=H(#96 literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompSlotLoadable.dll b/1.1/Assemblies/CompSlotLoadable.dll new file mode 100644 index 0000000000000000000000000000000000000000..232b0f0bc02b339a3a34f43ed7527f356c3b73db GIT binary patch literal 32256 zcmeHw3wWGWwf6ch^UWob%S@7)q)FQ8El!&YNiVc1r8I4N3G|+}P_U-cWYSJa@})DA zmXM|-MZ}6diUL|aCa-2SpL798eCZa8wkP^1o~CZzhwpc=?~_ zf1dw&{xfCvx7XThueJ8tYp=cbp2@KK(vOlsL?+(vyhC(9p8Q%Y<=-xb(OfX;>jiY5 z_p!+|z{(;U|8 zmJzMe40`b8w{Ocxdx54z^0Wq`J-}EB`(HQU8NvG&yorjWt}DG6;gAu%004M?8MN&h zCguM|pAN_s~q3n6YM`<{F@#gLSIu)l@s}fpoOVNC!nf70nPPj1!G}I-^{P- zsVW9wbdXHsDk!qln9yA6iTYqMT4xqFn6$=GOCKx%s@AQZGZjT`gRUz3XQ6R=UATIG zBPyq@i{K=wNf0xAm|LRIvSx@GINgcH@(!YjdGqrO-m`(s;k{~+|lVyRMDW* zI_M3l0WpowQFpO=+LNJKUQKyWi%vn!Z+Ql%;@O`EGuT)xJ~T|nqwe|V3xe9|kQXfN zd?22)W@_+nohDHAV#0WM92$X^T_B(jR)ffX4+@`ESE5JJ(W>>Ur-Pn3%b`MtnwgjC zQ8=zOID`Am}#%pPO}Fx0v(Og&fhs1N<8*O}ENHLgL>o3$4y zoB(zm*!XHD1u0sOni8Fwf-ZT=6mI(*;L+TGN8OJxUOF8DOJ}?@NsV_7)oxSc-Kuzc%3*?p#pT&BlP4R@fNPdB8>Iqwrbbp(bV}#unyQ$X);VaPTlHR_L^92X-E( ztxe#QS_Z=D#qJ>{3b>#%XG~sQ*JpMQ%lVl+|;UD zxgWtJtFF_+b7_ydY_ZoJ@WS`nGOW)w@+buR-0Z_X8%_%6ZmyL0MEl`$2v_tayd`)6 zo?_VWOsjh4qDiMym!URYAHodFnyhGW(_Z)|LR26Hr^aG4)QrGceKxf4RU0;IzhE`U zEF13WtG4zd0A>ebh(Fr!1ZUYf-GomX^Q{kJXEJMNWP3*eDk3Xc2!Gg*;AlqSk{O9P zU9rWOO;2JtN=y{drv^*WD5G#yuW)-dhA`{g-BICoDU`@HU;^~Y8@xjdZ)~?%+wHRk1AL|FEANY3m(Z;~C?#AP{e=*0B#OW((vP!f9fg+ft8 z?izg`$I2u&qESpSV-Pd?$~a!u@P=EXN4vmX1?;*!J+%YS5EJg-iCS58wLB+OSI^{) z7E^*8D@&tC6Rg@SJqfSwi{`@>vO6}Sn?7@*L*Wa{s)D+_s#byvH|^rid-TD}@f_?% zp+|dA%9d7c_i`)7#^d}Ho?hM$2W?>Y^)c0M6h2F>LhP5ma3h>8B^8eqw$rFpJG}c* z&vVya>bCcw1{YfAvB9ne9U&TPr3O$&ujFD7 z#mo!!DUbbN)%ip0DtdHZE{dntL1EBC+{9zTK1Dtrlc01Nh$LP<-5Q*XK0_0@qcKz= z{SmT!x*jS^U4_a}IdC(dak?5qQ@PQ|>1DoquUqvf2h&>U!cUP~3oWw1;4rw&ESdSR zLpU|3trpqCDB%bQ?E_3LnKb5JvDQN~!!vj3gFJxRBK0)vt3l}O_{9wtVX4bYkG>xb z;%4F5h5Fz%fJ$d0pOO*pmHv4-_r;KmpnboCnCwL zr0574mZa!ViDjs|>eqmN5EY2R5Wb8KU2&6wf%>EW&>?7Pb$awo!RP*P*4{U=*^fmxds9D3?Q&TIDdh~O^RR>Jl zKyNt#7Q5ybFu6-kfyGv;7cJP--PX`5a13C3R|%+HjRsCCG;`=8X&K~46Q|?>x6~y` zEA|57uA=(j=OJ+L-%#wo9ff@din?`4L!-WcH+m!=+=t-aQ5iH~D11HTHK%dwA80RK(F6A_qCzZSygGPf)Pf6dgO zE=wTaE6IFau~(AzV$%wkhNQZe_&~yTse2km(Z^niIClhLYFMF$$uhqNQNbLUri5x< zL_w9AXYMTWcqLs2>hamPzos2RFNM&2uO!{Z>@}8m@T)*vf;|QTd{IP@n!5RV^nL)v zW(Wy;rE0+e^*C?=Gf4K=x#9|6QtS%2RIB~(K+XCOu*Y`ntNWxH6PP*khzkvM?{OY= z->$~Q`^VL6KfIC&_}4J3X(o4bZ7SF9;@UK>J<2s0%S^t?H3Sbcsp+U8g))<2u0^>v zgKIOmwux()Ei;+oS`F837%-h172E!KarW8({Waw=tuDAS64%}jm*JX7BQvF`~OK!x%=>j^luCKrgwQy?fQiGC9#CGO-O z7)pJMffD-!9@W+pAIZ{|o77i+s7fweo`Ab57RdFVfX`)svL`;81+si+qvv?O*wh^z zwsLEh_Ug0HVyAa#kB_1K;aO-$$M*IZ+A7zXI$+Cp_^#&GtPZI&Xn9{V30ohPWc}VS zqvvC>`JSJam%I}_4B01=KSk9o2b}0hm@pLmHp=Ho*VkB=Y*xO9UgRsHX%|2~^L-Y4 zk!1&T`#YdT>M+>PPYqi)S0u&vSxtxl*xeAaMvuW9L7Hv`-aWeY`D^x!Tk~CN&C3az zH%(rt?tm$W=-O6nn=qO+=!VDeGOC>yeGpP{sREtMxifV8A%MDs^5oAkI(XxW#nFcu z38D~)N}@}_ArnSM#)lD(Rcg(xpsT;1i6cH5gpZ?pK=0>S!w7qTF!C(5yMC94{yi=p zLE)c&8@QzUASd7JvA+-0&}xWwhZ-zn!L@9foNkD;HQqtQVqDskReQast=%9<{Q$kD z7rTbIA>fK4Zr0e316OR;G{Ox3i>tU0i#~x$?Icv5M5Qjomt^)+s3yXfTyFmm6?b?` z9y%0o^TW^kaZH9i)itt5unRW4gFVLQskJ-`Z8l+HkWuV5>Ws2tw<$v|_5?hmT8Bbd zc29$4NfgnwMh&}Wr5Y^fAECzc0-pWPfTCiOFZClli+w>~^v9@Nj!7Bj5HWl~z!UJ6 zgi2EIDxdum6x9K!TkKYf)!mz`75ow5N=NitbW(lfq2tE;*iZNv$M{NZW1lAV3gm}d zFg=(lcn$`RJxuOm)Hc?%7;S2Al8q;CelZZ4OL&jENa9QTpaCVpdJR8cXpa6A3S!%R z4i6wsG;h(@cw~o){)|-*8q;&yqR#{8js6^EZRvgvfYBEiv;P#z=r2&HzACkT5pYTL zKT*~$9gnwP8f~nG;Nivk8c|4!6lon-Fwu-i~I>~$gDu(rG^8hli(6CwB_R=fhf zYNHMC{dkSD=}K0CwZvIUNuITToh$-;db1Xl(^i_-!GCerVQ#TsMOCE=^S{i~qp}4x z117lQV);|Rdq?l9n(6@SgRjZ3S_NsBi%LmLR#$F|2x3dYM8Z!>M8SD?5WAuMXm!D>T+|UE;N)v zSD>NESG@Y*oBTvzi~f--c|m{9r~-MHJCFslunyk}_(}qvP)U>*QqUhN zi~dO}2n%niiaYveRq;muf{MG&O8phjJa@ovzm1CFj$#Y1S?@6RgRxwxtx^G2U6IXQ zqz2y-mQ>LWX8WU3)8F6mZU9dzs)R_DY4wdnz4e+3cFmXsxa{TH4&Ys5C z&Dgm3Vr&z}jI*UdD__2wMviy>+K1abp(5I`pUE_Wn9KQ|-R88n{*7yKHbM7e{) zo-W0LtO)toN!|-?_^4ds3eP>iPQ!%!7H0w6<;=X(d-OAQ`21iqEIM;SssP$unE}y< z&&XIR{M``5h{Yh9bb2;Ec4hAsKc1b3Piq;k`)Z0q@^O|A7iR2+@}ZWjmF>_D*ZL9< zunLwjxmpDXB)s||$3-U~2WtUxm;eiPB_4T}_%hs_Cga_X_s8+Z{aLBv6UNew7V<1F zXSQL%hBM8nA~rX!Aus^PBLj>n8w%p#_k=myuBp~Ns(0Dg-g>q>^vdlXmhP%g`Pe=o zwkE5RV@(0GwnW5p#;9z`HW;;~7)NZ`37Kq5HiLYWA-3Gbw#>x5_vvyIXV@heO%w@8 zjU7TQ+YXr~b-`Zz(&gGLgdu}O&$%_51MfGBnh$fjlcniZp}sDVyG2Z5icpTbtOvqz zmo{$Wn2DI@#7u6Lm}y$!*(zcp&ESZs;$?vJ;!M2M#djb8_UC@Mk@2|0^_#JVu7W>_ zpuvr37%W6lyA5BpVaP__Z*k!p+6<7_CX>Q#1{vm$b$ouf5H@pmKyC~Bp0CT$IaG2g zc}$P8c6y0$Qfqe)tLxl<@Y?;*hm^j(S(R8yErPp9%ZD^raFC_t_?UoMAB$wisC4dQ7$*cnJl2eFL7ydU7cSBGaDW$*B-%5lzM+10!|cW;#<-{(<$SEG zsr!jOhvx}6_SCj?GSRyOQ%%%~F#KZ+xJ_-e5CH?*BTZegskH^qRe*mFrc;-6^PyZ` zI<~lrC*7Lo^#S~|Hk%KjEd2qz!JaUBx!*e%Pv!;pBDU9jyd!u+6rb1mEF{kH=Xk9|h~t+GDxQV3&6uO$UD;ohahg zSKVArllt$_*GF5;-x)r-w~%?(7*`eeXhA;L-}YQpV9|ehS=%O&^-=V)=!bz5l@@(Y z@VA#S&7wjsrwje=l0Swlx)$^n`8`~p>|0XmqkHmLpJzn38;e=uv;r=l3$hN|!(6@w zZGCh>F^}jKgGXc=j2S53IZVhvk(b_wMxqHWVe)^N8_x&?o^ z%;s$&p3PlF+X_Pzvbf$LE8?AkCtVhOtboV9+Rd~1fdH59$SU}WSoIT9|8g12tr3Y| z5&i*qmyf)wgXVTH`vC&j{_g>D>czH4yFu~b9ky3zf(yDy2jwBq zO%muS@Qi^jBG5bF*@SpHU!Yz2kGubarcjf}3s2;JQ}F38OFt&kr_cp7jF9VAj(Yg4hF+<-GXdZ14=w9?a1pXTZdJRGT5cqEvh`$1N zh!)W$0(}}*It2cg2~;7J%ka$;<_SWywPMd<=mXO4BI*?g8!FmXQ(ul|Yw^uSraUG* z*Hb^@`X7qU!yNuTya?s@O7VRRy0qjo9^ms{v@DuX7>DOxWvv0;ZE^ief$yT%$-rsd zqC3MIfN!-fMfoRJ94ENO%J-rEOYqdFKA+34xwtF`UW1hF-VpT_RA?4`T)5SiFCA0Y zXlvyS@U?eDleXgL+!n3F`Ud}E*7Fxqo(yw+f#8`kL@fnB)Izk|#pTc4T;479sZusd z`DB>!OG>!>wA5elaJ@n5ms?z4fU=QhzygirL3u76HEi&ot))=TAufNQANGXkHaZL| zz2#>OM?(9c&sG`xgGIxr-=V)B<-^(sQTkm>bD?p4mWJsy8ul*LH0rOo5%rf%wu8do ztbZz}_12u$+reRR=q{ACMPG;ge=O4P(7yuAfcZ6)mue4qS?7nL=d<+v96lK-8dei) zdlaQcH|sz2u8Y7`=mTX9*hw|Iatw5bf;^|fKLho>4)n{4mjU@FqZ@s|^R_@c9Vi%j z6>U#D&|O781y81g|% zKo8P&p_x7p8GL2o*xEyR0*z1y=T}tgK%a&Ld@o@Pp!p@Mj6C|01ATR31-?1+pAKZYmVi>eqCyXo50>!L<+UP#?!j#O zDdj+s;%7a6;xC9pI(@ECH~e(9Krd_8g+FHc>3Rp68G6=}Plpwy=Ro;)^n7~4fj(Y- z+M7>P>V%8uk&0)rKh1QYrz%$Z3TTc4oeI2(Z))swpszxgLb}g^?!Y&-3h8wRdcJh6 zuaN#E(8JnKEABwsN9tJudqD+0gFfa!O9i@LAT`qgI-%NVYS|^e0KGG&&2tWO`8bmB z0kl=lV(2D%HGI%lLTLwjs{96DDgDZU?gJF22WB(n^=0Rl-s~%ImBAb0QC@pz4dhN^0P120-ulzwE1`7dWX0w6p5peG%%!B^*OTRS){6(tQgRR1GfG zBRAZLazSz7}8$q;#nzzR$~eWG!7S(ABh1d)-${H#*QFdfit?w>!`? zh&=Ulrvu#$->s*+1X32Pr>{6|X>h5hCmiTaKY3nq@)AsLU~P=5_=WhBG4&qE#l!Udd`8q z2A`Nk{$`dwLib~|v#462Q(j-io4#38uORKUGH#pev|U(H2WYX=cCzHJpuF0FjMAlO zyG|e;g9hmHP8&;~O?NmDOP@{YB`p1v_j?oEd9!Jsf<)eIy4q=Dd9&%mPTNpPJ}Cc} z1F^i>^do_k&1Tcj1-hDkp_PI1k2!5{$E7UqY6`Nkh3blPItq`W!wA%T?l z%%z)hDCg2=9Lit7U*^)+vuzrkOHT`=Y(0^*s8qY7<+}qZb@X zw)H&vrPIb^pGU7dZEWj#G#i&h%#+7HkBV@|^$XlVXjJCn@-07?TXAF_TW*rp3yT@Q z1vEOT`l~n~YxHmdmyHOBnbPknD$=P#dM(1CTE||D&r0ca;s3Ifj|!h|9Iep{d~{Ov zK4j=R-56kch4~bY=d2s^tSv7pGU#FH^}s}?{CqxBD$SV^-@gC{gZ@Kk6gO_oaC;n= zni`E#YIIW-V{%L8oWTrxxvok@^ODeiQ)q^9$~cKg=fnF5-WJ|B;(Zu7bP(?&co*P( zBi@IRJNxiHg13eDjd&l%cZS*111K$I+6_2o&p=s(mB(e1l+9AMO1WOjEmFRLvXlZE z_no0_#~NuAZ}C&2B8qxmIb#y=gA$rj+Cyv`11y7v+qzq&))u z720t+zcixl))y8`NBxMaf*SQmd4o2fpJ&cznu?`ponbE54(e~`uhp*C<7I8yVg0Vk zOSL=oPItTZUKz_A`e4P)+8mMFDRS?mbm$K4s9xj0TkDoF9@qDHAJR_IaN(ocNxcLa z^eKvzKch{Ctw!ic&^!ljJl;;x_F4Tz{-3m0^oG*Y+9|!x<8`A1pOYJH5t_R ziL7#C6-GDN_+0tbdb!5+8ODF*e^75U?w|Ncy$SW(^uv;;wa9o|jq}~dfRXtXtzsJI z$j7NC_)R^gJz;!D-(nof{~qcw^XK{_bjo;9Z`4ovzoYM_c{qifq>sV2C+Ud)SLpTE z^55vYwFjzxht}O?r}dNc3FJ2kqoLGe>^36hL1V!9Mn#2Dt}GyOM~udz8OHljpJ!Ze zJXf#;WI4K#`NxCJlR6BxETx{Hlvd1`TTo~GG9MpK$jvL!b z4x+xb;8*%V?Nb2@J~pfP24FtwK5QJ+XA~VleWvRU<0!GGounJ#Cx^9%T;Bx$W}MLu zYK;XC8oNcS4@-F*dQLKLKz)S%73C)L!!omXivFKdG{jlk7o~omP=1cK zYp)nR#<$GlbXWfO%r}hBmOf@`W`5yQ=3B;Pc|XDz2qNXro8{&n?@K1n=5Nf&W-R}Y zW|O%r&*!?6>VoC2R`Z*A6I}=Obmdy@0h#L-@zn<*@lkq^mXt?PPRpyH>k)V3u2Wi7 z*-qCh+Bb{$x_&@g3$AsoH%s#lq0Y7%K(EiZ-oPk|Xp328{hKRcHk2L%=BoT}x!41L z>N;*z=N~kV(_hRAI%4MK{n2%jR)qiJy3>5RQnTJL9w?h{9X0osZpy|f-TKT~zsI&PLsxWzhYUOn-4l)uft3w(TK_gbgSw*n7a zub6)-e9;PEz5Ehozx!rw2I{}IPSO&$?k-3DGp=&|6ZyAWUe_yymB1VUhk$FKc$&N1 zwHaS~n(X>R3#(-I@Co-}ZLjecS3>W?`8(nIK*0;{8TuOqFQHr+_$|sW_}@g??s?m7ivO4z zM~N+ZnaA%rNy`cwJ-b~;i|2W^==W5ekMezGYdm*STd>nJ;98cK@Qk<~HLvg-bn$Av z-sMK*x!(0v^M{&W`%>A*JlDHk!`eCM+EREJ_20q**SpGa7C$2Nce+;Q-Rnt++=R9O zGzrb^{-)=o>r(~a@r-DE*4UzdqVngSFH*Prx1L8_#|z%_lxQDzea!Q$>*=EJ(w*jw zUZ3}*xxKOs_hQ({v9C7M9Gsm7=v>_74xy~aiD)>l9^Yy_h_Zt2Ksl9;qO75JP|l`O ze?7iq7eTpH%8LZwhVnMLi+1^M)4qf9MJWxv1NEs=F4ixjI{#9scSw1)l($KFLdx$* z`J$ADA$_G>Y+OdRf3a~JxGfb-hm^xoUM=M@Z;|qZlrKn0`9d${Vkx&tc}oG~Pe>UlIN*v)IS zotmu`>QCv@jE@-i821}57+cM1*9ERN*G;acT`#))_(t$9_Y}`Q&#>oK&+VS4Jrljv zUK4qWg?s{c$H+j6kZ}Z&VU%F*eiN=nb~dT<9L~|C429;PeoxW)C{MeWpqyN^0_9cV zRZ^};`HAw)C@-nJ4CQ|Zxb^Eo|3x!~`Y%d%po~xGLwRJv9+dByaAmeWir2}&KOLX9 zxKQGI2Pj!f9ko1^9(=;011?1ALms3ToBC`!SR{?hg6pvH_)zyr>-IEclxa z5352s2e*|vKHr^;GDcHT?!b56bV|^BP!1rU(rFMr8NzQkRG|DidWGnl=oO+9=oO-G zqgMzKbvnw2(JM^f2W6Ok0Lm~u4qd|Z1SrGw6ez>=v}p7UC@bkTP*&1!Kv_xu4W5x0%ut;259bI_xC&0)?(HH^o=tn!PqSyNS|tno$!WU8rEKVGAn zrXrgj|N0nzxHXR3Cqs&#f` zEY@gfZ={81+6~CF43@DxBlvNSGsXer*tz6cIYR?r#+w$XG4eaP-DcyIirdyD{-eRn0(a6k49n7Vmr{DX*3|uFxo6)|KBz%GoV>?QG8%?th+zHE|y3FKUTxD=rEf$ z+E8?Jyn}0aV6d~#RCSILH0KP(Faxuic#zPJ{S+#uuM#jCC9j8NSM=GbIL{)jj3s;Q-how#?bMU% zu#?@Wz-KpN9j{Gd_Trrv;!6kY9{gmH2oGEZ(Tc>Lc*eOIwacMcmrV4;k^>OF9b@RA zWW0k`U}|?JItV`pB+s^iR65>Mk0sR&>%eVN^(*3V5GH|;b+IHIXcd0OrZe6Z>+ept z#8Vx_t4J!29!#@3){7; zfl+nRvMV~`eLObSySbYc9B`Ue#M5hHJ)mLD+WKNx8>-%tjCG|^Z%t)t3B*7dP2x(2 zrnPquLQE%ZNc3Ec8AB!33vKP59)9wwb0)sc?nixZJl1FTf@Vh?u0uWjS6#vj0WGmR2Vnd31_b(KC$)7X6WimoIo8vcz|?Te?}*bL2jocSpm>B!Y-}J{ zjeRNDx+~tBf_vnUU?R`Jbtr~BVX3t6W_zqeNa^arc=|AaBm^>2mTnKG!@;eKrFSmt z?Zgn`D!#1ij&<+=0VZR6*zpyBt%zB5$I}YoIMf)NcriLjk5#sPxm4h4>7+d%^&Vl2 zWuUegHt_cL)$#6lyg8kYbzJVCS7Xb9I}+SS3@)nk^w>SEY6>`jsU}`yJZpVyvv@L{ zh^N}wj;svFTDbCT?8a<{T&y!;XW%#W#`eGqr6)J4SSKLcZ$&(vgUJM87So&>jqlXT z`GK91ZYhXGpa;o@{@!$=C%$o@FTN6k0S4?CTAs9f986n0-Q2qaO)L%0yLWXg-G)^L z%qBSSz%ou3;`Obo5sP3_gs?IArFN3dKOW7oY(t#)5wLRFvCRUr3fyuzkeUM4ii3tc zVZGi?EFQa8z>9YxpiwsTpw7DX#1g$u$RyS~Q&&r33HCX}aP?iSHT^x?IiG`r- zgm+;H_M@pKzP*3P4xWxtTyrWF@7dlxurZO&MYm$Jh+)fN#_`p$4g|ZLPHN9sj^AaA z@3oVck8)EI;>neX&dzx6C_WbcUxF-a{220JAq7K)r8!tj#*M7P8l z2F5C-0%~e)7dNSBEIpjfVPk9ugBiW)ik|M=<`qf1zmE}0TbavMv4MD!aqN=(95+&4 zvDDUwSz6nLN<4kBY+6b-j}bCu$Rd;^GV!L5pg_E3v-O=O8*xhT9sNmFNeh^poM&Qy z<0bWuzcROrW655ACQ>V~!${a62uF&crUIKGydo12XqCN#mfOi?SY*mKxPnQKNf?J# z*|QZkEHq(ZBQAmj$y%ECFck|Dov5WaDoAZ7c2*!VyKxKB2t{}?Hg|h3I(J-t#ug<0 zwlRSg-oY?$v2KJHgaTwjB4t%Z01yIO$;MW~ogR@Hp(cCTQ7HmyiZA+^s za_}?Uy1o-gc1MJr9`VN{cK&3$vL7!1X;5L8HgHa&c0`QN?vBTLiLFf*ayH5NyQrmR*5!3CAxO zrZ>^okGRYL=fKHzNI%mmF!2yMmugoh8sc=)sq#3N$0TDVyRW^ie>?gp(Aifu#Jil7 zmM42O!DVu!1+p8_=*A?LLsG8rE8^*FJ?lAZC5hzpv#r0c&rV`n$flN<&J>a~MS%=6 zh2d~0UK&ewF6mFF0WRrJ_KK9HG34AyUU@lSYbuLi;oR5~myDD+zi(~XXu~mKPIc_x zXv@JL3xGQK8XyOj5X7<(O*om9s)|HXMK+I=T+S#0%gIJG5nn{y6JWLTgf^L~It?(? zgSSdb5&YtP*kjZ2_T}+-=XR_J$#0-FAMDrmDrmc-N-|cC5Y?h1Zs7hN>blHM3t2NNET71V+)@%&>x`< z4-WUp+7ev}0HRZC3m+zv94AzTr%=_zDje&f7Ly<oR0_@ zta3h_k(e8+;#8U1*=CV+tNb;|DQ#;nj-Z&rG*Uuz*$HF9jB<0Kv{%*M_+C}9`A$Ra zy)xGTI%JV4F9b)}7-zY)P~X`|+0WW}WW2h>3@s8aWk-Z#q<1dInb_WoHlEM5T{zcZ z@8nHJHi+ilj-9A-lIm2MOs=M=(~hUq^31uY%fTutnFh7wcm-!R1P-8zU}a**&ThQ1 zCb*r0s;Vj8IOECrUg3Dt>JYkRd=$>+yQpRk8CVOMC4fHT&-?WmGHjL$VHmlvsOODn z5v~N%&e`Oj<{@F=AK;K9eVn*@Uc^-2A&*`5_EcsNEs5BUURuC1FXaoGF_pAqN}nBLHlz!efe8LQ4X-Hn{p&8ShqUR*JCqi|eFF9l&xz zOp4EeP9tCF#Z~5&LIBMH7A~68-k!$qLd&Tqb4^SQ7sfkqU2AuPaR=Y|s=BibQ#l@m zHGmTawm%j3vb#Cc3~&s=Z6rHRPCU!bP>$ziCM6fe-8c<_RJBE?u;21YTy4IXo^E7T z*qg=Bd`#rJI#FjXlU0bgIFa7TZlEZ6-cp2>zFpP&1creniBSO>I_88)%+wgD1H9z6 zK4&2_J*0PaVUALCaiVia98VN-fglsezMv*uz}DVf{kY8IyB&d%Osr0%QgB0s>dQ1_ zvyRj_zZ2H5yUwsNbT++S8RuZf`B^LO zi4r(`(O%waS0#E-#cXt3uBy;U7Smcj%J8kEI+cxrYQq6{ZfkGH_Q(}zVJBgS>;$dt z=;+6B6}+7p%OW!8igj_^dx4+@w^qp>Y)09o%~Rjpzk|0qTDmjdak(rznQhoUw{=PjQAo~M9sWa}~`cUASmgdwYkvNTwy-xJMH&SPK7gTuW6u z1kv2Ns~-WgQ!W;jGd1@}3uggq;RZYL8=B0YCp_yu9R4^~2~wo9$H{Ju1)jy`Bn4yI za?<-T_>MEU;FP$GuegOJgpL9!)`vxNIFWcJ6~;)a0mU8s2KXW_R{3zmTLq4s@<4dZ ze%^;z!7)HS`$LMq2OlZo7xEp)QoFLgQ0e%2S zRmAxLiDkVoG(IOt5Ac;Ue-yO|rwIlTCvdXPKs=Z1Je(S2a4HeVKsnoK1|>mTWi@E?1=R$;1&nxi@F01f6 z^D+K?T_b`&s*MoJiUg(bEd!kRDUEjwfAy50D+yP?_~TY?TLB#Q4`7mL!O0gt2#UM} zoUnfQ>j2&iMAI|1H2Q1@4KDxCQ}t>A)WtpWY}yMx%#ZA);L{6EF`;6qqdg+{OR5y; zI-w_1ML-q7w?~tJ`e+?We9QxU7itm6u^|!P$^>Qy;6->h;?24%9RB1Wyc9fo@sG7% zM!O*)0bXp2D1Lx|xpjb|4{xPE8Tdn!{57Co2ORUF(hbmw^-AJ@G{M>}!M8IgFNd3( zt=LV}G>C7Y4B?v`Dd>^0O#~7dW|}1W^Lz{d?gE~BF-L8Z>d6+s?F!_ueY#OPT4mc6 zuTF4^fkRq)W1OX%(2wVcxkvC_7S@AGGxM)(>RcI@Kk70Gp{YR+I;N7?!y?MQ>b*lW9 zS2C|<9s~P4uMM_w5>LWk1k;R_B9%Qmvwqp{d9AgPC=&~m|2$2a@!$?qXhFsw5$31G>W1Fw3`sQ&p|9dlWPk2F?_3Xcc3;%;@I7a zcN}Bj*B29?&%gFdT`kwe?!W7;@;j=?jA)t%Tb$-XC4jF_Ygz$UgZ)72p3>m(&027H z#Ejs}Wx!OrOM^p<@J2}5ig`Z>4j;}?9&-qeS*5|bTCmnlU=hcqsGP{&_fX~Afb+fZyu1M2|>ql!h;1L?pNlcgHKy@|EP z7vS7laFb~Thra=pgPUCVtFsz7{402bg{2Av}E`4-TJ% zHIFdQM_7@^cvR;@5PsLjSES*u+@Wt(r3-?FA7XJ$-V9d97jc#0hfj*lf|x^HD-a)x zF~^785go&bd3a(1Bd09(u$b;~8^Nu?Ey1lWH>-7sjJ1%z0QBh#5; zk{eAwD-8@kE6?EYDKjwq5_rVayierEyEj7%NdI+Z5Nmy0&k29KS1}c9weY5GN{*Bm zEIUIiSR_v@=U`_rQJ^SbTEvUtlW_8kX_O1eVBQ#Q8hInT?qfVz!;fJ^JOOWU@ivMB zE?7n`evc0oV;jG)$g6v%S5DyDFUXfYC9-B!ozxiSs$p-eJIWyy1-S z)UiN$9Ec$j`gv>emqtuSRNz27a3B#p&;#*jGL<+aqBSh?W{%(RO94U-qG^$seRxEK9Y^2^9ypFDmzhj9^)PIhfpht=%HJr6I4e#q zFF2sbaAQu~rtS$A1vg^i4?G4Qk6`;OCPYFw?e&HgIG>~MC5U^TU}bRlSUy(5@Ug&w zXN3(y`+=W93*-wE2}sf6825ND>pA?88WQguN+Gr34Z)6>Ttp(BGn@mjKIM}V-2DC%=1CD*3uU+}x&E<1mIH=*9^?2!)?pCWBKQk|@y9pMLIQ3T4r{NuS z;3#w*eiDeq910}$0l+)ZCcIZV$Qb@cJh+O-K7xK6EYS}G2DZ{+6hnO*kRzH`F~Z6O zs+&28$1qwYZJZ@ZaN;deawdjq8QQ{y2VnpBuF!r#9jh>yB2#u^pPM|`ZKvXmf> zjUtYz@tnj%!d^6E$S51qfoe@ao4DA*#a1pnT==<&xljy0gc3_J)1^s}BSw@erFIOz zcj;kgqKW)BB^&k7#rV$h8oM|9oeQ~iOlhFgg>E%|ccgyJvW?lV)YbCGnD}DJ`S=;Q zdG)ivq@X0*===c&-@})1uSm8fBGmZX=pw#Z%e|MwPdMTCQZ`)NSl@_ULL)aS^|R_{ z<8L}Nnm3*r->M$ly=MFu-_`favCTmLX8a#)#&@X4r|{}y>2crUsX5DE3eW`_EjWY2 zyL?Tx=FBg&iw$!M{=K@~*NGcOp`UO)G79I`GXMWlg~LbU$(HW!)%YY|eX~6tmoF-D z>pRoIW4xGLR{v9n=d*$ElLEtIjlpYza36Ojp6OQNeaS8O*>1#%%&Ww}FG=86tlDtm z-i(v_2Gm;d`&VlKx1wB*I={YQ{`R!``z%fVevT#a-_czlt?Dnb)Pi#mc(mZHfh*ru z@NE#^Ib?2cm};8r3mehOCw;zo;?uvno#S?*drkiTm}<}|4Jvg{b|$BFLeqe8tABHF zlL;H(?lgeDe4oho5iA3@*Le0o4}N7@GUxux4QBSv3p5uBkBrRB9Ruq!dXxB%@@hcn z(z2G=3@!K`b9B6oxPRj}eyxNMJs_L^=8!GM_Yp}v`EGG^1bYXCEAip@{W|wAt`=IloG4b@@`44 zeRq4_-IK(qR8B?YL_qA=DH_8HjKp$+!ib9|a11+Xf+R-bGzDC^MT(~Rg5$b>v~cU@ zpQb6|sK0r8$Inzn{z!oU-Q&)infKnzyqS5kyN@I9f1Fez(s19pMf5USzWOA*J*c8P zde>K?^reQ^w!bWfU)w%4Z@G!GW6wE8F_AM$CEH8PmE{D?xNV<+x4`l(el62nXstxK~_#us-FO1sem|RyvQHW!;H;#nneNu!5B6 zJo^8G5v2Gl<5PNarp+WN!k#q2cmoG(o!suq)y#Yp@Z5aH#ckB&6HOxbVKe zk+ucsEy#z^*rsqxqjGr*x_Vz=l@h&-AcT8Axtf;ZyDqL6Avvv&-hoxNxA)QD@+uIyNc5SJNXn&9MBr}r8$*}K|&UWYNCI57` zInAQ(tjEB^->dI(&ML5$#Yv+i_z)X< zc@KC#hA@WRP5?a_=KR^(t_K}v(w5wZwxK3+Kk!z`i7ObwqMV0efARn@ zU8cN!5NNY@_!IC+Tuc5QQvs|BRb*NDXZq!GTAFoLre7?uUu|vHV*wkxIGj8T5Yv-L zqHx!sYTv^$f~tKlw;|O&!fk`vVjl&f#sZ6+!RqG4`?yK|zGQ}C!B|5}OR^8tuAl4- z!Ggc+KOKQZ{ovd)bL-ZvpG4!@uUfD#w%P;W{V16R>=4+M3Oz}mJ0h^pQF@eQhWWft zzsL++cT@G-X-L#FGKZ?Qyh;pIkp-M#hX<;N4P)QvuLgaL2CD2|@V?MrZSb+azA6IB zymEh)V*!l%tEe`NRnk?I9LC-psKOY=-WsT)yf79{S79n+kM~!RZj7bVRn!f}{$rqu zqM@}`Q7*Vd(ZJ;W1EN+9xwc+7km^qD@7~`7FLU-506z@#cU&R*ceHO|0Xrr=$12Ua zJmPzp^t=Mz$w^`ppqq9aJDG)Z=yA~V+&56LXLv9!kYalC&4vann*K}dCzLAWCLs}d zuMq5#H6Gp}mH|I-KJ&b#8?ljd;9tojdRJu`Jo1;~P(Y_qh2bf&Gq91SAy%iW;!#zn zgG!gC(~kwi8xp=G;Wo*C5O|no17jjgk7#2;r;RiU3))rY9HuJpo9NZ)?*eUF6sB)S zGQ1wxF7BmUFeXfYgjr!cmKg2=)M>A1gRWPp4U)eqr&3vK$YTj0J_5TL&>j7_<)4pl-B;al=B%m{-@H0a}qu&bv+O5>>X@jTpVqI zIK88^sy$0otJm_7(LxpFd3fS6 z~y{_y*-^+dh!jxK1q+!=h1h1=dzR#otM-TZB2n|f>T=17m;s*`jLNO36>`)D3I_zm0Cm~|7^XddP1GY{uY~;)W+fb#@Qj28pibYV@6%>7=%v6m zvY<5q$UgW7`cw72*h4&K6CGB^=%4AkfivK2)Xve*Xp1nxd0U+a$D$&jsk^}X^hNpw zrPQnFy+^+$XMG%emUC6YrvU$io}%aUPXXSiJxdMZhlu`Fs;VziOgyfA1su+hEuuB> z*T~rSgMXd=So;k`;=pD4(PC-fJP3ty#|WEQC4 zg;41RC`;W!tNQy<;rB3kwE~fwwMJhTgA(ICyW@`UkNWIStsGJtsX)ux>t7@zORvy4 zZh2+Q*^J>CGlpxP@1bGK_0XI$bDr(&qio3ox}PR&?*JVcvGbLJc^{#iQ+CRjp&_eK z;I`=IY^Pw&(By*anZ;DvE)*cavP*92m{~F%D@XnLJWUvR%O0qBo?RL?X3T;KmQ|d_ z+&pBJ@|1Cmi)q8j)3jAKq0Xd?>3WX6An|O*a?7@B%oI$TGreerb z7Ru&vqm&2dnCUS!@3dN3aHeIkb|WwjEZBRZ`xZ9W{#P%5Gwb z@QGW-;;`-k_>89IRys zACTrn+j(gHcsSW)sqp6d&TMJcc8UhO+9>>wqtbS1)|#t0a@?|zv|TJ)1<9N+3&tgh zxy$`^i^m+eBrEf)5x37+O9F%DtVGQh3`p;Og@AxbO-E9lFA~=mQi3WE(6Zfb5r)*T){-96I+Jm zlugI8Om{^`*+AS@k6WhjnO~aY=|~Ei%1jw^GXMGu1u$LSGq8RF24fhF8F|@qhE9S} zFej1eInT^XG32hINzv-zi-j74Q=*CC~3)J0oLVu#iB$=xk=hcnAcCYSKik z4U{*o5rd^l(e$Ylmpn@4WK#=^EQ9rRXDnl`WV@b~bL*^nq}X0;Q)kk2E?7C!trY;+ z#)ZpWlXf)Ab+ew6E_utSAKA$=HqME%ETH}ZIB2ZIC7d<^=76UQhU=nI=3y+WDCG=~ zCSWq1n0b&JhXLH5gB>SkXI&E%SO`{~l3U03*KyODoA*}bQ;o&GnD=`T?`#pq~mU>-wFlL$*l+o;iGxwDqzdNg8RFh}`Bi1U;#$@vS*x$!=8 zfeQSDV8qKm1PIk5m4auL3k$U5J1!(AJy~X!bEwW3#52KL;D_9yA-oq^_;x{Arv!Oq z1Lnv9ZGbXsJnU*YCIika;d5qp8T}40e_melOW+md92=t&w421i-DqcjjShqh5-sRR zKxawnF`z}x3hbs7iONav4Vsaf>$WZHO~7KdW^_sG4CoxFinJ?%*}NJLrwbN1DQIMy zP4GQX{_J{NmqO=V%INnaA)Ora^oi4$=^vBfO1Z^&IP*jIAGW_6}+k zJT(vhxM+R9rQy9Id^Ux4b^JM^HawZYo7oiR%s}?~QPjNN2I`$$VSyic&M`k@M}MR>jzt(&OS$4LWq!>AQ1o(i!m9+M^D_0S*jj4 zarbCJB^u@Kcu#;75mh2VZF9U=#E(Wp@uRwrqInn`e3LNUj8{%f;#tiUQuHX~DpE!> zL0KpeRPKl>5I%_eXhQepOpomAb1jQGF zO+ws>Rttlp2bK6>Jc5s%c=d@ux4<{CqDO)W4RRup)?he}CN{n~b`mzmk1Fvqv9mD) z+C*#|_C$fjMxwwXSi6W-pV6_<*myKZs%VNtqM-!w+-A~!5wHMDOi--)945f>=P**i z1chxo0}wmQz|i5gSoO~oJ;ci5i%q1*7vqbuv#`L3Rllr2r-FBI5qjx^51iU^;En6S znnM*`VLwEp!GxkTMVnv?n*@&~DT-SOiQ0+yo&2&srL;^tMtRgO4PMHbvbImnJN89a zV4Naf#YY5fON|arExinO)!qP(;uPjkY9E9|H!XGY8)v~-;Fr`*JS(x(laQn1f;R9Y zW2so;KtfPpV!9`VGrNeOAdu9)6b|dwTzqD;@_L|lX3o3|j3*ddf7Q>{{T@_&CsQbl z7*@&uKrl`Diow0N+96}Dn)L#I>l{A!kpGIPu2#hXBR;EN$LDd!ai8uZdfN{hvw-7l zlTOhjs>CT&q6uJGRHsqUS->Ixzb^DO?VVrw-*^Jwczhb*w>XZJ7k|jD5G#2ZKmn;- z*N0FmxVB|czqo?%wNri}PNCNT*F`@+)hzUuWIv7)wP6SqunBJkwQ93oQc{lT#=8CA z0n|MBfR0cUbL*9obu27Bk61yy=hsw6RAru9*Tqj(yu3&o%ByU=os4emqh%SVAcLRD z%j@gGbB^zQxH+3MI3E+zL;P%aV6Oq6EIs>fV=q4^xh4}~|3bzv=FiF5Y+o7cX7A0R zf_oT~z&$K=ov87-jaPS*P#kG03uEM@2rrmaV>>4E$eD`e^mswVqn* tr^9kiKYYng%%Xe;S-`6Pw|Q93@9u?!=5y_juBd6hyNmgM%YRc3{5KBnat#0g literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/CompVehicle.dll b/1.1/Assemblies/CompVehicle.dll new file mode 100644 index 0000000000000000000000000000000000000000..ca3d905c007e03f6cc9b582ea533d6ed3dd5aa0b GIT binary patch literal 87040 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 F{{?zMgVF#1 literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/PawnShields.dll b/1.1/Assemblies/PawnShields.dll new file mode 100644 index 0000000000000000000000000000000000000000..ed5a0b061ea06459fda366ae719ea297f6620ffc GIT binary patch literal 34816 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 I{x%Q%U+Ig4e*gdg literal 0 HcmV?d00001 diff --git a/1.1/Assemblies/ThinkNodes.dll b/1.1/Assemblies/ThinkNodes.dll new file mode 100644 index 0000000000000000000000000000000000000000..365ed2c2e133443b31d4713ab6c72e3c34d78688 GIT binary patch literal 8704 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

    oyxD?%jX;DCHWfd_O|T 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 E7wOyFjQ{`u literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/AbilityUser.dll b/1.2/Assemblies/AbilityUser.dll new file mode 100644 index 0000000000000000000000000000000000000000..a96437215694d82e783971ff2e3367f3805776c7 GIT binary patch literal 68096 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

    YiSQ__y5HOSV@X;zBK`NAv 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 XEdOu)8&AQN$gmju&;I>?M}hwhbECTv literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/AbilityUserAI.dll b/1.2/Assemblies/AbilityUserAI.dll new file mode 100644 index 0000000000000000000000000000000000000000..2ddc9b1ec44507c2dc3ff21b52f2a15f62beb996 GIT binary patch literal 26112 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 literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/CompAnimated.dll b/1.2/Assemblies/CompAnimated.dll new file mode 100644 index 0000000000000000000000000000000000000000..5d4831222290a943a34aa89ceabe4d0ecc9f31d7 GIT binary patch literal 12288 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 wpRSiXrQh($ literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/CompBalloon.dll b/1.2/Assemblies/CompBalloon.dll new file mode 100644 index 0000000000000000000000000000000000000000..56b0136c48012bb90751c13b74ce31d34d0af742 GIT binary patch literal 6144 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 CDh5;l literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/CompBigBox.dll b/1.2/Assemblies/CompBigBox.dll new file mode 100644 index 0000000000000000000000000000000000000000..304c8556ffda002c60911323865d4b71994ff38a GIT binary patch literal 6656 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 literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/CompExtraSounds.dll b/1.2/Assemblies/CompExtraSounds.dll new file mode 100644 index 0000000000000000000000000000000000000000..5e7f1ed8ce66f8600747c9dd29ac019189b307de GIT binary patch literal 5632 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 D$nc+$ literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/CompToggleDef.dll b/1.2/Assemblies/CompToggleDef.dll new file mode 100644 index 0000000000000000000000000000000000000000..d54c0378111249088589ac61f5763df34272ae3a GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/CompVehicle.dll b/1.2/Assemblies/CompVehicle.dll new file mode 100644 index 0000000000000000000000000000000000000000..ba1510424dc59671ede58828f9d08f74c8002e39 GIT binary patch literal 87552 zcmd4437AyH)jwSKcK5x#%nbA_-8~D;FfhZVm)U`t0fu4N7g11jzztDU7P;7iYt!Qh zN{suiam5{tM&lBV;;v|n3mUg1NZg_rjlpOV<1+q#=Tvp~9Twl@|GnS$eDgrvI;W~m zojP^u)T!m(-e=K;!X<=okV;G?zF_ z>$pEt+qfL>ge>`5L81oH+Sxuf>O)A84d?y5^JU1=jD@hZSG%iw_B@^v|iar7&+i~fi= zU3kQlO{nx~AqJM@EdNn3RJVo*;g23DpSmkeouqrxAn1;sudgLA31D@|LKxH6QbID! z2&BcL)w;{_phKhWh*W}BHJUeZQFJcADu8+l-Q>21Q7xzqss5-CMGbE8vEon%PKaF4 zGaPx+#VDm$f3oF?$>~y#zVzapj&wOk?|k;Qv1xQKGOXK_8k}7 z5KqY!)Og6nt@ok@{&X`%6{q&IJ%TJRXyo zdM^c7lL*)LUV=!!@f4WpK|}mCeUxHBy<#L7G{~R0LJ9^9=L93=5*5c?A?1>39`!vp z57MIM{eRZBaIS5a4Q$)fxwcWt|9#s?JGpJpiT|CpaSy3}i_aL)f6jg@%eC$Dfo*#x z*EUM|@7va-r&`d*C!o7Dsf)U>p=nTnV9#izU`&w`#t(NYW8*vpNllFIqKRb#T0$d@ z6x1FAav7a^X|FnEiLr-EodR!TQDhC~HC^)N7WaWSH+a)ivk__MVG~YMT(^P{hTTd$ z8*S$!pJ5?qEYtxh3#0c6Hvn088WUlF>6f(E5#KDqCYCQ0%2?(}g%u0J>bpW&{ zBG^7UP<9>$gH{tto(ThRV@)`h?Z%o&@=uH`HE*;!kv(L=TKcz(DBBVt4idF#F}e!n ziyEp01|DV{v`2E^MU_lO;CIDaT=ohxw(gk-d|FTByTne`Fm!8tOfDY z{8Ntk=PZx|H|QU*=Z+5=pfy@l8NpggJJJCtQ@x)PMfTbs8&N3OUI!#4*(8%yv*#Yv zWzRu2&3 z#764g)CDMMm7sk^M$m{4GI<0Ajj%lr*=mEHaCea>=n1-;euqlgO0Sb`hhi!#t=hh? zSodnC?QU^C2DTS%??GD)XiNH9ZXwx#fMK#3NTXqHBSm4`5@eTA8?&sxZ9ZTnkLlT{ zlE)ZAuo_$YBX3Q@U0WOrS_fp~9(w`e$vVvDy$cbH`#{f- zv=;$(=(BY&;P$7p>DD0x-$!u5RUDfkvq~PuSu_GmkFMM5NXL-4}^2Pq9VrG$jPx z7J4FKot=Z9f)B#l~`A6N4470zlh& z$fDF>T{bG!pmB{%uxU)>#ZWhks+N7>3}1;)c4I1(#sF~Zp)~p`W6P4eP0R_84#y_#l!>CE5uvppc~)ktwjqva&YdfZk`NFY7bc*Os5 zgZ98aCIbshi#F~4ziI_w74c*A@^!k3x4O#rcX6D2{6jEod|CS?70+V<6Z0GKlU37` z;5`oEvs?(Udk9l0G1eLaMmPZb1TJ9MC*sL^kv<8rSWsg06y_o~qYV3GBqRo*uN+;5 zE&zitReFkgFk!-a%B~!&(3F|cT#9oihRWRG<`UHpBakUlXJ++)3R5mBlgovUQMn{7 zC^zStJ|Gubp>h#k(HQqHk}lZ@ESyL;k z5~+ke?vacLlzwDXh|G4pN)}`rPL@p>BZlqMvoNz4U!!WtDcBM{wGT;Ku6BkaS~-4E zW5;g!2Joktc4mTI@k0xUR;)mmM8n+-t7g=-s4i8KAJ~}GdTNXsYYdd8&&YCbpGm2u zN>?+vHUJs2e}a(LEwmu>XU7>EARGMn+x|kfksX}2KV_q87JNB}s6$?V>kU9;9RqYb z+^7h-QL#!nsdE=+k$zsj^_+#Gd1%m2@eFkw1`?tC)@gXiGCuokBoxsUatSOZBfv@ZlA=ni6iN-AZ+ zFEFy%PZ&icyg~2YNMPp4k?<-KSVTBTM2Uni==+aI_!NnDCkb+@{Jj?=Xs*h#HlQU# za%>pzli)xFJ@zFiF!A&LAAazKyYqcgj4bPkw*#r1sP_F4-_4Jjgmys{#031mA2R&{ z|JfJ=CVvuxPy`_Ao|nO=-*BZjf&r-?0W-eTw4g+>#GxjffLD;C=Q6NjW4VTvyG-ix z@@$zOt15KyY)RwJZ7)U^BSpmQD-ezA+e?w&jA-I5FzIqm>X572tC%Dbt0a3byVz+< z40lO6+E=2eg_%$dY5OWfL)O&@Yq7CZ4&I>mx|ju8u&5Xng~aYPNXNv|ZrImS{>Dbb zz7CN4w5B6%cSpRffuV~B1tPUNYLMI1PpNv#cJ@&;3E(S;bqdQ^m@R0&vZdjL4+zCzp0Ksep4 zj!SZgI?xKV-VZ?z++b*fHVEe)LkG+j5bLN0QX0pe7xsltlv#VB`OZc3b6`sCc~J`Q zoy2D;viG9u{Mc}eH_~vjwDt-_5j0g;> z%nq6yOC7hO{~S9ow5Cg;y?*-v1gT#kSPMP!ryfE8L$>F{UsIwPG?rFl8Q*zukrz+w z2K(eV&2OziC7Fi!gXn5lb-(>E1&<(*<2rI^xOsWdZ_vJEta)+JZ$FB()ME&A9rlwT z`*8$JoP(f`ca? zinz_8#zds3I!RPPU(iG{;@w3))s^k9$XNgeHrJcb=}B|sJOFu%2K@g7|6vdKPe<5+ z|4=I7fxMmg(*U>P|AWYs!51}n#OugA7@~0bJ=T*DjP(?P_{c)xNKOp8 z)U%ADu$yFwGFuStR)#YSEJMT=sxshj_cEMeU>PElDf9fE%5a8(Wr&RA&4?CZUWCyS z@FK7mL|VYs9XoTFgs?ng6^YS!g{uSSo&6$M81jpZoa+m}NFx30`m*0kei5czY_r6% zLpT#O5>Z)&^&6l=)(Z&pbw?dO>$gCqDQnbBl*vL^9C2a$MWpG)G8J~qCmumRVde|= zpo4giG4P^kO6@zr&2>f2NaYVwyA(_Z9`N!VEg&Ts!7L2P6$;~#%4qdPHI zN;2F$)ywi_yG_mtcGZG~9%;)BJ!nXO#Um{@9sGElV;z?L4=5Cs)Y?D*U8KmI-1822 zAV=Cr!;yfitmvlEeeUExAd{e(qPPua{q{BlIibMdnEl3fY6Zyni+pC#%R(UZpLT6r z(B}{Xs@aGl?Q7+9GJs(V6#Zro2>9)H5n!*Geb$$>p`T{<6N>e-u95o*9hLn(@1w37 zJ$)DW#8`C;vdQ$PTkoN~z80p=oh;Ykl7y^$%n170{RlG_m~e>J?!Z9(-N|_pgLxj9 zX@pq;j74@PWWl-tJD0FO0X9O5iWqs7z)mIXZ8aiuYbyD@i=j8QfJ@s600 zYC?)jZfkuCg1S|Qg6yNKD2AbO&({>dgRYh6i2a#jgV~{@V$|r5lFjw73?Rv%%l;h5 zaJ?4Qt-m1_$BJ$zWpnF=sfPsy5MJPX3Z}{x5fuqssvc?i8 z5sLkra2_)bC&)Vn?o}Y@$>Y_UVSj_9rsvJL*KN-8xaNhU?&5i#;(4LyVY>Y-(&G6# zAKJLAR*;K^qK`o=ZA5v5ib(~U$qJPotABawa%f?x< zU$-@c@oGoTaAUE{(g}-H7oOOM;iBkU51+J4xntGsk2Glzw2LJ@j=1pYhUvD(6K|vo zy70muD1q$UHoOHauM$2qrvR-AMgJ3V28tobR@fh5=48o|;JsPw1)wfJvl%}Py9B5z zM$TnC30KZUjVUnTk00fPQa+%JlpkU9Y*#8k89LxRxw@p zx%)8T7nn+8rIxysmb&AGo}8Atl$K(HZwSg_T$lpBi3k(z1V)6*MpgdwJRX3H5cRw4 zB5)jVg?MoF6ayelooULWz!JbdJA^P5Mo?@;5R&@to?eQSbQuC~(5+TpYR7?kBt?|$ zas*8`(@~G*MGsT}H1rg)6UGso(O*)I;f_ga2oh>DXFXott!R3gE_@6{0tP(VM7mUk zXN1P#bia!>HVu~r+vkrL=tjcpqBUGBriJIT98gk}BJWm6K;w%P$!E!4SAilflpthV zgOLtt#oAyMus*2<+Taryj@A|Fso^;kMVqnM7=dRXW*Rou8*t9_kSyYsq-=~1BNay* z4Qn}~-2vU;Zm?>R9V>Ca={4+;h<69fs;9taqrnfX@_R{g*yHlY7dn8{C}8q^;e}J( z#3lY?x)DS1pVTK-XO=Dsn3dz}YbwVFVpV2@pr-n8Wm6zlXa-^h<_hG)tr{x|Isum% zwql4J5W=8N>fC&|i2Rg0+8!5;PTbfiYB0p-sI!b@ZpBfEWoY9N$8Vz}unpg~73l_d zhGCH;vE+Z0P;soV*s|)OD0#gu>EQav>!oJ$ZeSMax9UNYz21B*PSVt?dnlOPL%|;4 z1{Pc-{pwT$NXCmCfZYg8xE_SJ&dzGZE6|GKVyg*BdRQHIt1`{NojV0NZ?szwtwl>x zqY+7sL2v>*2QAOrb}{g;W|g0cBGiRQp5(MeahkMSQn?1I;vT zxI{+VU!Zds#57>3667Fmtxn1h|1dR)BHmaM(JqSmVh7405%h(E-k!;nc?yDfo1-~< zl7*tYn;b&XAZ!b5r=p6fpwxJM&P*x$H5!-v0>dLY9}Aa-gkXKWC zg)Tm)PAvoldl3R0rK&2cP$lLV7jH4*C{>{`r!iWVv(auox?VZ_X#V?rVoNq_rOcWs zIZT3KUgK>;zri5_U#}yU;j8UA0CW?eud{n_rrZdiLXD?}EL=Rm8srd!)u?M?F6cQF zIO{M3y{95GdLAAHj%bTazW>yVxyo%Fj$~Z9R4B}E3dJ4b9we;AL>LoASI-fMnbs17 z){zKQ%aP^|b*zUNi9>G}IQ-9eN})uaL3g5vC+{vi<;8*umE|dKFFbj7<0Cpi+l%&cD#IzX_Ba$g(3s`L7j_0$P|NuSlZW<-VCCWyUGed{ zy^@Nx80-Ng;>l64?J~E098z*SJ-n;ay9&6lWg~R77wb|fzdiWi1LaqoZMol+PAE4T z<*6TrXXIwDMg`z7oXwtZvYKTjy~Q;>5qIhK@yOWw=)j)-hI$&;(b3bCLTjej{LI<{ zl9qDGtSqF-Pq_8{Vp{P$=!1*x9qbN#;WeNl7gyE^RMTSvYxP6Gp&H9t8Os_DLv{6K(os6n107469P3=VVGl^?aJ=_S&Zau8pp8rA|d8 zcVFDbQJEhi2+jY|G?MEu)n>?REea({q)tJ=SfOAi#)!E?yr5G3fQdrNXutUIfntgm zx#UfQfME|p!Gud^nYjfmtg1+6sWhrc^&;qfe4wMT*f>T&C%63?B@GK@W9`2{ zG!$t48DUJj59xVc$#S8W=Vsh3tMsv|#=~B|1krmsa`mi3kY0}w5;oug!_@b9&rcAOWJ(-aa@5T*)^hTAY2v}~_OfHZEntFn zZ9m$EeY;HC{y@>*CkBe-d*IZO9i{O7Io?5s6fQvlhcpMuqtemLL{2y}ecYe%Nk883 zv-Z^RnsEB3|4I8DJh5Lg@gPV7UVHk0jnb5;g z!@daR)EH@!ncVV#-|rTGf_~IE>XK7I+Y3Ou;$G#n zRwkc?{B$*U@{M2XYS58a8_2hvj~e18w%YDM#3ipbRLEyd!c`j^imMdYphVcZ6B%l8 z`-?$W_8tQ*G1?kXt8@3BT^Bd5)b%K7Z$!ZJCLF7MBrbIWaHiA@-E`YG z0(8e4_?`#u#$cxK$EuS{!HLV+HOX^;VK-gAroa|ju4#TL9$6{Rj_8ilUm@LE^u01j zx1gAuAz(1z967Hu&c}su)IRX);sk3kSQv;K)%!GB?(jlKnO;P!ro_C9(X5Bu2Qs|Hc$%tKW!0|S32nOWONV)5F4zC z7L^dpCcs+7LiH8N7%+R3A8lQ7-OmoJThG-^DXfW!H7f6xfqBu)jMh?$%sWHneQsc0 zcP=lb$h;NF6?^B;OdPA4bvH5<+ndmvHb!DhVV@p|9n-$`i0rED9ZFMsxW#g>Hu=Tg ztCB3^I39;PvPJgos11Abqmz|}Snaj%AQfB!ow43TKwHv3C(Ka*yw*~LYQb|1qS!Gi za<^jp242~n$OYSa7asO65Tx!#5b3PjE%6@U`SL34ZpR=bhlwhSKz?vlJ>V>s(+E)(=;#VkB(?=;524c*wCw~iua-+lO{msBq zMy?d4a4GviP$Bz3>%VDu!tcPjofLh$&IdcGhmgnqHG;UMR#HQpE2(@o<+}ASa^U`C z%pHztSe;3lHfW9_nhw7P3$Vjf=gpO)6fVbCRd7Irl`M`HuBEZlu@Z4C7eg__uq0*? zVR%}}Z*4+6bE6NlQX&ucSNK+W&=af0^hBN+yE!$9{8~qv-+CO)hx3hcG>#D?K9pt51u%-_H*+@&7kd6#+`_f?tY+~|$f7JB8}=##BZ z=-cCF&}Y*O7{|>RA76W>TpK|x@havvuXAq8mZ|`IJj*SRGnwI>P0jYF_Hez= zWLcY1){R=UT0C*e6r5{Zhnn+aLzJ-DHIN%wb!fHMdIGHGA(0vU0~j1|XAm23E4&9U zI{?Zw2?H7WAPz^*HRE|Pp4dv@Kf+^>iF@(Hm>Gblwf$7!w(o-Xp%BQ5W;`==NOvb8 zUyO8@of|CMT5Ew(y93NV&gRIldRaf(Fd?a^O{x*<_!2~Mwcz*kfc?h)ph}1ReiAw4 zs|Du(4KJ9w9`6^>YK(70`8e9V+{?!Re5oA=U|s0JddQIus`!p>>O3mvNu7lU$N6=@ zco~xWD8*E+z7FgD6lmk#yH{@aKOl7=FYBk^l}Kg4nHjmlCTAyODP=pkaTA+?R~Jf1 zKPQ$0_7?MU!MRoOGW3IFEB)Ye#J+!!A}0UkYT)B&d(YG03;xS~_A`j!YR)Q1IUX^R zn&~vAGBtLX4hsX5X2cILb^BSAuvP=gqnoLxPH7osB!{C|p`M&grMFP}5-`ZKEKdQ7 zPRK~^zX$p*L$0%)L&14;KJ5~4U_^rYDAeyRa37BQ<>#QFT!d})Yngr9YrLqh3dM@E z`?lp+zrrG*ZT!M^@AJgXZxF0m2$2Llp(fMx*jV)WvCQ}_JxuFGJnWYcAT?mUOi23` zgrU4x((tlUu@>OOd$ze6nHts0C;)E_$lYUq#6EpV4M$IW=T znZgN+Khj*b*8;=2zz`F5PUX#z@)>684V3QAa`Pr2-F^$9^)>>$PoGQsJ*UCT=FO2- zj3`0-9@t*vRjjDF8nj{DsO9(tkDNDQKD=9EKmk;#FA zCxoFm@nOiCySc&dCl>?_ndUJn6WzI`t#q7LV3@hu?gne{=2~G%-MvO=JSVn%=+q?QI^rM_T*n|T5{SEF;~#Nf=4vyba-dMD_Q zCxZUepHL<-0zO|gMT!s^P7%LRwF9dO^qbeHx*S}AapeM5`X(*}(*{1c!cwR#ZGv0) zE=u7Tly#;Z`C-$rA2fqRmFouDDJzA&r5HUX8Q7BZi^SV z_RGNcK{O7--SigBG0_b*qMi`H!{>n=YyxjEv`FAE(6a+f(eD!+W z<9|VbTUzDVz4?@)23GO*XNV=d6vL*7A4!8iIk9bf9=3)|fS8W`+sq8HlepT&%cmdQ z9iUf6E<%}ZKhHwCoUKlx;bDJH^v&3COnHB!C@S!>{&0P9l=bp*Wd&)etnzhKX`)I~ zRcY-+!IjW$`8URIR0~vWE;<tejXtb$3D; z0(O$V5Aa7AN+U%fvmO|vSzn+UNb=mSF^x`WAxRhSR2YLaPPP7ye1o(a>q|U?Mz{49 zo-XSj2;;b-_D?+BxSomiCU#?to__%zgqLJ68Z`TB06qUkV10uCPg-CIR<8QwUqLk9<+x&qe~@N-=h4Yyj-?Jx*A=y(BPBp3O?CJ;&;g9>qcZT zRrk`1FHTrQ5OJ=MzJ&u)2~u)EoB8xQIRzt%53l8cd7&G5h%g?CP_9I#t^s7MBapk0 zt{O>x5TSy25L-TKe&?cv0Ev!wA!o-OMC*HiwFRCyt{jG}egG!zV6wDmdmM|+9Y$Mf?s^RMCXpRen2_;ddVS-Eln<_rv(L3>pVAq7Y1jwG?qFi`E#fD zp~)>?s2Z>bb!fY)MUo!CtO zC9+}wlWpbuj^w?v6~K`-Vq{owg-RMOw#YP$yYsT%rrV~SilzrzujE?1t?Ti`5M@`# zQH%_^!<6`9lQ4&|DWUxkVoXl89qG2Gs4g(>5-p9q%Zo>zJ02}` zL0Pc0!3RVT@#j1=oCs|C;t<(zvl#_{hh_Mr1}JmNvfX)NUAN_K&a z+#bhdi_@ay>MR0tbonh3GM8$ zfV~-l{hC#ZEOB23fsKjGaa|b_Ce}f{qd9$4e5&R++W?f3-ShH}QF6xssX055=D)EX zysJlcW+=~puJksV|2*k;cp9WIiC2dmor~S4Tph50(z1aC#7TdZ$v>nER*u@PL_(I{ zNHM)xpr>?U1bPiOgczO7Rzp}E!YA(mCbv%)4uvhepyO|YwG&t!Emq}Tpj<%|u`7@o z;;Xy%5JYc*XP~uVF(G<~0+cVA87XRD$gTuN5%?@yaTSn#-AHfUh*HHx9yjj78P+hM z(ZG$JEz>g)&6xFh$*(dT#zrK^=V3)FGZ&eK=3XrV{Hp_f@uK93$e(K+u$=`oKcJSe zh^Pu4%Vdg`CyjiudXVuWbfJpXV72`WbjH>rFz3np?wu&7cEx4uGuNB30ve9|@>a8y z)+Q7!FyocU!%!&4onuF~^-LOE+ezC!)(8}bKT}Em%v(T(ime);>~|559q!=a#$9<( z{nP@r;F{x&|8*zfIEM@(WL7mvDceHe$T~VzPfoHg4`@$Dm*UO6wcuB(hJ)RYeuUjx z)Ilbj>+Rlag?MMoA;4^fczu!-F#JC#AWq({gq+n#lg-(Cir8@@-gCA97qoq{BhCP? zS!p;`=G6gx1n+SziqcxC3>Q zoip4{BG)XA?_H2jBYm>bScq9(_Q>R`Owu8v)flh$vM<`RJL8p(*DJj2)A<0T=>~d} z27a5z;eDNq5l1&NGH=hQEulYzqO)`>ipurmc(f!PLsYI~HM$!su&xgl)3qDolTN$w zly^PMxNiE@J2#rBLf&!Cyv4e8DqO&Lo_yMc0Fa&5wpbHm#U+Bhhe5mS1Snc{2xzBZ zIF_>Yh^HVn)W}88+wdfl%h3~R#1V0nNkMtN=Cpgg8js_i`rBsw=Z&p*JS530UAQ>Kht^^kR zYIg0Lv`|mM#=6-*;~aU0zIHJ%c(Derjrw(%hSMPwJWaz|hnUq0wB3eaXmh?!Yd5$a zX(rMRB+G6Vc%?tx8b>s6`xl{@AHyL-n2y<$uWUf4Vw73+F9mph7&2@w*V zUDV(e*tw?n^@BZ_6nUNd9u=@AfB;^_S^^;bE&?M(A aoC48%-&9W?P82gHuW#Z) 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 Oe^$5tUvK_C5Bz_1pM)v^ literal 0 HcmV?d00001 diff --git a/1.2/Assemblies/ThinkNodes.dll b/1.2/Assemblies/ThinkNodes.dll new file mode 100644 index 0000000000000000000000000000000000000000..3290574a09657000b4b364830da7a9eb8b2c5fae GIT binary patch literal 8704 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 RwxaLa~T-ewYkPC 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 literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/AbilityUser.dll b/1.3/Assemblies/AbilityUser.dll new file mode 100644 index 0000000000000000000000000000000000000000..8172d2ee645df164031d9dffafb5654993304b39 GIT binary patch literal 76288 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 ChZ<%8 literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompActivatableEffect.dll b/1.3/Assemblies/CompActivatableEffect.dll new file mode 100644 index 0000000000000000000000000000000000000000..16126188bb66261d132a78e964e97bedb86a1ace GIT binary patch literal 16896 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 E1C;U!Q2+n{ literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompAnimated.dll b/1.3/Assemblies/CompAnimated.dll new file mode 100644 index 0000000000000000000000000000000000000000..09fdfc1e4739b1e68e63e6fc0692869cf30fd8d0 GIT binary patch literal 12288 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 Ny;Jyq%m4Qt_;2Vj0=xhK literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompBalloon.dll b/1.3/Assemblies/CompBalloon.dll new file mode 100644 index 0000000000000000000000000000000000000000..42220e938650802d17eb9933f3695f6dae45466b GIT binary patch literal 6144 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 literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompBigBox.dll b/1.3/Assemblies/CompBigBox.dll new file mode 100644 index 0000000000000000000000000000000000000000..314790952222d51ea8e20d51a86c6ac19519ba40 GIT binary patch literal 6656 zcmeHLYiu0V6+ZLWhc~w4U2mKO^4L5`7bn@+v7rgC__a=4;>5{1385f+ynDSKJUg?@ z%n~~($Vd>0s)e8yP^!|3QVCV+4^UA-RZELh(IN_^5~^B|5QvIWsa0P{Ek!E*&Yf9% zV;(JkDc7EJ&pG$J?z!jQJF}zLpCgTkbUg39NAx6mZhaDdG+4lJ>&73n(&J6fZ+cQW z`242v8Pm&DU8n3Cl}ypFZO6|{iHuvbGp3yxI$X$9oRY}3v?R8MrpNL`2NjKuq^F*! zdwY#GXI3a(L@98h0e1sP%HZk4L)0d5HHe!Tp%~Eu2=KXSGdImGocdS#hD2l|6bU-^y?2M@$PCIK&sad2Zp?-m7 zU4&5W$O3L>vmGoz)ZP`PemPf4x(K7{t;WEMaH3|Bu0-O+jR;<%ocC%vom~rd)cpz* z-bKLE>9lh(`fV@=dok*U4@@Sh))0k~i0<7CM)VBIC2`44eOr2agrkVAi0y6S-dT@< z=GYmi=sVZOV`s2bdUiv=gn-_%=S#30br4A+n_;jCU`Gc;n;Jw>UV6*+QYeRYYmkdI z$YEC)@R8Wc79Jk!0ke-OqM(uIBs=6h1eg zgw@8idrNPwE7#N2)4dl2>d^w+gUGhrM)Ym;KS9J>3chRFWsfCFi0>uzTaFcI58~$S zv}OOXks1BoC0}?(i;abTb zm-u(}l$N0L>J>_qn&^5;&{pjVrIprG2jC@u2|BA^0ayb+L0<=qQm2yATInsd19%&> zT4}Auk`KX7f__O1w?QjKw?&2#?JLAyp3=_Y$eGlcb6V@yQuH)2z6+5g=&Mq9r_}vg z_+m$wYEV3(dnWPlNu?ti`DC8Sd8Pq7wCXE)LnU#_) zI3J^QkJ^T~U)R%sx6>NHvy$^`$uTAVJ&E5c@#iG&N&LqWe?q%h8Ov}a_tS7>qoU9~ zk~+KQ1&#ebAgO0ak1%yUq+Z49sq{!7Nd+nSd^mQcjQh=CEVS|$N!`2VC2gCcQr{** zyO)|GouD`e4{~AA%YZ8V0|leeeJB;3_Ulc=aU=mFv{vGq029;=*hYIL?3Zvv!Xpx% zl+cjyJAew^OqRYGIebg+25izUL%x`Qo_H?5q8eQZcs8;R9G=1J^oE)T&N6?Hb{?ZY z(MeL2pVK5Il@~Mz{HN7m5OMeg6G5#?vDY!lKe?NZ zi=ywi^}dIWI({!*HR_aVmbixUb5+L^LxykA0mH30_WVI}iYi{waV;Q)dCwP>+@NDw zFaw)jZojaFYZj?2{E0%}oE83< zNKaKoV@IWFLkn5vb_#*`)ceVp7=HD6G_=ZVUcH9v0pjqGv5 z#l(m4`Y290?(C9$e$E%RhYT&T>L!LwOR%F492~Ky9k*i0^|C%xYS6K#&2r6^a!Vct zol4b2eqs5ju#7p0c}wH<2*zA2chP_U02?su`K5s{-;(c}Q>KN~E{)ob>(3O-(}Fyw z7GlEie91b6Wedhw0B_oMc}PrC36CV|#T2^8g_DICjTwG%hK5|@)Tr=g2Kks52*NDtO{8g;R_ zN>UVCL1t_*GBF*NDGknu;_M+IN}jAnB#(_a)rtO6NmedmK4pic#A~=%FgpheGlpB0 z4r)~@u!|zr4>b)dj(gY!%k?o-LFR-@i+h9T4?4$EfU?`~8r2!I=+#3UGL5qBcrfYF z#Kgo@u$>M%OA__;2DKsFf^cs!ivkvkC~YxuR7?w3*vtv)9t*%*P1^J1J{`x7^Qhl0 zqw?oWU`0rKBw@bIc1TU;dhn`;K|oaJkK%$FOA0^4B|WupXX<3@`qWAMH)S-inMh|MJh1TP)WThh|E;lDYBbfH97*Qm@ubkBsfBy> z3?)b6q=JdR2&jeoaM1!bk*cD@KQ8KIes!A?Q`RR(Hb6d^UzIY{4b+^>H){!H9Se-a zU_`(;n|-K-A__W)iqwtq_!FmZIKH;`wY#)vGLL6OjjCESb%bZpoZ5>Q0A(fV>N=QD z-N>fbHS2uw$CdDFeFMJ;jH?|da4;Nl?EG9&RQYTgpK+a2o&vexonus?b-6?N@x`lZ zM|j>|jW3wb=61tKYkF~T$n@|IF@FfxTAH;oiz68+y;7k>!%m=tLXo2$Y6|0Pwd?V|yFFQPf*2f7fT~)Uuw(78|y_J7ig-hG_>cCPK(lp9S8#1U8nt zS=9U#`J`olzue@{Mhh3tEOa{SxTb$vv?3AP5afcF9($9Xsbn5Uz_M({>` z2=oZxaPX@e{Yd}wzk|2=U}tIAer#qR8$rW{4|kj-B^Ux!VAa5x$S0zOlW_#6@-)s? zZd;|+xIB0HthOLoKaHgTJ*w}469qB(kTRiL{s2p9Dbq#uzh0d7ymcp0wdQ*y?Vq$koIs-u>a}>@qL(n7tSbUG0x-AcNcFY zcHE6ysRvIN9zHCtp_P#5%mg=|jTo(lNI%FA-+X)na?2v~3LS)>veabxD(1=&muUu8 zNggr7($C?L&)H-@^?5QCWahv53-Zc09pAb&d58WldF_>XxlnI;c9!R6kJRZ${yfaD if|a!}vka>0!mKXWlZp8x0TeX literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompDeflector.dll b/1.3/Assemblies/CompDeflector.dll new file mode 100644 index 0000000000000000000000000000000000000000..d68d42210fb2e47bab7ba2e08303f8a6003e05d2 GIT binary patch literal 27648 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 literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompDelayedSpawner.dll b/1.3/Assemblies/CompDelayedSpawner.dll new file mode 100644 index 0000000000000000000000000000000000000000..234c054f8c2b9c95aa4de92149c73d9c3367fa0f GIT binary patch literal 8192 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 L{(p@BwG8|d+i%YR literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompInstalledPart.dll b/1.3/Assemblies/CompInstalledPart.dll new file mode 100644 index 0000000000000000000000000000000000000000..b20777a32ce1117aac52344f88bb5264c2a49d09 GIT binary patch literal 20480 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 J`G3v={|kE4@=X8$ literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompLumbering.dll b/1.3/Assemblies/CompLumbering.dll new file mode 100644 index 0000000000000000000000000000000000000000..1d1eb043288aae468df2073d7a91a0415a1f693d GIT binary patch literal 7168 zcmeHLU2GiH6+U-&cD>oeCc8^Xb>&$;K`d+y8(eDO|-5|M`cgAa&K;g_#=1wS6lL)>uQPa5daWzTOq zCHkM=G(2f~ddYPrT%)KL4BK{meN^i1w5^-A-gO|a7o9Pgt*=jR4qXp+6ZMNIeN{Bw zQi*n&&exZV9Ym|ai3i-yo%q#px8o*SsqjdUH#0&tqInSD^A)Az@VQd`SARn?P@#Xc z5*=W?ooF8yV(E39Xa#sLL2tuS*~ig3QKCkk0KKn<&ieAC4|-o305Ub!FmF)m(us~| zUC%9mQn|GQ;fZR*U30Y~`>ZQ12a2349mmbS&cx_ABFF2M5}g0=pbCecPf%Wg7GpWT1zgH0W0pnCb?z1 zcERfAR2eCRc&vOD@MOGYL)^h!CgU}xP6~`UlrRbR@E@ZU@C47b{@eZw*(VCo_98Tc zD1m-?6?pbJ$18y7CslmbLK! z3B6tb-rR)%+g9y}QWn~Lg~h`v(%^(>&si?!tEAryJd=TTs1U1BKu;*?ygNe$xQe%( z2E9}__bXP~3NH@kBN-`UCbTd7SZT6RxfxuZ;l}1zrUiK0w^$Y_L#Q>rFXs3+QsW?4 zB%DiTJJhe4V~1f>?09X<_UHx8jlqC3S!gt7E&|M;cOW`@Ye_^hSY+{L%pV3_Sv++t z(!(ijW$hpo*F}YLurHF^z8}f#V&M(!%Keg{Qez`4Hb-vYOk5M3HH{pgdE4H|nlQaR zYsy6ZCT|>$IFvR>phaz z#4>J5?}}aAL!d$^n(F^ZRrM<*M{v#hO3uF(9K%$)M0Z5l7UiTnB4@|q^m_&WBl#-VB0|FYTpKY3ouCsVHKxC(R-o|7!h-%^7goj(xC8T3cjVh zU99~4R7;}{b1LF%O8QFl-{3qT7(S#i>{FVK^8Z6|4@No!$aPu90MYnwCG|#oqpb^6 z7E}l7m_U{ON|S)yB8m*}rhede#p1yK6=fI|%K+bqP12yw{%%d&rqv5U*M`)oSQ?ZS zP;?ut1w9v1Pb%v5O)#Tp$U|;|HZ}#+5hc4yQMaypM`PL1Mbt8SM-!9+jMI9+By9y; zNv#UDDcGT4pMnP!JgT5UnfMwq=!MvNGU*iB%)NA0$!%w z(6O{D=?U5*a=@FleKbqwpcb>#3;0XAKRO7_)$w8a0X-7E2KWog>gia4{zx}PC&51+ zoua?c>6i`u%i@FJychB56?#>iBq838&B5vqu$raq@OeA^M*BKA4}p_HjlW6j#ZK*R z+9bXvzKa|>wFhXc=!`#1t>V_$Bh)4m@yDn`{4M$v9TXSEpM}oe*stlRcmq{3i0f&H z8=}7j&K0{!K~s#0H-Wz#dmFoKIlO0S6>S4Nhx!1Uuv)UzOy2?AMLz<(jGh9_DR{Nw z=K;^9OR)oazulp&#m}>`4T9+?xO`%3^Ssh{+3`N*s}}@X#=`Y3jVoN)=sycZ^|dOY z?g_Q6d+93};p@2n9Pkgzg73IH>GA<*Y}%4vpu^JjWVWM^#%0m4WUp(KCe1>Z;Ttq2 zJrO#B4 z>l8!IA=~t4yX^_nmf4)+%Aoct&M^DxHHwmIlxV;(ZC~03@?%#Nj){vqiqTVk(ioHO z0;%Ruxtp0ZeMwz%bb4aK7`0@Fk8@^p8oUnAlf_YMcG&c5*~5m5N$SBvzMOH~sWbI^ zOiQwV)3MJK_Sxf(TQqzK4eKMda*jQ2PE5N>uj(Y{6icS1m_yPsPAbf+$}1TUx>%|O z|4acpFznf?Ae;-u_svn$LfNa*G1r*Mo7bayyaKx9IN=?~o}m1!=gVR?G|q;@Uqwso*T9erJM8hCf-Et&xFg%QuxS&oboB6ch?m9kz+Bw%AE_ z%(B8vC^zjp(|&%+w0SM%91BZkEKF-5TRCoFE2Hpg0S9B^>7Zan720PH7$x##!Li4@ zLFwjwSqcWtBU@M!+jCe?ZYf+R(}SV+aZu8V;#wAlwR~W(g5oA6(XF`%0KW)Vas8EQdMa?g$IjUsAHcyfl%+e9lpX5Y5HGcLR zV3nXAl@zZ4ot$NO9^%_**qkhnzk7TfYXot9HD6(!@*thkNMEsJnFZ6Qp`eGVLSa`J zShbjC%mb_}WA=b8^OKGru1b~3fO7%`*ze5X@n{eyWr3#fw*F8Kj{-$1;aHx=?cH*3`i=)WJ5Hb9>Cq9)roYQ zrc?SLs6)6FaTLhWcwHpjmc9b$wX6UnWq|0$Z2~VQ^=SHN+DsKwMV4O|iAN&wh8RT} z8sI)Pi-(X@am7lZrH?j1Z5C=tk)Es51r{?cZz$D!Vl6Akg9InO6jnuG_BGIJaI{~xw{9~#4Cs^aL#N*c= zJG_4P>DwdmL?pffiT81)dl;MNNQm%z&PINyAC5F0L0{PK*xe@!vcxTQc+z!d zJORDnIcz}ChV1_C;e}(eCG5sm;9c*M>`pjoSiK!*HNQCN;7bL!z@>bq`P<<&?L=<|3!hoQ zcLN?qCmR9mrXgT`_|m!`bRS?(@YR)`)c*c{@ct6)n z@ZrKsb$qRO-`s_J2X5ZtU6h7CSBQ^37rzE-QqB0IV`XuQSop(NJDwg*dN2=K><;!S<}J{d{~`#s~Rn~ zU0SK7b-Gm9bfA{}0KpF<7DlLJr7f=TQacR$vwLAd<8vW()tn2T-NAgG`KPVG{{RzD BvM>Mu literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompOverlays.dll b/1.3/Assemblies/CompOverlays.dll new file mode 100644 index 0000000000000000000000000000000000000000..e70e9016e84654eb249078bdc77276caf7a29012 GIT binary patch literal 5120 zcmeHLU2Ggz6+Sbw9mjo< z%gk&N*J(*nDYR6mg+4S0353c65|s+7M2J!W5=5=4hzKgwNC<@|Ktdn{NTm-o-?=ku zukADf@l=WH%(?gcpL@=kJ9l&B(HBW0q8Of~C8A51dGtzndvF2l4R>GOKyNf%+jU79 zyS8g;-tvu#=axLPY!pn#aRVbS46o`KmSYS~wm15Ym=qK$H`hH*0?5+k|*1aux6&3=(Z`QOSMp-jSf26iWS z(MvSKiC8;k!!YI{w_`2ucDO+luj9vokJRDWK%5JJ|F#(bJh|5>ZeVg4M6+4X_X@yd zY`s`;p*G;D8@-4=>j~S1Ag7FG@vyBlp1RRX)L)0n(V1CT(x$nbO1ASQtILz zV7sVXBC(}ecT-p-_w3LcU2G~*g#o3dX>VL@dQy65+bPsKlm18baxZ@2j67z(A{R>&1vQQ7R>jKBNe?p$EUX>4?M#n zp&c|@EbeZFKucrOBDNXJYy;97Yg$D6#P)VHEy6`CGPoVAR1NtAkdO|`MDCry_hdqO z7tM8h$@tde$#`85?p@G$cy4KF33<-!1k!$3&D@RoNsda*7)*Lz^>;Ce!&Wo!n^3PK zJ~h+E)ZHvX{kg;aN>p*~pEKRrj%-&)SLZ{D$FRA!r-s!2DL?V3(|REAxOuH8WgA)?dc$_Z7cwE7z0Wrg8c z3161*UlJYyOwhaPeM*9UKwp5CLXYA_i_;E8r(bCo!QDyB9nlzmMXtXlp(80dsXHkt z8v%97C>P=D_jHkiCiE5t=UG99u4q@Z&SmTaV13wIT=HH8Hj2DA0sAR^7qPU{_W(!L z*8p#5uLD+z*KccY&{2c!J{x~ty8`)>5%x>^889KStMn>l74jqOeu=#xv8SnkY$&u$}$U0a3ST!o=dnnHLxA&F+!67)&HjnpY28VKt?2}dP-M8Xpin)I@^ znM@g-NgUNh`WCF1bW`IUKdEJLp8Y|42=GO8Hj`{*UE!Q{!KzT{Rx9RU#y+q&8UZE^C z({;dBx&e46y${$%ijt*0Gy&K}Cg6i)0}e>|8A;Cp-i6atMNWyns$B*AHN7Ko4Uo^+ z2WXaJ7q}O=gJpAIz5;~bqT2W-;nRr0QmXOui1oXgcufp*1H0leX8FNvCryh&;Cfv& z=?2~O=_78jYKw>HkY`rrt-_!gn1t{1^7^Rj2Sev7t}i63>=#_mw(?XG!Kp}xatnSS z%Gm+ewqe_H9Y1?WIKs0EG*=b&r1)Ib@A!FmQ8Fr9@JMwCfO53IapBWWw#sxSOpP@S72T zn_i{X&*({1xj5{4l;yUs86LFEl7mLG3Vw}Li$6@K@N&XCV-k0cvoo6`rCbZ0!C-VfrjxIrO74=3owq1Q_B=EjEf z{!~vqolNzBs>TdT^{9F>6imiRP4)1fZYb%K=@ZO06Glt{%}k$20#BdBaRvcW(jsNS zn~4ADiN~h5ci(&t2)iFrbroUtG)6{QX(NOEu?(*O_Q#dzioKJ+sZ;8f860clt}}G5 zAS&EOQ}dpC)>j}Go|;D#+L0X}np%E|_eQPUgDcMi*?lmwVbd~m(DEzj<#D|5n^?;Ci={9KFM@-8hd1wnE-#X?l-3uFQ-K;mbj>0z+BHU*$tY&e3i8^jUXF2}uaJ-l3 z&taCCgmpLIH09_N;1Eq>HHu$adZ>o zAfN)PCV8-9;eIM$)1f(XC4aZnngZ7Z)d%0C0CFy{aJ(KHgHZ)B1(32pFWtft|5i}2 z>)Ky8B7^2hr6#I_cKLiD3G!aVzuic{wQBrDngEL|3n#7L7_3| zm!vl9RB)5x?3HL9v6F1u!_wD8MCZ)1uUf2(g<1Mfe1>^G3R^BBsUlB7UDUK(fm`Ld zTjprB?%GVP&C>y?(}#-q*k>8lwy{G4oyJvM$?#e|nV^p=Fv9;cc<;fF>jwTG_y3ZC Fe*?8z7=!=- literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompOversizedWeapon.dll b/1.3/Assemblies/CompOversizedWeapon.dll new file mode 100644 index 0000000000000000000000000000000000000000..7c546b78d932057d099e8fc0f4b3b255456c04bf GIT binary patch literal 8704 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 M4*hcW|IZBk4-*vd{Qv*} literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompSlotLoadable.dll b/1.3/Assemblies/CompSlotLoadable.dll new file mode 100644 index 0000000000000000000000000000000000000000..06b90070fa246603f649e9e5b9b82fb7389136b2 GIT binary patch literal 38400 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 literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/CompToggleDef.dll b/1.3/Assemblies/CompToggleDef.dll new file mode 100644 index 0000000000000000000000000000000000000000..8698d401b1acc07a5411149c1d52c6652e4219f3 GIT binary patch literal 13312 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 V)9U^0lke)^-zogT^Z$DU{s){Un4$mx literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/PawnShields.dll b/1.3/Assemblies/PawnShields.dll new file mode 100644 index 0000000000000000000000000000000000000000..c805aad6a929c1abb71cdcd76ac298be626101be GIT binary patch literal 35328 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 E0(Uq{-~a#s literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/ThinkNodes.dll b/1.3/Assemblies/ThinkNodes.dll new file mode 100644 index 0000000000000000000000000000000000000000..4a7f29571e1d2c9979e71442f2194d6211cf2856 GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/1.3/Defs/AbilityDefs/Abilities_Base.xml b/1.3/Defs/AbilityDefs/Abilities_Base.xml new file mode 100644 index 00000000..477dd882 --- /dev/null +++ b/1.3/Defs/AbilityDefs/Abilities_Base.xml @@ -0,0 +1,11 @@ + + + + + + + + UI/Glow_Corrupt + + + diff --git a/1.3/Defs/DamageDefs/AbilityUser_Damages.xml b/1.3/Defs/DamageDefs/AbilityUser_Damages.xml new file mode 100644 index 00000000..d07ddafd --- /dev/null +++ b/1.3/Defs/DamageDefs/AbilityUser_Damages.xml @@ -0,0 +1,23 @@ + + + + + Laser + DamageWorker_AddInjury + + true + false + false + true + {0} has been shot to death. + Burn + Heat + 15 + BlastFlame + (1, 0.7, 0.7) + (1, 1, 0.7) + Explosion_Flame + Damage_Flame + + + diff --git a/1.3/Defs/JobDefs/AbilityUser_Jobs.xml b/1.3/Defs/JobDefs/AbilityUser_Jobs.xml new file mode 100644 index 00000000..b39575ae --- /dev/null +++ b/1.3/Defs/JobDefs/AbilityUser_Jobs.xml @@ -0,0 +1,20 @@ + + + + + CastAbilityVerb + AbilityUser.JobDriver_CastAbilityVerb + Using an ability + true + false + + + + CastAbilitySelf + AbilityUser.JobDriver_CastAbilitySelf + Using an ability + true + false + + + \ No newline at end of file diff --git a/1.3/Defs/JobDefs/CompDeflector_Jobs.xml b/1.3/Defs/JobDefs/CompDeflector_Jobs.xml new file mode 100644 index 00000000..ec1ca382 --- /dev/null +++ b/1.3/Defs/JobDefs/CompDeflector_Jobs.xml @@ -0,0 +1,12 @@ + + + + + CastDeflectVerb + CompDeflector.JobDriver_CastDeflectVerb + Deflecting + true + false + + + \ No newline at end of file diff --git a/1.3/Defs/JobDefs/CompInstalledPart_Jobs.xml b/1.3/Defs/JobDefs/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..183535d5 --- /dev/null +++ b/1.3/Defs/JobDefs/CompInstalledPart_Jobs.xml @@ -0,0 +1,17 @@ + + + + CompInstalledPart_InstallPart + CompInstalledPart.JobDriver_InstallPart + installing TargetA. + false + + + + CompInstalledPart_UninstallPart + CompInstalledPart.JobDriver_UninstallPart + uninstalling TargetA. + false + + + diff --git a/1.3/Defs/JobDefs/CompSlotLoadable_Jobs.xml b/1.3/Defs/JobDefs/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..98af40fc --- /dev/null +++ b/1.3/Defs/JobDefs/CompSlotLoadable_Jobs.xml @@ -0,0 +1,10 @@ + + + + + GatherSlotItem + CompSlotLoadable.JobDriver_GatherSlotItem + equipping TargetA. + + + \ No newline at end of file diff --git a/1.3/Defs/PawnShields/Shields.xml b/1.3/Defs/PawnShields/Shields.xml new file mode 100644 index 00000000..b9c36f40 --- /dev/null +++ b/1.3/Defs/PawnShields/Shields.xml @@ -0,0 +1,212 @@ + + + + Shield + + 35 + + + + Shield_BaseMeleeBlockChance + + Shield users melee block chance is multiplied by this. The higher the better. + Shield + 5 + PawnShields.StatWorker_Shield_BaseMeleeBlockChance + 1 + 0.05 + PercentZero + false + + + + Shield_BaseRangedBlockChance + + Shield users ranged block chance is multiplied by this. The higher the better. + Shield + 4 + PawnShields.StatWorker_Shield_BaseRangedBlockChance + 0.5 + 0.05 + PercentZero + false + + + + Shield_DamageAbsorbed + + How much percent of damage the shield's hit points absorbs from a blocked attack. Note: a blocked attack deals no damage to the shield wielder. + Shield + 3 + PawnShields.StatWorker_Shield_DamageAbsorbed + 1 + 0.05 + PercentZero + false + + + + + ShieldFatigue + + HediffWithComps + Shield Fatigue + 1.0 + +

  • + -48.0 +
  • + + +
  • + + +
  • + Manipulation + -0.02 +
  • +
  • + Moving + -0.02 +
  • + + +
  • + 0.5 + + +
  • + Manipulation + -0.06 +
  • +
  • + Moving + -0.06 +
  • + + +
  • + 0.8 + + +
  • + Manipulation + -0.1 +
  • +
  • + Moving + -0.1 +
  • + + +
  • + 1.0 + + +
  • + Manipulation + -0.1 +
  • +
  • + Moving + -0.1 +
  • + + +
    + + + + + MeleeShieldBlockChance + + Chance to block with a shield a melee attack that would've otherwise hit. + PawnCombat + 99 + false + 0 + PercentZero + FloatOne + 0 + +
  • + Melee + 35 + 7 +
  • +
    + +
  • + Shield_BaseMeleeBlockChance +
  • +
    + +
  • + Moving + 18 +
  • +
  • + Sight + 8 + 1.4 +
  • +
    + + +
  • (0, 0.0)
  • +
  • (5, 0.10)
  • +
  • (20, 0.30)
  • +
  • (60, 0.50)
  • +
  • (100, 0.80)
  • +
  • (140, 0.90)
  • +
    +
    +
    + + + + RangedShieldBlockChance + + Chance to block with a shield a ranged attack that would've otherwise hit. + PawnCombat + 98 + false + 0 + PercentZero + FloatOne + 0 + +
  • + Melee + 15 + 3 +
  • +
    + +
  • + Moving + 18 +
  • +
  • + Sight + 8 + 1.4 +
  • +
    + +
  • + Shield_BaseRangedBlockChance +
  • +
    + + +
  • (0, 0.0)
  • +
  • (5, 0.05)
  • +
  • (20, 0.10)
  • +
  • (60, 0.30)
  • +
  • (100, 0.60)
  • +
  • (140, 0.80)
  • +
    +
    +
    +
    diff --git a/1.3/Defs/RulePackDefs/JT_DeflectionRules.xml b/1.3/Defs/RulePackDefs/JT_DeflectionRules.xml new file mode 100644 index 00000000..36125c88 --- /dev/null +++ b/1.3/Defs/RulePackDefs/JT_DeflectionRules.xml @@ -0,0 +1,198 @@ + + + + + Combat_RangedDamage + +
  • Combat_WoundIncludes
  • +
  • Combat_MeleeIncludes
  • +
    + + + +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets].
  • +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets] [to] [destroyed_suffix].
  • +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets] [expertly].
  • +
  • r_logentry(p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets].
  • +
  • r_logentry(p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite], [destroyed_present] [RECIPIENT_definite]'s [destroyed_targets].
  • +
  • r_logentry->[RECIPIENT_definite]'s [destroyed_targets] was [destroyed_past] by [INITIATOR_definite]'s [WEAPON_projectile_label].
  • +
  • r_logentry->[RECIPIENT_definite]'s [destroyed_targets] was [destroyed_past] by [INITIATOR_definite]'s [expert] [WEAPON_projectile_label].
  • +
  • r_logentry->[RECIPIENT_definite]'s [destroyed_targets] was [destroyed_past] into [destroyed_suffix] by [INITIATOR_definite]'s [WEAPON_projectile_label].
  • +
  • r_logentry->[INITIATOR_definite] [expertly] returned the incoming fire. It [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets].
  • +
  • r_logentry(p=0.7)->[INITIATOR_definite], wielding [INITIATOR_possessive] [WEAPON_label] [expertly], [damaged_past] [RECIPIENT_definite] in the [damaged_targets].
  • + + +
  • r_logentry(recipient_partDestroyed_count==0)->[INITIATOR_definite]'s [WEAPON_projectile_label] [damaged_past] [RECIPIENT_definite]'s [damaged_targets].
  • +
  • r_logentry(recipient_partDestroyed_count==0)->[INITIATOR_definite]'s [WEAPON_projectile_label] [damaged_past] [RECIPIENT_definite]'s [damaged_targets] [expertly].
  • +
  • r_logentry(recipient_partDestroyed_count==0,p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and [damaged_past] [RECIPIENT_definite]'s [damaged_targets].
  • +
  • r_logentry(recipient_partDestroyed_count==0,p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite], [damaged_present] [RECIPIENT_definite]'s [damaged_targets].
  • +
  • r_logentry(recipient_partDestroyed_count==0)->[RECIPIENT_definite]'s [damaged_targets] was [damaged_past] by [INITIATOR_definite]'s [WEAPON_projectile_label].
  • +
  • r_logentry(recipient_partDestroyed_count==0)->[RECIPIENT_definite]'s [damaged_targets] was [damaged_past] by [INITIATOR_definite]'s [expert] [WEAPON_projectile_label].
  • +
  • r_logentry(recipient_partDestroyed_count==0)->[RECIPIENT_definite]'s [damaged_targets] was [damaged_past] by [INITIATOR_definite]'s shot.
  • + + +
  • r_logentry(p=3)->[INITIATOR_definite]'s [WEAPON_projectile_label] [destroyed_past] [RECIPIENT_definite]'s [destroyed_targets] and [damaged_past] [RECIPIENT_possessive] [damaged_targets].
  • +
  • r_logentry(p=6)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite], [destroyed_present] [RECIPIENT_definite]'s [destroyed_targets] and [damaged_present] [RECIPIENT_possessive] [damaged_targets].
  • +
  • r_logentry(p=6)->[INITIATOR_definite] sent a wild ricochet - [destroyed_present] [RECIPIENT_definite]'s [destroyed_targets] and [damaged_present] [RECIPIENT_possessive] [damaged_targets].
  • + + +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite] with a [WEAPON_projectile_label].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite]'s [WEAPON_projectile_label] hit [RECIPIENT_definite].
  • +
  • r_logentry(p=0.4)->[INITIATOR_definite] [missed] [ORIGINALTARGET_definite] and hit [RECIPIENT_definite] with a [WEAPON_projectile_label].
  • +
  • r_logentry(p=0.4)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and hit [RECIPIENT_definite].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite] with a [WEAPON_projectile_label] intended for [ORIGINALTARGET_definite].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite] with a projectile.
  • + + +
  • WEAPON_projectile_label(p=0.05)->shot
  • +
  • WEAPON_projectile_label(p=0.05)->projectile
  • +
  • WEAPON_projectile_label(p=0.05)->blast
  • + +
  • destroyed_past->shattered
  • +
  • destroyed_past->crushed
  • +
  • destroyed_past->obliterated
  • +
  • destroyed_past->annihilated
  • +
  • destroyed_past->pierced
  • +
  • destroyed_past->perforated
  • +
  • destroyed_past->punctured
  • + +
  • destroyed_present->shattering
  • +
  • destroyed_present->crushing
  • +
  • destroyed_present->obliterating
  • +
  • destroyed_present->annihilating
  • +
  • destroyed_present->piercing
  • +
  • destroyed_present->perforating
  • +
  • destroyed_present->puncturing
  • + +
  • destroyed_suffix->pieces
  • +
  • destroyed_suffix->bits
  • +
  • destroyed_suffix->a fine mist
  • +
  • destroyed_suffix->fragments
  • +
  • destroyed_suffix(p=0.5)->a holey mess
  • +
  • destroyed_suffix(recipient_flesh!=Mechanoid,p=0.2)->ground beef
  • + +
  • damaged_past->wounded
  • +
  • damaged_past->injured
  • +
  • damaged_past->pierced
  • +
  • damaged_past->damaged
  • +
  • damaged_past->shot
  • + +
  • damaged_present->wounding
  • +
  • damaged_present->injuring
  • +
  • damaged_present->piercing
  • +
  • damaged_present->damaging
  • +
  • damaged_present->shooting
  • + +
  • damaged_suffix->in an ugly fashion
  • +
  • damaged_suffix(recipient_flesh!=Mechanoid)->with visible blood
  • +
  • damaged_suffix(recipient_flesh!=Mechanoid)->with the flesh visible
  • + +
  • to->to
  • +
  • to->into
  • + +
  • missed->missed
  • +
  • missed->narrowly missed
  • +
    +
    +
    + + + Combat_RangedDeflect + +
  • Combat_DeflectIncludes
  • +
    + + +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [damaged_past] [RECIPIENT_definite][damaged_target] [deflected_result].
  • +
  • r_logentry(p=2)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and [damaged_past] [RECIPIENT_definite][damaged_target_possessive_opt] [deflected_result].
  • +
  • r_logentry->[RECIPIENT_definite][damaged_target_possessive_opt] was [damaged_past] by [INITIATOR_definite]'s [WEAPON_projectile_label] [deflected_result].
  • + +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite][damaged_target_possessive_opt] with a shot [deflected_result].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite]'s projectile hit [RECIPIENT_definite][damaged_target_possessive_opt] [deflected_result].
  • +
  • r_logentry(p=0.4)->[INITIATOR_definite] [missed] [ORIGINALTARGET_definite] and hit [RECIPIENT_definite][damaged_target_possessive_opt] with a [WEAPON_projectile_label] [deflected_result].
  • +
  • r_logentry(p=0.4)->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed] [ORIGINALTARGET_definite] and hit [RECIPIENT_definite][damaged_target_possessive_opt] [deflected_result].
  • +
  • r_logentry(p=0.2)->[INITIATOR_definite] hit [RECIPIENT_definite][damaged_target_possessive_opt] with a [WEAPON_projectile_label] intended for [ORIGINALTARGET_definite] [deflected_result].
  • + + +
  • WEAPON_projectile_label(p=0.05)->shot
  • +
  • WEAPON_projectile_label(p=0.05)->projectile
  • +
  • WEAPON_projectile_label(p=0.05)->blast
  • +
  • ORIGINALTARGET_definite(p=0.5)->someone else
  • + +
  • damaged_target_possessive_opt->
  • +
  • damaged_target_possessive_opt(recipient_part_damaged0_outside==True)->'s [RECIPIENT_part_damaged0_label]
  • + +
  • deflected_result-> [adverb_deflected]
  • +
  • deflected_result->, [deflected_consequence]
  • + +
  • adverb_deflected_opt(p=4)->
  • +
  • adverb_deflected_opt->[adverb_deflected]
  • + +
  • adverb_deflected->harmlessly
  • +
  • adverb_deflected->uselessly
  • + +
  • deflected_consequence->but it [scraped_past] off [adverb_deflected_opt]
  • +
  • deflected_consequence->[scraped_present] off [RECIPIENT_possessive] armor [adverb_deflected_opt]
  • + +
  • scraped_past->ricocheted
  • + +
  • scraped_present->ricocheting
  • + +
  • missed->missed
  • +
  • missed->narrowly missed
  • +
    +
    +
    + + + + Combat_RangedMiss + + +
  • r_logentry->[INITIATOR_definite]'s [WEAPON_projectile_label] [missed].
  • + +
  • r_logentry->[INITIATOR_definite] missed [ORIGINALTARGET_definite].
  • +
  • r_logentry->[ORIGINALTARGET_definite] [avoidance], [INITIATOR_definite]'s [WEAPON_projectile_label] [missing].
  • + +
  • WEAPON_projectile_label(p=0.05)->shot
  • +
  • WEAPON_projectile_label(p=0.05)->projectile
  • +
  • WEAPON_projectile_label(p=0.05)->blast
  • +
  • missed(p=4)->missed
  • +
  • missed(p=2)->missed by a small margin
  • +
  • missed(p=2)->missed by a wide margin
  • +
  • missed->went wide
  • +
  • missed->flew into the air
  • +
  • missed->flew high into the air
  • +
  • missed->dug into the ground
  • +
  • missed->skipped off the ground and was lost
  • +
  • missed->dug a divot out of the ground
  • +
  • missed(p=0.2)->passed within millimeters of [ORIGINALTARGET_definite]
  • +
  • missed->passed within centimeters of [ORIGINALTARGET_definite]
  • +
  • missed->passed within a meter of [ORIGINALTARGET_definite]
  • +
  • missed->was blown offcourse
  • + +
  • missing->missing
  • +
  • missing->missing by a small margin
  • +
  • missing->missing by a wide margin
  • +
  • missing->going wide
  • +
  • missing->flying into the air
  • +
  • missing->flying high into the air
  • +
  • missing->digging into the ground
  • +
  • missing->skipping off the ground and becoming lost
  • +
  • missing->digging a divot out of the ground
  • +
  • missing(p=0.2)->passing within millimeters of [ORIGINALTARGET_definite]
  • +
  • missing->passing within centimeters of [ORIGINALTARGET_definite]
  • +
  • missing->passing within a meter of [ORIGINALTARGET_definite]
  • +
  • missing->blowing offcourse
  • + +
  • avoidance(ORIGINALTARGET_mobile==True)->jerked aside at the last second
  • +
  • avoidance(ORIGINALTARGET_mobile==True)->stumbled in an attempt to escape
  • +
  • avoidance(ORIGINALTARGET_mobile==True)->threw [ORIGINALTARGET_objective]self to the ground
  • +
  • avoidance(ORIGINALTARGET_mobile==True,p=0.3)->ducked behind [COVER_definite]
  • +
  • avoidance(ORIGINALTARGET_mobile==True,p=0.3)->leaped behind [COVER_definite]
  • +
    +
    +
    + + +
    diff --git a/1.3/Defs/RulePackDefs/JT_GrappleRules.xml b/1.3/Defs/RulePackDefs/JT_GrappleRules.xml new file mode 100644 index 00000000..f0f93fdf --- /dev/null +++ b/1.3/Defs/RulePackDefs/JT_GrappleRules.xml @@ -0,0 +1,55 @@ + + + + JT_GrappleSuccess + +
  • Transition_Include
  • +
    + + +
  • r_logentry->[INITIATOR_nameDef] [grappled] [SUBJECT_definite].
  • + +
  • grappled->grappled
  • +
  • grappled->seized
  • +
  • grappled->took hold of
  • +
    +
    +
    + + + JT_GrappleFailed + +
  • Transition_Include
  • +
    + + +
  • r_logentry->[INITIATOR_nameDef] [triedtograpple] [SUBJECT_definite], [but] [failedmeta].
  • + +
  • tried->tried
  • +
  • tried->attempted
  • +
  • grappleinf->to grapple
  • +
  • grappleinf->to seize
  • +
  • grappleinf->to hold onto
  • +
  • triedtograpple->[tried] [grappleinf]
  • + +
  • but->but
  • +
  • but->however
  • +
  • but->even so
  • +
  • but->yet
  • + +
  • failed->failed
  • +
  • failed->missed
  • +
  • dodged->dodged
  • +
  • dodged->slipped away
  • +
  • spectacularly->spectacularly
  • +
  • spectacularly->miserably
  • +
  • spectacularly->completely
  • +
  • spectacularly->utterly
  • +
  • failedmeta->[INITIATOR_pronoun] [failed]
  • +
  • failedmeta->[INITIATOR_pronoun] [failed] [spectacularly]
  • +
  • failedmeta->[SUBJECT_definite] [dodged]
  • +
    +
    +
    + +
    diff --git a/1.3/Defs/Stats/CompDeflection_StatWorkers.xml b/1.3/Defs/Stats/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..9bc7b3b3 --- /dev/null +++ b/1.3/Defs/Stats/CompDeflection_StatWorkers.xml @@ -0,0 +1,18 @@ + + + + + MeleeWeapon_DeflectionChance + CompDeflector.StatWorker_DeflectionChance + + Chance to deflect ranged projectiles with melee weapon. + PawnCombat + 0 + 0 + 1 + PercentZero + 10 + true + + + \ No newline at end of file diff --git a/1.3/Defs/Stats/CompSlotLoadable_Stats.xml b/1.3/Defs/Stats/CompSlotLoadable_Stats.xml new file mode 100644 index 00000000..be71f992 --- /dev/null +++ b/1.3/Defs/Stats/CompSlotLoadable_Stats.xml @@ -0,0 +1,8 @@ + + + + SlotLoadable + + 106 + + diff --git a/1.3/Defs/ThingDefs_Projectiles/JT_Projectiles.xml b/1.3/Defs/ThingDefs_Projectiles/JT_Projectiles.xml new file mode 100644 index 00000000..544ce068 --- /dev/null +++ b/1.3/Defs/ThingDefs_Projectiles/JT_Projectiles.xml @@ -0,0 +1,35 @@ + + + + + + Projectile + Normal + Projectile + Bullet + + False + True + + Transparent + + + + + + JT_FlyingObject + AbilityUser.FlyingObject + + + NullTex + Graphic_Single + + + true + Stun + 0 + 10 + + + + diff --git a/1.3/Defs/ThingDefs_Slots/CompSlotLoadable_Slots.xml b/1.3/Defs/ThingDefs_Slots/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..8f4c0ad0 --- /dev/null +++ b/1.3/Defs/ThingDefs_Slots/CompSlotLoadable_Slots.xml @@ -0,0 +1,15 @@ + + + + + SlotTest + CompSlotLoadable.SlotLoadable + + +
  • MeleeWeapon_Gladius
  • +
    + true + (255, 255, 255, 255) +
    + +
    diff --git a/1.3/Defs/ThingDefs_WeaponMelee/CompSlotLoadable_ThingDefExample b/1.3/Defs/ThingDefs_WeaponMelee/CompSlotLoadable_ThingDefExample new file mode 100644 index 00000000..08d6e4ed --- /dev/null +++ b/1.3/Defs/ThingDefs_WeaponMelee/CompSlotLoadable_ThingDefExample @@ -0,0 +1,138 @@ + + + + + + MeleeWeapon_TestKnife + + Never + 0 + 0 + One of humankind's oldest tools, the knife is both an everyday tool and a deadly weapon. + Normal + +
  • + +
  • SlotTest
  • + + +
    +
    + + + + Things/Item/Equipment/WeaponMelee/Knife + Graphic_Single + + InteractAutopistol + 40 + + 4000 + 0.5 + + -65 + +
  • Metallic
  • +
    + +
  • + + +
  • Blunt
  • + + 6 + 2.5 + +
  • + + +
  • Stab
  • + + 16 + 2.5 + +
  • + + +
  • Cut
  • + + 21 + 2.5 + +
    +
    + + + + + ThingWithComps + Item + true + Item + true + Never + Primary + true + 10 + true + Never + + 100 + 1.0 + 2 + 1 + -6 + 0.20 + + +
  • +
  • + CompEquippable +
  • +
    + + 35 + +
    + + + Industrial + true + +
  • Melee
  • +
    + +
  • WeaponsMelee
  • +
    + +
  • + CompQuality +
  • +
  • + ArtName_WeaponMelee + ArtDescription_WeaponMelee + Excellent +
  • +
    + +
  • ITab_Art
  • +
    +
    + + + + + +
  • Root
  • +
    + +
  • Silver
  • +
  • Gold
  • +
  • WoodLog
  • +
    +
    +
    +
    + + +
    diff --git a/1.3/Defs/ThinkTreeDefs/InsertHook_AbilityUserAI.xml b/1.3/Defs/ThinkTreeDefs/InsertHook_AbilityUserAI.xml new file mode 100644 index 00000000..dbea8898 --- /dev/null +++ b/1.3/Defs/ThinkTreeDefs/InsertHook_AbilityUserAI.xml @@ -0,0 +1,15 @@ + + + + + InsertHookTest + Humanlike_PostMentalState + 1000 + + true + +
  • + + + + \ No newline at end of file diff --git a/1.3/Defs/WorldObjectDefs/WorldObjects.xml b/1.3/Defs/WorldObjectDefs/WorldObjects.xml new file mode 100644 index 00000000..eaeee9ce --- /dev/null +++ b/1.3/Defs/WorldObjectDefs/WorldObjects.xml @@ -0,0 +1,19 @@ + + + + + WorldObject_ProgressBar + + true + This should not be visible to players. + JecsTools.WorldObject_ProgressBar + World/WorldObjects/TribalFactionBase + true + World/WorldObjects/Expanding/RoutePlannerWaypoint + 1 + true + false + false + + + diff --git a/1.3/Languages/ChineseSimplified/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.3/Languages/ChineseSimplified/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..ad77ae87 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,8 @@ + + + + 灼伤(光剑) + {0}被击毙了。 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.3/Languages/ChineseSimplified/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..8d26f05d --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,8 @@ + + + + 使用原力技 + 使用原力技 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompDeflector_Jobs.xml b/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompDeflector_Jobs.xml new file mode 100644 index 00000000..67ca2bd1 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompDeflector_Jobs.xml @@ -0,0 +1,7 @@ + + + + 偏转了 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompInstalledPart_Jobs.xml b/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..b704c3e8 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompInstalledPart_Jobs.xml @@ -0,0 +1,8 @@ + + + + 安装TargetA。 + 卸载TargetA。 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompSlotLoadable_Jobs.xml b/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..dafa94e2 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/JobDef/CompSlotLoadable_Jobs.xml @@ -0,0 +1,7 @@ + + + + 装备TargetA。 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/RecipeDef/Recipes_Add_Make.xml b/1.3/Languages/ChineseSimplified/DefInjected/RecipeDef/Recipes_Add_Make.xml new file mode 100644 index 00000000..30b216a8 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/RecipeDef/Recipes_Add_Make.xml @@ -0,0 +1,14 @@ + + + + + + + + + 打造[SW]开槽刀 + 打造一把开槽刀。 + 正在打造开槽刀中。 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/StatDef/CompDeflection_StatWorkers.xml b/1.3/Languages/ChineseSimplified/DefInjected/StatDef/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..f670f100 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/StatDef/CompDeflection_StatWorkers.xml @@ -0,0 +1,8 @@ + + + + 偏转几率 + 以近战武器偏转远程抛射物的几率。 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_Slots.xml b/1.3/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..bf4304e2 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_Slots.xml @@ -0,0 +1,7 @@ + + + + 测试 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml b/1.3/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml new file mode 100644 index 00000000..36d751d1 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml @@ -0,0 +1,8 @@ + + + + [SW]开槽刀 + 一件人类早期使用的原始工具,既可以当日常工具也可以当武器使用。 + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/DefInjected/WorldObjectDef/WorldObjects.xml b/1.3/Languages/ChineseSimplified/DefInjected/WorldObjectDef/WorldObjects.xml new file mode 100644 index 00000000..6943461d --- /dev/null +++ b/1.3/Languages/ChineseSimplified/DefInjected/WorldObjectDef/WorldObjects.xml @@ -0,0 +1,8 @@ + + + + progress bar + This should not be visible to players. + + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/Keyed/AbilityUser.xml b/1.3/Languages/ChineseSimplified/Keyed/AbilityUser.xml new file mode 100644 index 00000000..f344b80a --- /dev/null +++ b/1.3/Languages/ChineseSimplified/Keyed/AbilityUser.xml @@ -0,0 +1,25 @@ + + + + 禁用 + + 类型: + 有效范围 + 以自己为目标 + 以其他为目标 + 目标位置 + 冷却: + 附加 + 精神影响几率 + 影响几率 + {0}需要时间恢复能量 + + + 有效范围属性 + 目标: + 角色 + 误伤: + 最大目标数: + 从施法者开始: + + diff --git a/1.3/Languages/ChineseSimplified/Keyed/CompActivatableEffect.xml b/1.3/Languages/ChineseSimplified/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..20831c8f --- /dev/null +++ b/1.3/Languages/ChineseSimplified/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + 警告:{0}当前装备武器是无效的! + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/Keyed/CompDeflector.xml b/1.3/Languages/ChineseSimplified/Keyed/CompDeflector.xml new file mode 100644 index 00000000..a9cd358f --- /dev/null +++ b/1.3/Languages/ChineseSimplified/Keyed/CompDeflector.xml @@ -0,0 +1,19 @@ + + + + 没有配备导流板 + + 偏转几率 + 决定该武器反射袭击者的抛射物或子弹的偏转几率。 + + 最大偏转几率 + 每点{0}技能能提供角色{1}的反射目标抛射物的偏转几率。理论上最大的偏转几率为{2}。 + + 每点{0}技能增加的偏转百分比 + 每点{0}技能提供角的偏转抛射物的几率。 + + 偏转几率=(基础偏转几率+(原力等级*每级加成))×操作能力 + 基础偏转几率 + 每点技能增加的偏转百分比 + + \ No newline at end of file diff --git a/1.3/Languages/ChineseSimplified/Keyed/CompInstalledPart.xml b/1.3/Languages/ChineseSimplified/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..b3fa95f5 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + + 安装在{2}上 + 卸下{0} + {0}将{1}安装在{2}上 + {0}将{1}从{2}上卸下 + + diff --git a/1.3/Languages/ChineseSimplified/Keyed/Eng_WorldObjectMods.xml b/1.3/Languages/ChineseSimplified/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..e3666220 --- /dev/null +++ b/1.3/Languages/ChineseSimplified/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,8 @@ + + + + 该位置没有可交易的商队 + 资源:{0} + 失败。需要材料{0}:{1} 。 + + diff --git a/1.3/Languages/English/Keyed/AbilityUser.xml b/1.3/Languages/English/Keyed/AbilityUser.xml new file mode 100644 index 00000000..1e3b7cd6 --- /dev/null +++ b/1.3/Languages/English/Keyed/AbilityUser.xml @@ -0,0 +1,29 @@ + + + +No line of sight + +No targets available + +DISABLED + +Type: +Area of Effect +Targets Self +Targets Other +Targets Location +Cooldown: +Extra +Mental State Chance +Effect Chance +{0} needs time to recharge + + +Area of Effect Properties +Targets: +Characters +Friendly Fire: +Max Targets: +Starts from caster: + + diff --git a/1.3/Languages/English/Keyed/CompActivatableEffect.xml b/1.3/Languages/English/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..3142c3bf --- /dev/null +++ b/1.3/Languages/English/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + WARNING: {0}'s current weapon is deactivated! + + \ No newline at end of file diff --git a/1.3/Languages/English/Keyed/CompDeflector.xml b/1.3/Languages/English/Keyed/CompDeflector.xml new file mode 100644 index 00000000..2051f04d --- /dev/null +++ b/1.3/Languages/English/Keyed/CompDeflector.xml @@ -0,0 +1,20 @@ + + + + No deflector equipped + + Deflect chance + Determines how often this weapon returns projectiles back at the attacker. + + Max deflect chance + For each point in {0}, the user gains a {1} chance of deflecting the projectile back the target. {2} is the maximum possible deflection chance. + + + Deflect % per {0} skill + For each level in {0}, the user gains this much % chance to deflect a projectile. + + Deflection chance = (Base deflect chance + (Skill Level * % per Skill Level)) * Manipulation + Base deflect chance + Deflect % per skill level + + \ No newline at end of file diff --git a/1.3/Languages/English/Keyed/CompInstalledPart.xml b/1.3/Languages/English/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..fa0df1f3 --- /dev/null +++ b/1.3/Languages/English/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + +Install on something +Uninstall {0} +{0} installed the {1} onto {2} +{0} uninstalled the {1} from {2} + + diff --git a/1.3/Languages/English/Keyed/CompShield.xml b/1.3/Languages/English/Keyed/CompShield.xml new file mode 100644 index 00000000..ad7bf608 --- /dev/null +++ b/1.3/Languages/English/Keyed/CompShield.xml @@ -0,0 +1,18 @@ + + + + no shield equipped + + shield never blocks melee attacks + shield never blocks ranged attacks + shield never absorbs damage from a blocked attack + + Discard threshold + The hit points percentage threshold when the shield is automatically discarded by the wielder + shield is never automatically discarded by the wielder + + Damage to fatigue factor + How much percent of the damage is converted to fatigue damage on a blocked attack. + shield wielder never gets fatigued from a blocked attack + + \ No newline at end of file diff --git a/1.3/Languages/English/Keyed/Eng_WorldObjectMods.xml b/1.3/Languages/English/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..ff1c8a5f --- /dev/null +++ b/1.3/Languages/English/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,9 @@ + + + +because no caravan is available at this location +Resources: {0} +Missing Specific Items. Need {1}x {2}, have only {0} +Missing {2} Stuff. Need {1}x, have only {0} +Failed to build {0} due to lack of resources + diff --git a/1.3/Languages/English/Keyed/Grapple.xml b/1.3/Languages/English/Keyed/Grapple.xml new file mode 100644 index 00000000..7eb8aaae --- /dev/null +++ b/1.3/Languages/English/Keyed/Grapple.xml @@ -0,0 +1,12 @@ + + + +Grapple Success +Grapple Failed +Downed Attack: Grapple Success +Sneak Attack: Grapple Success +Restrained Victim: Grapple Success +Sleeping Victim: Grapple Success +Pet Victim: Grapple Success + + diff --git a/1.3/Languages/English/Keyed/Misc.xml b/1.3/Languages/English/Keyed/Misc.xml new file mode 100644 index 00000000..2a10068e --- /dev/null +++ b/1.3/Languages/English/Keyed/Misc.xml @@ -0,0 +1,10 @@ + + +Must be placed under a ceiling. +Must be placed on a wall. +{0} absorbed +Soak Amount: {0} +Knockback Chance: {0} +Extra Damages: +Explosive + diff --git a/1.3/Languages/French/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.3/Languages/French/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..ccff4a2d --- /dev/null +++ b/1.3/Languages/French/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,8 @@ + + + + brûlé + {0} a été abattu + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.3/Languages/French/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..96c0d2e5 --- /dev/null +++ b/1.3/Languages/French/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,8 @@ + + + + utiliser une capacité + utilise une capacité + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/JobDef/CompDeflector_Jobs.xml b/1.3/Languages/French/DefInjected/JobDef/CompDeflector_Jobs.xml new file mode 100644 index 00000000..33627009 --- /dev/null +++ b/1.3/Languages/French/DefInjected/JobDef/CompDeflector_Jobs.xml @@ -0,0 +1,7 @@ + + + + renvoit + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/JobDef/CompInstalledPart_Jobs.xml b/1.3/Languages/French/DefInjected/JobDef/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..543ab396 --- /dev/null +++ b/1.3/Languages/French/DefInjected/JobDef/CompInstalledPart_Jobs.xml @@ -0,0 +1,8 @@ + + + + installe TargetA. + désinstalle TargetA. + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/JobDef/CompSlotLoadable_Jobs.xml b/1.3/Languages/French/DefInjected/JobDef/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..e09b3bf3 --- /dev/null +++ b/1.3/Languages/French/DefInjected/JobDef/CompSlotLoadable_Jobs.xml @@ -0,0 +1,7 @@ + + + + équipe TargetA. + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/RecipeDef/Recipes_Add_Make.xml b/1.3/Languages/French/DefInjected/RecipeDef/Recipes_Add_Make.xml new file mode 100644 index 00000000..14bb1bd4 --- /dev/null +++ b/1.3/Languages/French/DefInjected/RecipeDef/Recipes_Add_Make.xml @@ -0,0 +1,14 @@ + + + + + + + + + faire un couteau d'entraînement + faire un couteau d'entraînement + fait un couteau d'entraînement + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/StatDef/CompDeflection_StatWorkers.xml b/1.3/Languages/French/DefInjected/StatDef/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..cc66a243 --- /dev/null +++ b/1.3/Languages/French/DefInjected/StatDef/CompDeflection_StatWorkers.xml @@ -0,0 +1,8 @@ + + + + chance de renvoi + Chance de dévier des projectiles à distance avec une arme de mêlée + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/ThingDef/CompSlotLoadable_Slots.xml b/1.3/Languages/French/DefInjected/ThingDef/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..73ce1273 --- /dev/null +++ b/1.3/Languages/French/DefInjected/ThingDef/CompSlotLoadable_Slots.xml @@ -0,0 +1,7 @@ + + + + test + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml b/1.3/Languages/French/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml new file mode 100644 index 00000000..027fc41f --- /dev/null +++ b/1.3/Languages/French/DefInjected/ThingDef/CompSlotLoadable_ThingDefExample.xml @@ -0,0 +1,8 @@ + + + + [SW]Couteau d'entraînement + Outil primitif utilisé par l'humanité à ses débuts, il peut être utilisé comme outil quotidien ou comme arme. + + + \ No newline at end of file diff --git a/1.3/Languages/French/DefInjected/WorldObjectDef/WorldObjects.xml b/1.3/Languages/French/DefInjected/WorldObjectDef/WorldObjects.xml new file mode 100644 index 00000000..ed041cfe --- /dev/null +++ b/1.3/Languages/French/DefInjected/WorldObjectDef/WorldObjects.xml @@ -0,0 +1,8 @@ + + + + barre de progression + Cela ne devrait pas être visible pour les joueurs. + + + \ No newline at end of file diff --git a/1.3/Languages/French/Keyed/AbilityUser.xml b/1.3/Languages/French/Keyed/AbilityUser.xml new file mode 100644 index 00000000..7da0f2ca --- /dev/null +++ b/1.3/Languages/French/Keyed/AbilityUser.xml @@ -0,0 +1,25 @@ + + + +DISABLED + +Type: +Zone d'effet +Cibler (moi) +Cibler (autres) +Emplacement de la cible +Recharge: +Extra +probabilit d'tat mental +probabilit d'effet +{0} a besoin de temps pour recharger + + +Proprits de la zone d'effet +Cibles: +Personnages +Tir amie: +Nombre de cibles maximal: +Se dclenche a partir du sorcier: + + diff --git a/1.3/Languages/French/Keyed/CompActivatableEffect.xml b/1.3/Languages/French/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..845d8675 --- /dev/null +++ b/1.3/Languages/French/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + Attention: L'arme de {0} est dsactive! + + \ No newline at end of file diff --git a/1.3/Languages/French/Keyed/CompDeflector.xml b/1.3/Languages/French/Keyed/CompDeflector.xml new file mode 100644 index 00000000..364534f5 --- /dev/null +++ b/1.3/Languages/French/Keyed/CompDeflector.xml @@ -0,0 +1,20 @@ + + + + Aucun déflecteur équipé + + probabilité de renvoyer + Détermine à quelle fréquence cette arme renvoie des projectiles à l'agresseur. + + Probabilité maximale de renvoi + Pour chaque point {0}, l'utilisateur a une probabilité de détourner le tir de {1}. La probabilité maximale de renvoi est de {2}. + + + Détournement % par {0} compétence + Pour chaque niveau en {0}, l'utilisateur gagne tel % de probabilité de renvoyer un projectile. + + Probabilité de détournement = (probabilité de détournement + (Niveau * % par Niveau)) * Manipulation + Probabilité de renvoi de base + Renvoit % par Niveau + + \ No newline at end of file diff --git a/1.3/Languages/French/Keyed/CompInstalledPart.xml b/1.3/Languages/French/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..3e9dabcd --- /dev/null +++ b/1.3/Languages/French/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + +Installer sur quelque chose +Retirer {0} +{0} a install {1} sur {2} +{0} a retir {1} de {2} + + diff --git a/1.3/Languages/French/Keyed/CompShield.xml b/1.3/Languages/French/Keyed/CompShield.xml new file mode 100644 index 00000000..7dcd3f87 --- /dev/null +++ b/1.3/Languages/French/Keyed/CompShield.xml @@ -0,0 +1,18 @@ + + + + pas de bouclier équipé + + le bouclier ne bloque jamais les attaques de mêlée + le bouclier ne bloque jamais les attaques à distance + le bouclier n'absorbe jamais les dégâts d'une attaque bloquée + + Seuil de défausse + Le seuil de pourcentage de points de vie nécessaire pour que le bouclier soit automatiquement défaussé par le porteur + Le bouclier n'est jamais automatiquement rejeté par le porteur + + Facteur de dommages de fatigue + Quel pourcentage des dégâts est converti en dégâts de fatigue lors d'une attaque bloquée. + Le porteur du bouclier ne se fatigue jamais d'une attaque bloquée + + \ No newline at end of file diff --git a/1.3/Languages/French/Keyed/Eng_WorldObjectMods.xml b/1.3/Languages/French/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..4c5b9b13 --- /dev/null +++ b/1.3/Languages/French/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,8 @@ + + + +car aucun convoi n'est prsent cet endroit +Ressources: {0} +chou construire {0} en raison d'un manque de ressources. + + diff --git a/1.3/Languages/French/Keyed/Grapple.xml b/1.3/Languages/French/Keyed/Grapple.xml new file mode 100644 index 00000000..bbad95c9 --- /dev/null +++ b/1.3/Languages/French/Keyed/Grapple.xml @@ -0,0 +1,12 @@ + + + +Succès du grappin +Echec du grappin +Attaque abattue: succès du grappin +Attaque furtive: succès du grappin +Victime retenue: succès du grappin +Victime endormie: succès du grappin +Victime animal de compagnie: succès du grappin + + diff --git a/1.3/Languages/French/Keyed/Misc.xml b/1.3/Languages/French/Keyed/Misc.xml new file mode 100644 index 00000000..30aba2a1 --- /dev/null +++ b/1.3/Languages/French/Keyed/Misc.xml @@ -0,0 +1,10 @@ + + +Doit être placé sous un plafond. +Doit être placé sur un mur. +{0} absorbé +Quantité de trempage: {0} +Chance de recul: {0} +Dégâts supplémentaires: +Explosif + diff --git a/1.3/Languages/Japanese/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.3/Languages/Japanese/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..2fb18e0d --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,7 @@ + + + + 火傷 + {0}はレーザーに焼かれて死んだ。 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/HediffDef/Shields.xml b/1.3/Languages/Japanese/DefInjected/HediffDef/Shields.xml new file mode 100644 index 00000000..3c37f56f --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/HediffDef/Shields.xml @@ -0,0 +1,12 @@ + + + + + + シールド損耗 + 少し + かなり + 厳しい + 枯渇 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.3/Languages/Japanese/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..4f4d3f89 --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,7 @@ + + + + 能力を使用中 + 能力を使用中 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/JobDef/CompDeflector_Jobs.xml b/1.3/Languages/Japanese/DefInjected/JobDef/CompDeflector_Jobs.xml new file mode 100644 index 00000000..07662d64 --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/JobDef/CompDeflector_Jobs.xml @@ -0,0 +1,6 @@ + + + + 逸らしている + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/JobDef/CompInstalledPart_Jobs.xml b/1.3/Languages/Japanese/DefInjected/JobDef/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..753833c7 --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/JobDef/CompInstalledPart_Jobs.xml @@ -0,0 +1,7 @@ + + + + TargetAを装着中 + TargetAを取り外し中 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/JobDef/CompSlotLoadable_Jobs.xml b/1.3/Languages/Japanese/DefInjected/JobDef/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..9534d0cd --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/JobDef/CompSlotLoadable_Jobs.xml @@ -0,0 +1,6 @@ + + + + TargetAをスロットに装着中 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/RulePackDef/JT_GrappleRules.xml b/1.3/Languages/Japanese/DefInjected/RulePackDef/JT_GrappleRules.xml new file mode 100644 index 00000000..0e83ea9d --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/RulePackDef/JT_GrappleRules.xml @@ -0,0 +1,32 @@ + + + + r_logentry->[INITIATOR_nameDef]は、[SUBJECT_definite][grappled]。 + grappled->と取っ組み合った + grappled->を抑えつけた + grappled->を手で掴みました + + r_logentry->[INITIATOR_nameDef]は、[SUBJECT_definite]を[triedtograpple]、[but][failedmeta]。 + tried->試みた + tried->attempted + grappleinf->捕まえようと + grappleinf->捕らえようと + grappleinf->抑えつけようと + triedtograpple->[grappleinf][tried]が + but->しかし + but->またしても + but->それでも + but->すでに + failed->失敗しました + failed->逃げられました + dodged->避けました + dodged->外しました + spectacularly->見事に + spectacularly->無様に + spectacularly->完全に + spectacularly->ことごとく + failedmeta->[INITIATOR_pronoun]は[failed] + failedmeta->[INITIATOR_pronoun]は[spectacularly][failed] + failedmeta->[SUBJECT_definite]は[dodged] + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/StatCategoryDef/Shields.xml b/1.3/Languages/Japanese/DefInjected/StatCategoryDef/Shields.xml new file mode 100644 index 00000000..099e37f5 --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/StatCategoryDef/Shields.xml @@ -0,0 +1,6 @@ + + + + シールド + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/StatDef/CompDeflection_StatWorkers.xml b/1.3/Languages/Japanese/DefInjected/StatDef/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..8def147d --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/StatDef/CompDeflection_StatWorkers.xml @@ -0,0 +1,7 @@ + + + + 逸らす確率 + 近距離武器で遠距離攻撃の発射物を逸らす確率 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/StatDef/Shields.xml b/1.3/Languages/Japanese/DefInjected/StatDef/Shields.xml new file mode 100644 index 00000000..595ebda9 --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/StatDef/Shields.xml @@ -0,0 +1,25 @@ + + + + 近接防御補正 + シールドを構えた者の近接攻撃を防ぐ確率はこの値で補正乗算されます。より高いほど防御率が高い。 + + 遠距離防御補正 + シールドを構えた者の遠距離攻撃を防ぐ確率はこの値で補正乗算されます。より高いほど防御率が高い。 + + ダメージ吸収 + 防御した攻撃からシールドがどれだけのダメージを吸収できるか。 + + + + + 近接防御率 + 近接攻撃を阻止する確立で、失敗すると攻撃が命中します。 + + + + + 遠距離防御率 + 遠距離攻撃を阻止する確立で、失敗すると攻撃が命中します。 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/ThingDef/CompSlotLoadable_Slots.xml b/1.3/Languages/Japanese/DefInjected/ThingDef/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..f0c19f89 --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/ThingDef/CompSlotLoadable_Slots.xml @@ -0,0 +1,6 @@ + + + + テスト + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/ThingDef/JT_Projectiles.xml b/1.3/Languages/Japanese/DefInjected/ThingDef/JT_Projectiles.xml new file mode 100644 index 00000000..ebe7213a --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/ThingDef/JT_Projectiles.xml @@ -0,0 +1,6 @@ + + + + 飛翔体 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/DefInjected/WorldObjectDef/WorldObjects.xml b/1.3/Languages/Japanese/DefInjected/WorldObjectDef/WorldObjects.xml new file mode 100644 index 00000000..f17fe8e5 --- /dev/null +++ b/1.3/Languages/Japanese/DefInjected/WorldObjectDef/WorldObjects.xml @@ -0,0 +1,7 @@ + + + + 進展度 + これはプレーヤーには見えないはずです。 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/Keyed/AbilityUser.xml b/1.3/Languages/Japanese/Keyed/AbilityUser.xml new file mode 100644 index 00000000..4713458f --- /dev/null +++ b/1.3/Languages/Japanese/Keyed/AbilityUser.xml @@ -0,0 +1,27 @@ + + + + 指定可能な目標がありません。 + + 機能停止 + + タイプ: + 目標(範囲) + 目標(自分) + 目標(他者) + 目標(場所) + クールダウン: + 特殊 + 精神状態変化率 + 影響確率 + {0}は回復する時間が必要 + + + 影響範囲の詳細 + 目標: + キャラクター + 味方への誤射: + 最大目標数: + 使用者から開始: + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/Keyed/CompActivatableEffect.xml b/1.3/Languages/Japanese/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..5bf0cc6d --- /dev/null +++ b/1.3/Languages/Japanese/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + 警告:{0}の現在所持している武器は不活性です! + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/Keyed/CompDeflector.xml b/1.3/Languages/Japanese/Keyed/CompDeflector.xml new file mode 100644 index 00000000..bf49557f --- /dev/null +++ b/1.3/Languages/Japanese/Keyed/CompDeflector.xml @@ -0,0 +1,19 @@ + + + + デフレクターなし + + 反射率 + この武器が発射体を攻撃者に跳ね返す頻度を決定します。 + + 最大反射率 + {0}ヵ所の各射撃地点に対して、使用者は攻撃してきた目標に対して発射された攻撃を反射する可能性が{1}回あります。反射可能な最大回数は{2}回です。 + + {0}スキルLv毎の反射率(%) + 使用者は{0}の各レベルごとに、この反射率(%)を加算して発射体を跳ね返すことができます。 + + 反射率=(基本反射率+(スキルレベル×スキルLvごとの反射率(%)))×指の機能 + 基本反射率 + スキルLvごとの反射率(%) + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/Keyed/CompInstalledPart.xml b/1.3/Languages/Japanese/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..f3783cb8 --- /dev/null +++ b/1.3/Languages/Japanese/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + + 何かを装着します + {0}を取り外す + {0}は{2}に{1}を装着しました + {0}は{2}から{1}を取り外しました + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/Keyed/Eng_WorldObjectMods.xml b/1.3/Languages/Japanese/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..57c5c404 --- /dev/null +++ b/1.3/Languages/Japanese/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,10 @@ + + + + この場所にキャラバン隊がありません + 必要な資源:{0} + 特定のアイテムが足りません。{2}が{1}が必要ですが、{0}しかありません + {2}が不足しています。{1}が{1}が必要ですが、{0}しかありません + 資源不足のために、{0}の建設に失敗しました + + diff --git a/1.3/Languages/Japanese/Keyed/Grapple.xml b/1.3/Languages/Japanese/Keyed/Grapple.xml new file mode 100644 index 00000000..986a776d --- /dev/null +++ b/1.3/Languages/Japanese/Keyed/Grapple.xml @@ -0,0 +1,11 @@ + + + + 捕縛に成功 + 捕縛に失敗 + 倒れている相手:捕縛に成功 + 奇襲攻撃の相手:捕縛に成功 + 拘束中の相手:捕縛に成功 + 睡眠中の相手:捕縛に成功 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/Keyed/Misc.xml b/1.3/Languages/Japanese/Keyed/Misc.xml new file mode 100644 index 00000000..012588fb --- /dev/null +++ b/1.3/Languages/Japanese/Keyed/Misc.xml @@ -0,0 +1,11 @@ + + + 天井の下に置く必要があります。 + 壁に置く必要があります。 + {0}ダメージ吸収した + 貫通量:{0} + ノックバック率:{0} + 追加ダメージ: + 炸裂 + + \ No newline at end of file diff --git a/1.3/Languages/Japanese/LanguageInfo.xml b/1.3/Languages/Japanese/LanguageInfo.xml new file mode 100644 index 00000000..d74dc636 --- /dev/null +++ b/1.3/Languages/Japanese/LanguageInfo.xml @@ -0,0 +1,13 @@ + + + 日本語 + Japanese + true + LanguageWorker_Japanese + +
  • + Translator + Proxyer +
  • + + diff --git a/1.3/Languages/Spanish/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.3/Languages/Spanish/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..57fca9f6 --- /dev/null +++ b/1.3/Languages/Spanish/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,8 @@ + + + + Quemadura + {0} Fue fusilado por armas laser. + + + \ No newline at end of file diff --git a/1.3/Languages/Spanish/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.3/Languages/Spanish/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..5ce0b377 --- /dev/null +++ b/1.3/Languages/Spanish/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,8 @@ + + + + Usando una abilidad + Usando una abilidad + + + \ No newline at end of file diff --git a/1.3/Languages/Spanish/Keyed/AbilityUser.xml b/1.3/Languages/Spanish/Keyed/AbilityUser.xml new file mode 100644 index 00000000..9085a1a7 --- /dev/null +++ b/1.3/Languages/Spanish/Keyed/AbilityUser.xml @@ -0,0 +1,25 @@ + + + +DISABLED + +Type: +Area de efecto +Concentar en ti mismo +Concentar en otro +Localizacion del objetivo +Cooldown: +Extra +Chance de Estado Mental +Chance de efecto +{0} Necesita tiempo para recargar + + +Propiedades del Area de Efecto +Objetivos: +Personajes +Fuego Amigo: +Max Targets: +Empieza desde el caster: + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/DamageDef/AbilityUser_Damages.xml b/1.3/Languages/SpanishLatin/DefInjected/DamageDef/AbilityUser_Damages.xml new file mode 100644 index 00000000..5a92f877 --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/DamageDef/AbilityUser_Damages.xml @@ -0,0 +1,8 @@ + + + + quemadura + {0} fue disparado hasta morir. + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/JobDef/AbilityUser_Jobs.xml b/1.3/Languages/SpanishLatin/DefInjected/JobDef/AbilityUser_Jobs.xml new file mode 100644 index 00000000..30592e33 --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/JobDef/AbilityUser_Jobs.xml @@ -0,0 +1,8 @@ + + + + Usando una habilidad + Usando una habilidad + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompDeflector_Jobs.xml b/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompDeflector_Jobs.xml new file mode 100644 index 00000000..daff1817 --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompDeflector_Jobs.xml @@ -0,0 +1,7 @@ + + + + Desviando + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompInstalledPart_Jobs.xml b/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompInstalledPart_Jobs.xml new file mode 100644 index 00000000..1aa92b6c --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompInstalledPart_Jobs.xml @@ -0,0 +1,8 @@ + + + + instalando TargetA. + desinstalando TargetA. + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompSlotLoadable_Jobs.xml b/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompSlotLoadable_Jobs.xml new file mode 100644 index 00000000..c43a6051 --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/JobDef/CompSlotLoadable_Jobs.xml @@ -0,0 +1,7 @@ + + + + equipando TargetA. + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/RulePackDef/JT_GrappleRules.xml b/1.3/Languages/SpanishLatin/DefInjected/RulePackDef/JT_GrappleRules.xml new file mode 100644 index 00000000..3512ff9d --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/RulePackDef/JT_GrappleRules.xml @@ -0,0 +1,33 @@ + + + + r_logentry->[INITIATOR_nameDef] [grappled] [SUBJECT_definite] with [SUBJECT_possessive] [culpritHediff_originaltarget_label]. + grappled->grappled + grappled->seized + grappled->took hold of + + r_logentry->[INITIATOR_nameDef] [triedtograpple] [SUBJECT_definite] with [SUBJECT_possessive] [culpritHediff_originaltarget_label], [but] [failedmeta]. + tried->tried + tried->attempted + grappleinf->to grapple + grappleinf->to seize + grappleinf->to hold onto + triedtograpple->[tried] [grappleinf] + but->but + but->however + but->even so + but->yet + failed->failed + failed->missed + dodged->dodged + dodged->slipped away + spectacularly->spectacularly + spectacularly->miserably + spectacularly->completely + spectacularly->utterly + failedmeta->[INITIATOR_pronoun] [failed] + failedmeta->[INITIATOR_pronoun] [failed] [spectacularly] + failedmeta->[SUBJECT_definite] [dodged] + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/StatDef/CompDeflection_StatWorkers.xml b/1.3/Languages/SpanishLatin/DefInjected/StatDef/CompDeflection_StatWorkers.xml new file mode 100644 index 00000000..637577a5 --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/StatDef/CompDeflection_StatWorkers.xml @@ -0,0 +1,8 @@ + + + + chance de desvío + Chance de desviar un proyectil de rango largo con una arma. + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/ThingDef/CompSlotLoadable_Slots.xml b/1.3/Languages/SpanishLatin/DefInjected/ThingDef/CompSlotLoadable_Slots.xml new file mode 100644 index 00000000..bdfa1aee --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/ThingDef/CompSlotLoadable_Slots.xml @@ -0,0 +1,7 @@ + + + + Test + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/ThingDef/JT_Projectiles.xml b/1.3/Languages/SpanishLatin/DefInjected/ThingDef/JT_Projectiles.xml new file mode 100644 index 00000000..3199d6c4 --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/ThingDef/JT_Projectiles.xml @@ -0,0 +1,7 @@ + + + + objeto volando + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/DefInjected/WorldObjectDef/WorldObjects.xml b/1.3/Languages/SpanishLatin/DefInjected/WorldObjectDef/WorldObjects.xml new file mode 100644 index 00000000..af48a3e2 --- /dev/null +++ b/1.3/Languages/SpanishLatin/DefInjected/WorldObjectDef/WorldObjects.xml @@ -0,0 +1,8 @@ + + + + barra de progreso + Esto no debe ser visible a los jugadores. + + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/Keyed/AbilityUser.xml b/1.3/Languages/SpanishLatin/Keyed/AbilityUser.xml new file mode 100644 index 00000000..6b73110d --- /dev/null +++ b/1.3/Languages/SpanishLatin/Keyed/AbilityUser.xml @@ -0,0 +1,25 @@ + + + + DESABILITADO + + Tipo: + Área de efecto + Dirige así mismo + Dirige a Otros + Locación a donde se dirige + Enfriamiento: + Extra + Chance del Estado Mental + Chance de efecto + {0} Necesita tiempo para recargar + + + Propiedades del Área de Efecto + Objetivo: + Personajes + Fuego Amigo: + Objetivos Máximos: + Comienza desde el emisor: + + diff --git a/1.3/Languages/SpanishLatin/Keyed/CompActivatableEffect.xml b/1.3/Languages/SpanishLatin/Keyed/CompActivatableEffect.xml new file mode 100644 index 00000000..011e0b58 --- /dev/null +++ b/1.3/Languages/SpanishLatin/Keyed/CompActivatableEffect.xml @@ -0,0 +1,6 @@ + + + + PELIGRO: el arma de {0} está desactivada! + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/Keyed/CompDeflector.xml b/1.3/Languages/SpanishLatin/Keyed/CompDeflector.xml new file mode 100644 index 00000000..5713efa7 --- /dev/null +++ b/1.3/Languages/SpanishLatin/Keyed/CompDeflector.xml @@ -0,0 +1,20 @@ + + + + Sin deflector equipado + + Chance de desvío + Determina que tan seguido esta arma devuelve los proyectiles a los atacantes. + + Chance de desvío máximo + Por cada punto en {0}, el usuario recibe un {1} de chance de desviar el proyectil devuelta al objetivo. {2} es la chance máxima posible de desviar. + + + Desvío en % por {0} de habilidad + Por cada nivel en {0}, el usuario recibe esta cantidad en % de chance para desviar un proyectil. + + Chance de Desvío = (Chance base para desviar + (Nivel de Habilidad * % por Nivel de Habilidad)) * Manipulación + Chance base para desviar + Desvío en % por nivel de habilidad + + \ No newline at end of file diff --git a/1.3/Languages/SpanishLatin/Keyed/CompInstalledPart.xml b/1.3/Languages/SpanishLatin/Keyed/CompInstalledPart.xml new file mode 100644 index 00000000..c8fb3c08 --- /dev/null +++ b/1.3/Languages/SpanishLatin/Keyed/CompInstalledPart.xml @@ -0,0 +1,9 @@ + + + + Instalar en algo + Desinstalar {0} + {0} Instalo el/la {1} en el/la {2} + {0} Desinstalo el/la {1} desde {2} + + diff --git a/1.3/Languages/SpanishLatin/Keyed/Eng_WorldObjectMods.xml b/1.3/Languages/SpanishLatin/Keyed/Eng_WorldObjectMods.xml new file mode 100644 index 00000000..f13cc1b4 --- /dev/null +++ b/1.3/Languages/SpanishLatin/Keyed/Eng_WorldObjectMods.xml @@ -0,0 +1,8 @@ + + + + porque no hay caravana disponible en esta locación + Recursos: {0} + Fallido. {1} de los {0} materiales es requirido. + + diff --git a/1.3/Languages/SpanishLatin/Keyed/Grapple.xml b/1.3/Languages/SpanishLatin/Keyed/Grapple.xml new file mode 100644 index 00000000..b0f508bb --- /dev/null +++ b/1.3/Languages/SpanishLatin/Keyed/Grapple.xml @@ -0,0 +1,11 @@ + + + + Se aferro exitosamente + Fallo en aferrarse + Ataque a un caído: Se aferro exitosamente + Ataque sigiloso: Se aferro exitosamente + Victima Contenida: Se aferro exitosamente + Victima Durmiendo: Se aferro exitosamente + + diff --git a/1.3/Languages/SpanishLatin/Keyed/Misc.xml b/1.3/Languages/SpanishLatin/Keyed/Misc.xml new file mode 100644 index 00000000..be63353a --- /dev/null +++ b/1.3/Languages/SpanishLatin/Keyed/Misc.xml @@ -0,0 +1,10 @@ + + + Debe ser colocado en la pared. + {0} absorbido + Monto absorbido: {0} + Chance de Retroceso: {0} + Daño extra: + Explosivo + + diff --git a/About/About.xml b/About/About.xml index 2959bd4f..0a85bfd5 100644 --- a/About/About.xml +++ b/About/About.xml @@ -1,24 +1,25 @@  - JecsTools - jecrell jecrell.jecstools + JecsTools + jecrell and contributors https://discord.gg/AaVFA7V
  • 1.0
  • 1.1
  • +
  • 1.2
  • +
  • 1.3
  • +
  • 1.4
  • - - -
  • - brrainz.harmony - Harmony - steam://url/CommunityFilePage/2009463077 - https://github.com/pardeike/HarmonyRimWorld/releases/latest -
  • -
    -
    - 1.1.1.2 (03-29-2020) + +
  • + brrainz.harmony + Harmony + steam://url/CommunityFilePage/2009463077 + https://github.com/pardeike/HarmonyRimWorld/releases/latest +
  • +
    + 1.3.0.5 (10-09-2022) Adds modding components to RimWorld: vehicles, spell casting, weapon slots, oversized weapons, and more! @@ -52,31 +53,128 @@ CompSlotLoadable CompToggleDef (by Roxxploxx) - Allows for something to despawn, change its def, and respawn. -CompVehicle (Experimental) +CompVehicle (experimental for 1.0, removed for 1.1+) - Allows for a pawn to be treated as a vehicle that can be loaded with pilots, gunners, crew, and passengers. CompInstalledPart (WIP) - Allows installation and uninstallation of things onto other things. This is particularly useful for weapons on vehicles. -JecsTools.PatchOperationModLoaded -- Allows modders to use xpath code to check if a mod is loaded before patching code. - Additions by ChJees Additions by roxxploxx Additions by Swenzi Additions and transpilers by Erdelf -Extensive hours of testing, debugging, and fixes by Xen. +Extensive hours of testing, debugging, and fixes by Xen +Improvements by lbmaian "Hey, should we make this into a public toolset for people to take advantage of all this cool stuff?" - Jecrell "Hell yes - this is awesome stuff - people will love it!" - Xen Thank you to my Patrons for supporting me in my efforts. Without you, none of this would be possible. These are the most excellent rim dwellers who support me: -Cade Perkinson, Jay Sacane, John Pahl, Tankok1998 also known as the Shermanlover, Vahl Kilmer, Zsolt Biró, Genaeve, JD2.0, Olteanu Laurentiu, Penelope Charli Whitman, Charlie Garnham, Steven Pretswell, Sultan Saltlick, RainerWingel, Daniel Paseka, Kyben, Charles Morris, Chris Seieroe, Robin Gleeson, Lea Stannard, Teres, David Silberstein, Kiya Nicoll, Matt Harris, Paul Fenwick, Michael Whitehead, Robert Alessi, Elodie, Gothi, Audrin Navarro, Михаил Юрченко, Calum, Tim Stillson, Populous25, Don Homer, Adam Bliss, Maaxar, Christopher, TinyFloatingTurtle, John Kanady, Midgeman, Nathan Getman, Sharp Spook, LionsFate, Cristina Shaver, Mark, George Chong Chuang Ming, Oliver White, roxxploxx, Emily Shaw, Justin Andres, Robin Hager, Kevin Reagan, Austin Harbert, Marcus Regan, E_T, Alex Mederer, Alexander, Toss Antilles +Michael Fisher, Storm D Bain, Luke Salinas, WonkyWoo WeebHoo, Daniel Schott, RainerWingel , Lea Stannard, David Silberstein, Matt Harris, Kiya Nicoll, Paul Fenwick, Elodie , Genaeve , David Turner, Populous25 , Matthew Isom, Charlie Garnham, TinyATuin, Michael Cailler, Jimes Tooper, Landon Cash, Sharp Spook, Don Homer, roxxploxx , Alex Mederer, Justin Andres, Dan Jones, Kaz, Michael Whitehead, iknowdude00, Alexander , Ken Birdwell, Michael Fisher, Storm D Bain, Luke Salinas, WonkyWoo WeebHoo, Daniel Schott, RainerWingel , Lea Stannard, David Silberstein, Matt Harris, Kiya Nicoll, Paul Fenwick, Elodie , Genaeve , David Turner, Populous25 , Matthew Isom, Charlie Garnham, TinyATuin, Michael Cailler, Jimes Tooper, Landon Cash, Sharp Spook, Don Homer, roxxploxx , Alex Mederer, Justin Andres, Dan Jones, Kaz, Michael Whitehead, iknowdude00, Alexander , Ken Birdwell ======================== Changelog ======================== +1.3.0.4 (08-08-2022) +======================== +damageTypesToExclude was not working correctly and has been fixed. Grappling a pet will always succeed which should prevent some fustration. Credit for this update goes to Gefallener from our RoM Discord. + +1.3.0.3 (07-30-2021) +======================== +Due to comptability issues, the patch for Enable Oversized Weapons will require additional work. Reverting back to the previous version. + +1.3.0.2 (07-29-2021) +======================== +Carny Senpai's Enable Oversized Weapons is now supported and JecsTools CompOversizedWeapon will yield for it. + +1.3.0.1 (07-24-2021) +======================== +Fix regression in RW 1.1 & 1.2 by using separate defs for 1.1+1.2 and 1.3 + +1.3.0.0 (07-24-2021) +======================== +lbmaian's 1.3 and 1.2 updates have been merged and are now available on the main JecsTools branch. Stay tuned for updates to out of date mods as we move into 1.3. + +1.2.0.0 (07-24-2021) +======================== +Note: Starting from this version, changes only apply to RimWorld 1.3+. +- source branch for assemblies supporting RimWorld 1.1 and 1.2: https://github.com/lbmaian/JecsTools/tree/rw1.2 +- source branch for assemblies supporting RimWorld 1.0: https://github.com/lbmaian/JecsTools/tree/rw1.0 +Preliminary update to support RimWorld 1.3 +Lots of performance improvements (too many to list - look at the individual commit descriptions since commit d0e37a8 for details) +New features and fixes: +- CompAbilityUser: + - revamped CombatPower-based pawn generation balancing to actually work + - PawnAbility.TryCastAbility now checks for matching verbProps again (regression since RW 1.1) + - fix AbilityDecisionNode subclasses ignoring the invert field in certain cases + - fix various assumptions that there's only a single CompAbilityUser when multiple CompAbilityUsers are common +- CompOversizedWeapon: improved thing-on-ground detection for graphics +- CompSlotLoadable: + - avoid showing unavailable slot options + - improve stats display + - fix doesChangeStats only affecting stats display (and not the actual stats value) + - updated to latest vanilla logic (exceptions noted in TODOs), centralize most stats logic + - avoid bloating save file if slottableThingDefs is same between SlotLoadable and SlotLoadableDef +- CompToggleDef: + - improved GUI to be more like vanilla + - add toggle GUI for colonists with toggleable weapons + - fix ranged weapon toggles not working properly + - changed thing is reselected and has graphics refreshed after toggle + - avoid toggling to the same def +- CompSlotLoadable: + - configurable per-body-part amountRange in SlotBonusProps_DefensiveHealChance and SlotBonusProps_VampiricEffect + - configurable damageDef and armorPenetration in SlotBonusProps_VampiricEffect + - update body part healing to be consistent between DefensiveHealChance and VampiricEffect (randomized, skip already healed body parts) +- CompAnimated: added layerOffset to CompProperties_AnimatedOver (thanks Aelanna!) +- BuildingExtension: wipeCategories should now consistently work +- HediffComp_ExtraMeleeDamages: updated to latest vanilla logic (damage now created just like those from Tool.extraMeleeDamages) +- HediffComp_DamageSoak: damage soak amount no longer rounded to integer +- HediffComp_Knockback: + - configurable knockbackSound (was broken), KnockImpactDamageType (instead of always Blunt), knockbackSpeed, and knockbackThought + - configurable explosiveProps (CompProperties_Explosive) + - knockDistance now accepts floating points + - add knockDistanceAbsorbedPercentCurve and knockDistanceMassCurve that controls how damage soak and mass affect knock distance + - improve push angle algorithm so that it's no longer always a diagonal + - prevent multiple knockbacks occurring due to multiple damage infos (e.g. extra damage) for same instigator+target + - FlyingObject: configurable props (ProjectileProperties) and accuracyRadius + - FlyingObject_Equipable allows equipping apparel along (not just weapons) +- PawnShields: support generating biocoded shields when generating pawns +- PlaceWorker_UnderCeiling: works again (regression since RW 1.1) +- PlaceWorker_OnTopOfWalls: also considers anything with BuildingProperties.isPlaceOverableWall as a wall +- CaravanJob: fix placedThings type (old regression since RW 1.0) +- other misc minor fixes, code cleanup, and code documentation +Deprecated: +- ApparelExtension: + - swapCondition: use vanilla apparel.gender instead + - coverage: use vanilla apparel.layers and custom ApparelLayerDef instead +- AbilityUser.GetCompAbilityUser/AbilityUtility.Abilities: use GetCompAbilityUsers (plural) +- HediffComp_Knockback explosiveKnockback/explosionDmg/explosionSize: use explosiveProps fields instead +- FlyingObject speed/impactDamage/explosion: use props.speed/extraDamages/explosionRadius +- ProjectileExtension: seems to have never worked properly due to incomplete implementation +- some fields have been deprecated in favor of properties +Removed: +- JecsTools' CompConsole and related Faction stuff (broken since RW B19) +- CompVehicles (broken and commented out since RW 1.1) +- CompProperties_OversizedWeapon.offset (mostly broken since version 1.0.9.3) +- some public classes and methods have been moved or removed + +1.1.2.3 (05-09-2021) +======================== +Update French translation (thanks qux!), rebuild to latest RW version + +1.1.2.2 (10-23-2020) +======================== +Fix CompAbilityUser subtype search to not cause errors (such as broken world gen) if another mod's assembly contains references to missing/wrong-version dependencies (even if they are optional dependencies). + +1.1.2.1 (08-13-2020) +======================== +Fix regressions in RW 1.1 version by compiling separate assemblies for RW 1.1 and RW 1.2 to account for different enum/constant values in RW assemblies + +1.1.2.0 (08-11-2020) +======================== +Performance improvements, various fixes, improved stats display for shields and deflectors, code cleanup (full changelog in https://github.com/jecrell/JecsTools/pull/15) + 1.1.1.2 (03-29-2020) ======================== Activatable weapons now activate in defense thanks to code from qadsad. diff --git a/About/Changelog.txt b/About/Changelog.txt index 27539d36..50a29654 100644 --- a/About/Changelog.txt +++ b/About/Changelog.txt @@ -1,3 +1,107 @@ +1.3.0.5 (10-09-2022) +======================== +Updated assemblies for RimWorld 1.4 unstable support. +- JecsTools BackstoryDef now inherits new RimWorld BackstoryDef setup. Once again based on erdelf's work. + +1.3.0.4 (08-08-2022) +======================== +damageTypesToExclude was not working correctly and has been fixed. Grappling a pet will always succeed which should prevent some fustration. Credit for this update goes to Gefallener from our RoM Discord. + +1.3.0.3 (07-30-2021) +======================== +Due to comptability issues, the patch for Enable Oversized Weapons will require additional work. Reverting back to the previous version. + +1.3.0.2 (07-29-2021) +======================== +Carny Senpai's Enable Oversized Weapons is now supported and JecsTools CompOversizedWeapon will yield for it. + +1.3.0.1 (07-24-2021) +======================== +Fix regression in RW 1.1 & 1.2 by using separate defs for 1.1+1.2 and 1.3 + +1.3.0.0 (07-24-2021) +======================== +lbmaian's 1.3 and 1.2 updates have been merged and are now available on the main JecsTools branch. Stay tuned for updates to out of date mods as we move into 1.3. + +1.2.0.0 (07-24-2021) +======================== +Note: Starting from this version, changes only apply to RimWorld 1.3+. +- source branch for assemblies supporting RimWorld 1.1 and 1.2: https://github.com/lbmaian/JecsTools/tree/rw1.2 +- source branch for assemblies supporting RimWorld 1.0: https://github.com/lbmaian/JecsTools/tree/rw1.0 +Preliminary update to support RimWorld 1.3 +Lots of performance improvements (too many to list - look at the individual commit descriptions since commit d0e37a8 for details) +New features and fixes: +- CompAbilityUser: + - revamped CombatPower-based pawn generation balancing to actually work + - PawnAbility.TryCastAbility now checks for matching verbProps again (regression since RW 1.1) + - fix AbilityDecisionNode subclasses ignoring the invert field in certain cases + - fix various assumptions that there's only a single CompAbilityUser when multiple CompAbilityUsers are common +- CompOversizedWeapon: improved thing-on-ground detection for graphics +- CompSlotLoadable: + - avoid showing unavailable slot options + - improve stats display + - fix doesChangeStats only affecting stats display (and not the actual stats value) + - updated to latest vanilla logic (exceptions noted in TODOs), centralize most stats logic + - avoid bloating save file if slottableThingDefs is same between SlotLoadable and SlotLoadableDef +- CompToggleDef: + - improved GUI to be more like vanilla + - add toggle GUI for colonists with toggleable weapons + - fix ranged weapon toggles not working properly + - changed thing is reselected and has graphics refreshed after toggle + - avoid toggling to the same def +- CompSlotLoadable: + - configurable per-body-part amountRange in SlotBonusProps_DefensiveHealChance and SlotBonusProps_VampiricEffect + - configurable damageDef and armorPenetration in SlotBonusProps_VampiricEffect + - update body part healing to be consistent between DefensiveHealChance and VampiricEffect (randomized, skip already healed body parts) +- CompAnimated: added layerOffset to CompProperties_AnimatedOver (thanks Aelanna!) +- BuildingExtension: wipeCategories should now consistently work +- HediffComp_ExtraMeleeDamages: updated to latest vanilla logic (damage now created just like those from Tool.extraMeleeDamages) +- HediffComp_DamageSoak: damage soak amount no longer rounded to integer +- HediffComp_Knockback: + - configurable knockbackSound (was broken), KnockImpactDamageType (instead of always Blunt), knockbackSpeed, and knockbackThought + - configurable explosiveProps (CompProperties_Explosive) + - knockDistance now accepts floating points + - add knockDistanceAbsorbedPercentCurve and knockDistanceMassCurve that controls how damage soak and mass affect knock distance + - improve push angle algorithm so that it's no longer always a diagonal + - prevent multiple knockbacks occurring due to multiple damage infos (e.g. extra damage) for same instigator+target + - FlyingObject: configurable props (ProjectileProperties) and accuracyRadius + - FlyingObject_Equipable allows equipping apparel along (not just weapons) +- PawnShields: support generating biocoded shields when generating pawns +- PlaceWorker_UnderCeiling: works again (regression since RW 1.1) +- PlaceWorker_OnTopOfWalls: also considers anything with BuildingProperties.isPlaceOverableWall as a wall +- CaravanJob: fix placedThings type (old regression since RW 1.0) +- other misc minor fixes, code cleanup, and code documentation +Deprecated: +- ApparelExtension: + - swapCondition: use vanilla apparel.gender instead + - coverage: use vanilla apparel.layers and custom ApparelLayerDef instead +- AbilityUser.GetCompAbilityUser/AbilityUtility.Abilities: use GetCompAbilityUsers (plural) +- HediffComp_Knockback explosiveKnockback/explosionDmg/explosionSize: use explosiveProps fields instead +- FlyingObject speed/impactDamage/explosion: use props.speed/extraDamages/explosionRadius +- ProjectileExtension: seems to have never worked properly due to incomplete implementation +- some fields have been deprecated in favor of properties +Removed: +- JecsTools' CompConsole and related Faction stuff (broken since RW B19) +- CompVehicles (broken and commented out since RW 1.1) +- CompProperties_OversizedWeapon.offset (mostly broken since version 1.0.9.3) +- some public classes and methods have been moved or removed + +1.1.2.3 (05-09-2021) +======================== +Update French translation (thanks qux!), rebuild to latest RW version + +1.1.2.2 (10-23-2020) +======================== +Fix CompAbilityUser subtype search to not cause errors (such as broken world gen) if another mod's assembly contains references to missing/wrong-version dependencies (even if they are optional dependencies). + +1.1.2.1 (08-13-2020) +======================== +Fix regressions in RW 1.1 version by compiling separate assemblies for RW 1.1 and RW 1.2 to account for different enum/constant values in RW assemblies + +1.1.2.0 (08-11-2020) +======================== +Performance improvements, various fixes, improved stats display for shields and deflectors, code cleanup (full changelog in https://github.com/jecrell/JecsTools/pull/15) + 1.1.1.2 (03-29-2020) ======================== Activatable weapons now activate in defense thanks to code from qadsad. diff --git a/About/Description.txt b/About/Description.txt index 834247af..e04df0e6 100644 --- a/About/Description.txt +++ b/About/Description.txt @@ -30,19 +30,17 @@ CompSlotLoadable CompToggleDef (by Roxxploxx) - Allows for something to despawn, change its def, and respawn. -CompVehicle (Experimental) +CompVehicle (experimental for 1.0, removed for 1.1+) - Allows for a pawn to be treated as a vehicle that can be loaded with pilots, gunners, crew, and passengers. CompInstalledPart (WIP) - Allows installation and uninstallation of things onto other things. This is particularly useful for weapons on vehicles. -JecsTools.PatchOperationModLoaded -- Allows modders to use xpath code to check if a mod is loaded before patching code. - Additions by ChJees Additions by roxxploxx Additions by Swenzi Additions and transpilers by Erdelf -Extensive hours of testing, debugging, and fixes by Xen. +Extensive hours of testing, debugging, and fixes by Xen +Improvements by lbmaian "Hey, should we make this into a public toolset for people to take advantage of all this cool stuff?" - Jecrell "Hell yes - this is awesome stuff - people will love it!" - Xen \ No newline at end of file diff --git a/About/Manifest.xml b/About/Manifest.xml index acf1bacc..61d04602 100644 --- a/About/Manifest.xml +++ b/About/Manifest.xml @@ -1,35 +1,9 @@  JecsTools - 1.1.1.2 + 1.3.0.5 - -
  • DoorsExpanded
  • -
  • CoC-Factions
  • -
  • CoC-Cults
  • -
  • CoC-ElderThings
  • -
  • HPLovecraftStoryteller
  • -
  • IA-ObjectsAndFurniture
  • -
  • IA-SteamCorp
  • -
  • LotR-Dwarves
  • -
  • LotR-Elves
  • -
  • LotR-Hobbits
  • -
  • LotR-MenAndBeasts
  • -
  • LotR-OrcsAndGoblins
  • -
  • LotR-TheThirdAge
  • -
  • RoM-Arachnophobia
  • -
  • RoM-Vampires
  • -
  • RoM-Werewolves
  • -
  • RimQuest
  • -
  • RimWriter
  • -
  • SW-Factions
  • -
  • SW-Lightsabers
  • -
  • SW-TheForce
  • -
    - -
  • HugsLib
  • -
    https://raw.githubusercontent.com/jecrell/JecsTools/master/About/Manifest.xml https://github.com/jecrell/JecsTools/releases
    \ No newline at end of file diff --git a/About/PatreonURL.txt b/About/PatreonURL.txt index 2d44cd2a..dd02ada6 100644 --- a/About/PatreonURL.txt +++ b/About/PatreonURL.txt @@ -1 +1 @@ -https://www.patreon.com/posts/34452021 +https://www.patreon.com/posts/54071148 \ No newline at end of file diff --git a/About/Version.txt b/About/Version.txt index b0fff185..e474c207 100644 --- a/About/Version.txt +++ b/About/Version.txt @@ -1 +1 @@ -1.1.1.2 +1.3.0.5 diff --git a/Languages/!NOTE - this folder is for 1.0 only and cannot be put in 1.0 folder due to 1.0 limitations b/Languages/!NOTE - this folder is for 1.0 only and cannot be put in 1.0 folder due to 1.0 limitations new file mode 100644 index 00000000..e69de29b diff --git a/Languages/English/Keyed/AbilityUser.xml b/Languages/English/Keyed/AbilityUser.xml index 1e3b7cd6..cd19821b 100755 --- a/Languages/English/Keyed/AbilityUser.xml +++ b/Languages/English/Keyed/AbilityUser.xml @@ -1,9 +1,7 @@ -No line of sight - -No targets available +No targets available. DISABLED diff --git a/LoadFolders.xml b/LoadFolders.xml index 442918ae..d5543cf7 100644 --- a/LoadFolders.xml +++ b/LoadFolders.xml @@ -1,15 +1,16 @@ - + - +
  • /
  • -
    -
  • 1.0
  • -
  • /
  • -<<<<<<< Updated upstream
    -
    -======= + +
  • /
  • +
  • 1.1+1.2
  • +
  • 1.1
  • +
    + +
  • /
  • 1.1+1.2
  • 1.2
  • @@ -22,4 +23,3 @@
  • 1.4
  • ->>>>>>> Stashed changes diff --git a/README.md b/README.md index 45a7b8b5..244974ea 100755 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@

    - JecsTools + JecsTools

    - Adds modding components to RimWorld: vehicles, spell casting, weapon slots, oversized weapons, and more! + Adds modding components to RimWorld: spell casting, weapon slots, oversized weapons, and more!


    **Note to players:** This mod will not change your game, but rather it lets modders do more, so you can have an even more amazing RimWorld experience. - + **Note to modders:** This mod contains components that allow you to do many new and different things in RimWorld. Check out RoxxPloxx's guide for more info here: https://github.com/roxxploxx/RimWorldModGuide/wiki - + Total list of components: *CompAbilityUser* - Adds spell/ability casting to humanlikes. - + *CompActivatableEffect* - - Adds an activation graphic for weapons (e.g. lightsaber beam). - + - Adds an activation graphic for weapons (e.g. lightsaber beam). + *CompDeflector* - Allows the ability to knock projectiles away with melee weapons. - + *CompExtraSounds* - Adds extra melee sounds to weapons. - + *CompLumbering* - Gives pawns a staggered walking animation that cycles between two images. (e.g. ATST walking effect) - + *CompOversizedWeapon* - Allows weapons to have graphic sizes that can be bigger than RimWorld's vanilla limits. - + *CompSlotLoadable* - Adds slots to objects, weapons, apparel, etc that can be filled to have effects. (e.g. an ammo slot for guns with different kinds of ammunition, crystal slots for lightsabers, etc) - -*CompVehicle (Experimental, Additions by Swenzi)* - - Allows for a pawn to be treated as a vehicle that can be loaded with pilots, gunners, crew, and passengers. + +~~*CompVehicle (Experimental, Additions by Swenzi)*~~ + - ~~Allows for a pawn to be treated as a vehicle that can be loaded with pilots, gunners, crew, and passengers.~~ *CompInstalledPart* - - Allows for a part to be installable and uninstallable onto another thing. This is particularly useful for vehicle weapons. + - Allows for a part to be installable and uninstallable onto another thing. ~~This is particularly useful for vehicle weapons.~~ *CompToggleDef (by Roxxploxx)* - A situational Component that allows you to toggle the ThingDef of a selected Thing via a radio button menu. ex. Change a ring to be for a pinky finger versus a ring or index finger. -*CompDelayedSpawner* +*CompDelayedSpawner* - Allows us to create things or pawns after a set amount of time. For instance, I created an invisible spawner for the Star Vampire (as of this update) that uses this CompDelayedSpawner. This lets me trigger the Star Vampire incident, drop down some delayed spawners, and enjoy results after a short period of time. The CompDelayedSpawner is highly customizable for things, pawns, and even allows for setting mental states and hediffs. Total List of Classes @@ -67,14 +67,14 @@ Total List of Classes *JecsTools.JobGiver_AIFirelessTrashColonyClose* *JecsTools.JobGiver_AIFirelessTrashColonyDistant* - These classes lets us call a special jobgiver for raiders that does not include setting fire to objects. This is good for monstrous creatures that do not have the ability to start fires but still want to break things. - + Additions by roxxploxx. Additions by Swenzi. Transpilers by Erdelf. Extensive hours of testing, debugging, and fixes by Xen. "Hey, should we make this into a public toolset for people to take advantage of all this cool stuff?" - Jecrell "Hell yes - this is awesome stuff - people will love it!" - Xen - + Special thanks to Pardeike's amazing non-destructive patching library, Harmony. Without his work, none of this would be possible.

    @@ -92,4 +92,4 @@ Special thanks to Pardeike's amazing non-destructive patching library, Harmony. MIT License -

    +

    diff --git a/Source/.editorconfig b/Source/.editorconfig new file mode 100644 index 00000000..a111c916 --- /dev/null +++ b/Source/.editorconfig @@ -0,0 +1,171 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +[*.xml] +indent_style = space +indent_size = 2 + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_style = space +indent_size = 4 +tab_width = 4 + +# New line preferences +end_of_line = lf +insert_final_newline = true + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:suggestion +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_property = false:suggestion + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = false:silent +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + +# Field preferences +dotnet_style_readonly_field = true:suggestion + +# Parameter preferences +dotnet_code_quality_unused_parameters = non_public:suggestion + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = true:silent +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_local_function = true:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent + +# Code-block preferences +csharp_prefer_braces = when_multiline:silent +csharp_prefer_simple_using_statement = true:suggestion + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_throw_expression = true:silent +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:suggestion + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = false +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = false + +#### Custom Dotnet Diagnostic Severity #### + +# IDE0001: Simplify Names +dotnet_diagnostic.IDE0001.severity = suggestion + +# IDE0002: Simplify Member Access +dotnet_diagnostic.IDE0002.severity = suggestion diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_CasterHealth.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_CasterHealth.cs index afaf8b23..7012356e 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_CasterHealth.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_CasterHealth.cs @@ -1,6 +1,6 @@ using Verse; -/* +/* * Author: ChJees * Created: 2017-09-24 */ @@ -17,13 +17,7 @@ public class AbilityDecisionConditionalNode_CasterHealth : AbilityDecisionNode public override bool CanContinueTraversing(Pawn caster) { - var result = caster.HealthScale >= minHealth && - caster.health.summaryHealth.SummaryHealthPercent <= maxHealth; - - if (invert) - return !result; - - return result; + return (caster.HealthScale >= minHealth && caster.health.summaryHealth.SummaryHealthPercent <= maxHealth) ^ invert; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetCover.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetCover.cs index e174a7b0..db7521ab 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetCover.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetCover.cs @@ -1,6 +1,6 @@ using Verse; -/* +/* * Author: ChJees * Created: 2017-09-24 */ @@ -24,18 +24,12 @@ public class AbilityDecisionConditionalNode_EnemyTargetCover : AbilityDecisionNo public override bool CanContinueTraversing(Pawn caster) { - if (caster.mindState.enemyTarget == null) - return false; + var enemyTarget = caster.mindState.enemyTarget; + if (enemyTarget == null) + return invert; - var cover = CoverUtility.CalculateOverallBlockChance(caster.mindState.enemyTarget.Position, caster.Position, - caster.Map); - - var result = cover >= minCover && cover < maxCover; - - if (invert) - return !result; - - return result; + var cover = CoverUtility.CalculateOverallBlockChance(enemyTarget.Position, caster.Position, caster.Map); + return (cover >= minCover && cover < maxCover) ^ invert; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetDistance.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetDistance.cs index 48d2984c..121d0b93 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetDistance.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetDistance.cs @@ -1,7 +1,7 @@ using System; using Verse; -/* +/* * Author: ChJees * Created: 2017-09-23 */ @@ -25,17 +25,12 @@ public class AbilityDecisionConditionalNode_EnemyTargetDistance : AbilityDecisio public override bool CanContinueTraversing(Pawn caster) { - if (caster.mindState.enemyTarget == null) - return false; + var enemyTarget = caster.mindState.enemyTarget; + if (enemyTarget == null) + return invert; - var distance = Math.Abs(caster.Position.DistanceTo(caster.mindState.enemyTarget.Position)); - - var result = distance >= minDistance && distance < maxDistance; - - if (invert) - return !result; - - return result; + var distance = Math.Abs(caster.Position.DistanceTo(enemyTarget.Position)); + return (distance >= minDistance && distance < maxDistance) ^ invert; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetIsArmed.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetIsArmed.cs index fc1164bf..ccf1ea78 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetIsArmed.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_EnemyTargetIsArmed.cs @@ -1,6 +1,6 @@ using Verse; -/* +/* * Author: ChJees * Created: 2017-11-05 */ @@ -14,24 +14,13 @@ public class AbilityDecisionConditionalNode_EnemyTargetIsArmed : AbilityDecision { public override bool CanContinueTraversing(Pawn caster) { - if (caster.mindState.enemyTarget == null) - return false; + if (!(caster.mindState.enemyTarget is Pawn enemyPawn)) + return invert; - var enemyPawn = caster.mindState.enemyTarget as Pawn; - - if (enemyPawn == null) - return false; - - var result = false; if (enemyPawn.AnimalOrWildMan()) - result = false; - else - result = enemyPawn?.equipment.Primary != null; - - if (invert) - return !result; + return invert; - return result; + return (enemyPawn.equipment.Primary != null) ^ invert; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_HasEnemyTarget.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_HasEnemyTarget.cs index 439e43e3..a2367e20 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_HasEnemyTarget.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_HasEnemyTarget.cs @@ -1,6 +1,6 @@ using Verse; -/* +/* * Author: ChJees * Created: 2017-09-23 */ @@ -14,12 +14,7 @@ public class AbilityDecisionConditionalNode_HasEnemyTarget : AbilityDecisionNode { public override bool CanContinueTraversing(Pawn caster) { - var result = caster.mindState.enemyTarget != null; - - if (invert) - return !result; - - return result; + return (caster.mindState.enemyTarget != null) ^ invert; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_InCombat.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_InCombat.cs index 21c440bb..43552f9b 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_InCombat.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_InCombat.cs @@ -1,6 +1,6 @@ using Verse; -/* +/* * Author: ChJees * Created: 2017-09-23 */ @@ -14,12 +14,7 @@ public class AbilityDecisionConditionalNode_InCombat : AbilityDecisionNode { public override bool CanContinueTraversing(Pawn caster) { - var result = caster.mindState.anyCloseHostilesRecently; - - if (invert) - return !result; - - return result; + return caster.mindState.anyCloseHostilesRecently ^ invert; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_UsingMeleeWeapon.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_UsingMeleeWeapon.cs index e730e352..a2a5a844 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_UsingMeleeWeapon.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_UsingMeleeWeapon.cs @@ -1,6 +1,6 @@ using Verse; -/* +/* * Author: ChJees * Created: 2017-09-25 */ @@ -16,18 +16,7 @@ public class AbilityDecisionConditionalNode_UsingMeleeWeapon : AbilityDecisionNo public override bool CanContinueTraversing(Pawn caster) { - var result = false; - - if (countUnarmed) - result = caster?.equipment.Primary == null || - caster?.equipment.Primary != null && !caster.equipment.Primary.def.IsRangedWeapon; - else - result = caster?.equipment.Primary != null && !caster.equipment.Primary.def.IsRangedWeapon; - - if (invert) - return !result; - - return result; + return (!caster?.equipment.Primary?.def.IsRangedWeapon ?? countUnarmed) ^ invert; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_UsingRangedWeapon.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_UsingRangedWeapon.cs index d64645bb..7ced96cf 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_UsingRangedWeapon.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionConditionalNode_UsingRangedWeapon.cs @@ -1,6 +1,6 @@ using Verse; -/* +/* * Author: ChJees * Created: 2017-09-24 */ @@ -14,12 +14,7 @@ public class AbilityDecisionConditionalNode_UsingRangedWeapon : AbilityDecisionN { public override bool CanContinueTraversing(Pawn caster) { - var result = caster?.equipment.Primary != null && caster.equipment.Primary.def.IsRangedWeapon; - - if (invert) - return !result; - - return result; + return (caster?.equipment.Primary?.def.IsRangedWeapon ?? false) ^ invert; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionNode.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionNode.cs index fdb20be4..bda7b254 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionNode.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionNode.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Verse; -/* +/* * Author: ChJees * Created: 2017-09-23 */ @@ -38,7 +38,7 @@ public class AbilityDecisionNode /// giant anyway.) /// /// Def to set. - public void Resolve(AbilityUserAIProfileDef def) + public virtual void Resolve(AbilityUserAIProfileDef def) { profileDef = def; @@ -98,5 +98,10 @@ public virtual AbilityAIDef RecursivelyGetAbility(Pawn caster) return null; } + + public override string ToString() + { + return base.ToString() + "(" + profileDef + ")"; + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionNode_PickAbilityWithMatchingTags.cs b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionNode_PickAbilityWithMatchingTags.cs index dc908269..1b3261cb 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionNode_PickAbilityWithMatchingTags.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/AbilityDecision/AbilityDecisionNode_PickAbilityWithMatchingTags.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; -using System.Linq; using AbilityUser; using Verse; -/* +/* * Author: ChJees * Created: 2017-09-23 */ @@ -25,82 +24,79 @@ public class AbilityDecisionNode_PickAbilityWithMatchingTags : AbilityDecisionNo /// public List tags = new List(); - public override AbilityAIDef TryPickAbility(Pawn caster) - { - //Get all eligible abilities. - var abilities = - from validAbilityDef in - //Initial filtering. - (from abilityAIDef in profileDef.abilities - //where tags.FindAll(tag => tags.Contains(tag))?.Count() >= tags.Count - where tags.FindAll(tag => abilityAIDef.tags.Contains(tag))?.Count() >= tags.Count - select abilityAIDef) - //Blacklist filtering. - where !validAbilityDef.tags.Any(tag => blacklistedTags.Contains(tag)) - select validAbilityDef; + [Unsaved] + private HashSet blacklistedTagSet; + private HashSet tagSet; - //Debug - //Log.Message("-=abilities list=-"); - //GenDebug.LogList(abilities); + private List eligibleAbilities; - if (abilities != null) + public override void Resolve(AbilityUserAIProfileDef def) + { + //Cache all eligible abilities for given def. + blacklistedTagSet ??= new HashSet(blacklistedTags); + tagSet ??= new HashSet(tags); + eligibleAbilities = new List(); + foreach (var validAbility in def.abilities) { - //Filter out abilities we do not have. - var thingComp = caster.AllComps.First(comp => comp.GetType() == profileDef.compAbilityUserClass); - var compAbilityUser = thingComp as CompAbilityUser; - - var knownAbilities = - from abilityAIDef in abilities - from abilityUserAbility in compAbilityUser.AbilityData.AllPowers - where abilityAIDef.ability == abilityUserAbility.Def && - profileDef.Worker.CanUseAbility(profileDef, caster, abilityAIDef) - orderby abilityAIDef.Worker.PowerScoreFor(abilityAIDef, caster) descending - select abilityAIDef; - - //Debug - //Log.Message("-=knownAbilities list=-"); - //GenDebug.LogList(knownAbilities); + if (tagSet.IsSubsetOf(validAbility.tags) && + !blacklistedTagSet.Overlaps(validAbility.tags)) + eligibleAbilities.Add(validAbility); + } + //Log.Message(this + " eligibleAbilities: " + eligibleAbilities.ToStringSafeEnumerable()); + base.Resolve(def); + } + public override AbilityAIDef TryPickAbility(Pawn caster) + { + if (eligibleAbilities.Count > 0) + { + //Filter for abilities the caster has. + var compAbilityUser = caster.GetExactCompAbilityUser(profileDef.compAbilityUserClass); if (compAbilityUser != null) - if (knownAbilities != null && knownAbilities.Count() > 0) - foreach (var ability in knownAbilities) + { + var powers = compAbilityUser.AbilityData.AllPowers; + var knownAbilities = new List(); + foreach (var ability in eligibleAbilities) + { + // Can we cast the ability in the implementation of it? + if (profileDef.Worker.CanUseAbility(profileDef, caster, ability)) { - var reason = ""; - - //Log.Message("-=AbilityVerbs list=-"); - //GenDebug.LogList(compAbilityUser.AbilityVerbs); - - //Can we cast the ability in the implementation of it? - var pawnAbility = compAbilityUser.AbilityData.AllPowers.First(pawnAbilityInt => - pawnAbilityInt.Def == ability.ability); - var abilityVerb = - pawnAbility - .Verb; //.First(abilityIntVerb => abilityIntVerb.Ability.Def == ability.ability); + var pawnAbility = powers.Find(power => power.Def == ability.ability); + if (pawnAbility != null) + { + // TODO: Put back check after Ability Framework redesign. + if (compAbilityUser.CanCastPowerCheck(pawnAbility.Verb, out var _)) //&& !pawnAbility.NeedsCooldown + knownAbilities.Add(ability); + } + } + } + // orderby ability.Worker.PowerScoreFor(ability, caster) descending + knownAbilities.Sort((x, y) => y.Worker.PowerScoreFor(y, caster).CompareTo(x.Worker.PowerScoreFor(x, caster))); + //Log.Message($"{this} for pawn {caster} knownAbilities: " + knownAbilities.ToStringSafeEnumerable()); - //Log.Message("abilityVerb=" + abilityVerb.ability.powerdef.defName); - if (compAbilityUser.CanCastPowerCheck(abilityVerb, - out reason) /*&& !pawnAbility.NeedsCooldown*/ - ) //To-Do: Put back check after Ability Framework redesign. - if (ability.usedOnCaster) - { - //Target self. - if (ability.CanPawnUseThisAbility(caster, caster)) - return ability; - } - else if (ability.needEnemyTarget) - { - //Enemy target specific. - if (caster.mindState.enemyTarget != null && - ability.CanPawnUseThisAbility(caster, caster.mindState.enemyTarget)) - return ability; - } - else - { - //Need no target. - if (ability.CanPawnUseThisAbility(caster, LocalTargetInfo.Invalid)) - return ability; - } + foreach (var ability in knownAbilities) + { + if (ability.usedOnCaster) + { + //Target self. + if (ability.CanPawnUseThisAbility(caster, caster)) + return ability; + } + else if (ability.needEnemyTarget) + { + //Enemy target specific. + var enemyTarget = caster.mindState.enemyTarget; + if (enemyTarget != null && ability.CanPawnUseThisAbility(caster, enemyTarget)) + return ability; + } + else + { + //Need no target. + if (ability.CanPawnUseThisAbility(caster, LocalTargetInfo.Invalid)) + return ability; } + } + } } return null; @@ -111,4 +107,4 @@ public override bool CanContinueTraversing(Pawn caster) return false; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/JobGiver_AIAbilityUser.cs b/Source/AllModdingComponents/AbilityUserAI/AI/JobGiver_AIAbilityUser.cs index b699f220..4152bbdb 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/JobGiver_AIAbilityUser.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/JobGiver_AIAbilityUser.cs @@ -1,9 +1,9 @@ -using System.Linq; +using System.Collections.Generic; using AbilityUser; using Verse; using Verse.AI; -/* +/* * Author: ChJees * Created: 2017-09-20 */ @@ -15,120 +15,112 @@ namespace AbilityUserAI /// public class JobGiver_AIAbilityUser : ThinkNode_JobGiver { + // Note: For vanilla RW (and this framework), this method is only called from TryIssueJobPackage of + // ThinkNode_PrioritySorter and ThinkNode_FilterPriority for subnodes that are JobGiver_AIAbilityUser. + // The InsertHookTest ThinkNodeDef that this framework defines in InsertHook_AbilityUserAI.xml doesn't + // use either of them, so this only matters if another mod has a JobGiver_AIAbilityUser as a subnode of + // ThinkNode_PrioritySorter/ThinkNode_FilterPriority (or custom ThinkNode that calls subnode.GetPriority). public override float GetPriority(Pawn pawn) { - var abilityUser = pawn.Abilities(); - - if (abilityUser == null) - return -100f; - - return 100; + foreach (var abilityUser in pawn.GetCompAbilityUsers()) + { + if (abilityUser.Initialized && abilityUser.AbilityData.Count > 0) + return 100f; + } + return 0f; } protected override Job TryGiveJob(Pawn pawn) { //Do we have at least one elegible profile? - var profiles = pawn.EligibleAIProfiles(); - - /*StringBuilder builder = new StringBuilder("profiles = "); + var profiles = (List)pawn.EligibleAIProfiles(); // cast to list for performance + //Log.Message("EligibleAIProfiles: " + profiles.ToStringSafeEnumerable()); - foreach(AbilityUserAIProfileDef profile in profiles) + foreach (var profile in profiles) { - builder.Append(profile.defName + ", "); - } + //Traverse the decision tree. + //List currentNodes = new List(); + //List nextNodes = new List(); - Log.Message(builder.ToString());*/ + //Seed root. + //nextNodes.Add(profile.decisionTree); - if (profiles != null && profiles.Count() > 0) - foreach (var profile in profiles) - if (profile != null) - { - //Traverse the decision tree. - //List currentNodes = new List(); - //List nextNodes = new List(); + //Result AbilityAIDef to use. + AbilityAIDef useThisAbility = null; - //Seed root. - //nextNodes.Add(profile.decisionTree); + if (profile.decisionTree != null) + useThisAbility = profile.decisionTree.RecursivelyGetAbility(pawn); - //Result AbilityAIDef to use. - AbilityAIDef useThisAbility = null; + //Debug + /*int nodesTraversed = 0; + AbilityDecisionNode lastNode = null; - if (profile.decisionTree != null) - useThisAbility = profile.decisionTree.RecursivelyGetAbility(pawn); + //Flat recursive iteration + do + { + //Add from next list to current list. + currentNodes.AddRange(nextNodes); + nextNodes.Clear(); - //Debug - /*int nodesTraversed = 0; - AbilityDecisionNode lastNode = null; + //Check if we can continue traversing on the current level. + foreach (AbilityDecisionNode currentNode in currentNodes) + { + nodesTraversed++; - //Flat recursive iteration - do - { - //Add from next list to current list. - currentNodes.AddRange(nextNodes); - nextNodes.Clear(); - - //Check if we can continue traversing on the current level. - foreach (AbilityDecisionNode currentNode in currentNodes) - { - nodesTraversed++; - - if (currentNode.CanContinueTraversing(pawn)) - nextNodes.AddRange(currentNode.subNodes); - - //Try picking an ability. - useThisAbility = currentNode.TryPickAbility(pawn); - - //Found ability to use. - if (useThisAbility != null) - { - lastNode = currentNode; - break; - } - } - - //Found ability to use. - if (useThisAbility != null) - break; - - //Clear current set. - currentNodes.Clear(); - } while (nextNodes.Count > 0);*/ - - //Debug - //if (useThisAbility != null) - // Log.Message("JobGiver_AIAbilityUser.TryGiveJob for '" + pawn.ThingID + "' with ability: " + useThisAbility.defName + ", while traversing " + nodesTraversed + " nodes."); - //else - // Log.Message("JobGiver_AIAbilityUser.TryGiveJob for '" + pawn.ThingID + "' with ability: No ability, while traversing " + nodesTraversed + " nodes."); + if (currentNode.CanContinueTraversing(pawn)) + nextNodes.AddRange(currentNode.subNodes); + //Try picking an ability. + useThisAbility = currentNode.TryPickAbility(pawn); + + //Found ability to use. if (useThisAbility != null) { - //Debug - /*Log.Message("Ability '" + useThisAbility.defName + "' picked for AI.\n" + - "lastNode=" + lastNode.GetType().Name + "\n" + - "lastNode.parent=" + lastNode?.parent?.GetType()?.Name);*/ - - //Get CompAbilityUser - var thingComp = pawn.AllComps.First(comp => comp.GetType() == profile.compAbilityUserClass); - var compAbilityUser = thingComp as CompAbilityUser; - - if (compAbilityUser != null) - { - //Get Ability from Pawn. - var useAbility = - compAbilityUser.AbilityData.AllPowers.First(ability => - ability.Def == useThisAbility.ability); - - var reason = ""; - //Give job. - if (useAbility.CanCastPowerCheck(AbilityContext.AI, out reason)) - { - var target = useThisAbility.Worker.TargetAbilityFor(useThisAbility, pawn); - if (target.IsValid) - return useAbility.UseAbility(AbilityContext.AI, target); - } - } + lastNode = currentNode; + break; + } + } + + //Found ability to use. + if (useThisAbility != null) + break; + + //Clear current set. + currentNodes.Clear(); + } while (nextNodes.Count > 0);*/ + + //Debug + //if (useThisAbility != null) + // Log.Message("JobGiver_AIAbilityUser.TryGiveJob for '" + pawn.ThingID + "' with ability: " + useThisAbility.defName + ", while traversing " + nodesTraversed + " nodes."); + //else + // Log.Message("JobGiver_AIAbilityUser.TryGiveJob for '" + pawn.ThingID + "' with ability: No ability, while traversing " + nodesTraversed + " nodes."); + + if (useThisAbility != null) + { + //Debug + /*Log.Message("Ability '" + useThisAbility.defName + "' picked for AI.\n" + + "lastNode=" + lastNode.GetType().Name + "\n" + + "lastNode.parent=" + lastNode?.parent?.GetType()?.Name);*/ + + //Get CompAbilityUser + var compAbilityUser = pawn.GetExactCompAbilityUser(profile.compAbilityUserClass); + + if (compAbilityUser != null) + { + //Get Ability from Pawn. + var useAbility = compAbilityUser.AbilityData.AllPowers + .Find(ability => ability.Def == useThisAbility.ability); + + //Give job. + if (useAbility.CanCastPowerCheck(AbilityContext.AI, out var reason)) + { + var target = useThisAbility.Worker.TargetAbilityFor(useThisAbility, pawn); + if (target.IsValid) + return useAbility.UseAbility(AbilityContext.AI, target); } } + } + } //No Job to give. //Report. @@ -136,4 +128,4 @@ protected override Job TryGiveJob(Pawn pawn) return null; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AI/TagWeight.cs b/Source/AllModdingComponents/AbilityUserAI/AI/TagWeight.cs index 9388af94..31b73186 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AI/TagWeight.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AI/TagWeight.cs @@ -1,7 +1,7 @@ using System.Xml; using Verse; -/* +/* * Author: ChJees * Created: 2017-09-23 */ @@ -44,17 +44,11 @@ public void LoadDataFromXmlCustom(XmlNode xmlRoot) } tag = xmlRoot.Name; - weight = (float) ParseHelper.FromString(xmlRoot.FirstChild.Value, typeof(float)); + weight = (float)ParseHelper.FromString(xmlRoot.FirstChild.Value, typeof(float)); } - public override string ToString() - { - return string.Concat("(", weight, "x ", tag == null ? "null" : tag, ")"); - } + public override string ToString() => $"({weight}x {tag ?? "null"})"; - public override int GetHashCode() - { - return (tag.GetHashCode() + (int) weight) << 16; - } + public override int GetHashCode() => (tag.GetHashCode() + (int)weight) << 16; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AIDefOf.cs b/Source/AllModdingComponents/AbilityUserAI/AIDefOf.cs index b487cf8b..ac082373 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AIDefOf.cs +++ b/Source/AllModdingComponents/AbilityUserAI/AIDefOf.cs @@ -1,6 +1,6 @@ using RimWorld; -/* +/* * Author: ChJees * Created: 2017-09-24 */ @@ -22,5 +22,7 @@ public static class AIDefOf /// AI version of AbilityDefOf.CastAbilitySelf. /// //public static JobDef CastAbilitySelfAI; + + static AIDefOf() => DefOfHelper.EnsureInitializedInCtor(typeof(AIDefOf)); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/AbilityUserAI.csproj b/Source/AllModdingComponents/AbilityUserAI/AbilityUserAI.csproj index 4871755f..1d2eb57e 100644 --- a/Source/AllModdingComponents/AbilityUserAI/AbilityUserAI.csproj +++ b/Source/AllModdingComponents/AbilityUserAI/AbilityUserAI.csproj @@ -1,84 +1,12 @@  - - + + - Debug - AnyCPU - {4FC16277-5CB6-4A78-90FB-27F09888708A} - Library - Properties - AbilityUserAI AbilityUserAI -<<<<<<< Updated upstream - v4.7.2 - 512 - -======= RW1.3;RW1.3Unstable;RW1.4;RW1.4Unstable ->>>>>>> Stashed changes - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - False - ..\..\..\Assemblies\0JecsTools.dll - False - - - ..\..\..\Assemblies\AbilityUser.dll - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - + + - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/AbilityUserAI/Defs/AbilityAIDef.cs b/Source/AllModdingComponents/AbilityUserAI/Defs/AbilityAIDef.cs index 76876b48..e25dfda1 100644 --- a/Source/AllModdingComponents/AbilityUserAI/Defs/AbilityAIDef.cs +++ b/Source/AllModdingComponents/AbilityUserAI/Defs/AbilityAIDef.cs @@ -3,7 +3,7 @@ using AbilityUser; using Verse; -/* +/* * Author: ChJees * Created: 2017-09-20 */ @@ -88,17 +88,7 @@ public class AbilityAIDef : Def /// /// Worker object for this Ability. Default implementation is only taking in account for single target abilities. /// - public AbilityWorker Worker - { - get - { - //Instantiate if null. - if (intWorkerClass == null) - intWorkerClass = (AbilityWorker) Activator.CreateInstance(workerClass); - - return intWorkerClass; - } - } + public AbilityWorker Worker => intWorkerClass ??= (AbilityWorker)Activator.CreateInstance(workerClass); /// /// Can the caster use this ability at all? @@ -137,5 +127,10 @@ public bool CanPawnUseThisAbility(Pawn caster, LocalTargetInfo target) //Valid ability to use. return true; } + + public override string ToString() + { + return base.ToString() + $" (ability={ability})"; + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/Defs/AbilityUserAIProfileDef.cs b/Source/AllModdingComponents/AbilityUserAI/Defs/AbilityUserAIProfileDef.cs index a069aed4..4fd40e37 100644 --- a/Source/AllModdingComponents/AbilityUserAI/Defs/AbilityUserAIProfileDef.cs +++ b/Source/AllModdingComponents/AbilityUserAI/Defs/AbilityUserAIProfileDef.cs @@ -3,7 +3,7 @@ using RimWorld; using Verse; -/* +/* * Author: ChJees * Created: 2017-09-22 */ @@ -54,17 +54,7 @@ public class AbilityUserAIProfileDef : Def /// Worker object for this Profile. If workerClass is not specified it will use the default implementation which only /// checks for Traits. /// - public AbilityProfileWorker Worker - { - get - { - //Instantiate if null. - if (intWorkerClass == null) - intWorkerClass = (AbilityProfileWorker) Activator.CreateInstance(workerClass); - - return intWorkerClass; - } - } + public AbilityProfileWorker Worker => intWorkerClass ??= (AbilityProfileWorker)Activator.CreateInstance(workerClass); /// /// All tag weights. The higher weight the better score. @@ -73,10 +63,7 @@ public AbilityProfileWorker Worker public override void ResolveReferences() { base.ResolveReferences(); - - //Resolve the decision tree. - if (decisionTree != null) - decisionTree.Resolve(this); + decisionTree?.Resolve(this); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/Utility/AbilityMaths.cs b/Source/AllModdingComponents/AbilityUserAI/Utility/AbilityMaths.cs index 03ef7dde..1391a1ca 100644 --- a/Source/AllModdingComponents/AbilityUserAI/Utility/AbilityMaths.cs +++ b/Source/AllModdingComponents/AbilityUserAI/Utility/AbilityMaths.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Verse; -/* +/* * Author: ChJees * Created: 2017-11-04 */ @@ -74,4 +74,4 @@ public static bool CircleIntersectionTest(float x0, float y0, float radius0, flo return false; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/Utility/AbilityUtility.cs b/Source/AllModdingComponents/AbilityUserAI/Utility/AbilityUtility.cs index 58601288..0a73d874 100644 --- a/Source/AllModdingComponents/AbilityUserAI/Utility/AbilityUtility.cs +++ b/Source/AllModdingComponents/AbilityUserAI/Utility/AbilityUtility.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; using AbilityUser; using Verse; -/* +/* * Author: ChJees * Created: 2017-09-20 */ @@ -27,43 +26,44 @@ public static class AbilityUtility /// /// Pawn to check. /// Ability user if present. Null if none can be found. + [Obsolete("Use the GetCompAbilityUsers extension method instead")] public static CompAbilityUser Abilities(this Pawn pawn) { - return pawn.GetComp(); + return pawn.GetCompAbilityUser(); } /// /// Gets all profiles from the Def database. + /// Returns it as a List, but for backwards compatibility, must return IEnumerable. /// /// All Def Database profiles. public static IEnumerable Profiles() { - return DefDatabase.AllDefs; + return DefDatabase.AllDefsListForReading; } /// /// Gets all AI profiles which are eligible for this pawn. + /// Returns it as a List, but for backwards compatibility, must return IEnumerable. /// /// Pawn to get for. /// Matching profiles. public static IEnumerable EligibleAIProfiles(this Pawn pawn) { - IEnumerable result = - from matchingProfileDef in - - //Initial filtering. - (from thingComp in pawn.AllComps - from profileDef in Profiles() - where thingComp.GetType() == profileDef.compAbilityUserClass - select profileDef) - - //Finer filtering. - //where matchingProfileDef.matchingTraits.Count <= 0 || (matchingProfileDef.matchingTraits.Count > 0 && matchingProfileDef.matchingTraits.Any(traitDef => pawn.story.traits.HasTrait(traitDef))) - where matchingProfileDef.Worker.ValidProfileFor(matchingProfileDef, pawn) - orderby matchingProfileDef.priority descending - select matchingProfileDef; - - return result; + var eligibleProfiles = new List(); + foreach (var matchingProfile in (List)Profiles()) // cast to List for performance + { + if (pawn.GetExactCompAbilityUser(matchingProfile.compAbilityUserClass) != null && + //(matchingProfile.matchingTraits.Count == 0 || + // matchingProfile.matchingTraits.Exists(traitDef => pawn.story.traits.HasTrait(traitDef))) && + matchingProfile.Worker.ValidProfileFor(matchingProfile, pawn)) + { + eligibleProfiles.Add(matchingProfile); + } + } + // orderby matchingProfile.priority descending + eligibleProfiles.Sort((x, y) => y.priority.CompareTo(x.priority)); + return eligibleProfiles; } /// @@ -78,13 +78,18 @@ public static IEnumerable GetPawnsInsideRadius(LocalTargetInfo center, Map Predicate targetPredicate) { //With no predicate, just grab everything. - if (targetPredicate == null) - targetPredicate = thing => true; + targetPredicate ??= thing => true; + var centerCell = center.Cell; foreach (Pawn pawn in map.listerThings.ThingsInGroup(ThingRequestGroup.Pawn)) - if (AbilityMaths.CircleIntersectionTest(pawn.Position.x, pawn.Position.y, 1f, center.Cell.x, - center.Cell.y, radius) && targetPredicate(pawn)) + { + var pawnPos = pawn.Position; + if (AbilityMaths.CircleIntersectionTest(pawnPos.x, pawnPos.y, 1f, centerCell.x, centerCell.y, radius) && + targetPredicate(pawn)) + { yield return pawn; + } + } } /// @@ -137,12 +142,11 @@ public static bool LineOfSightLocalTarget(Thing caster, LocalTargetInfo target, ShootLeanUtility.LeanShootingSourcesFromTo(caster.Position, target.Cell, caster.Map, tempSourceList); //See if we can get target from any source cell. - if (tempSourceList.Count > 0) - foreach (var sourceCell in tempSourceList) - if (GenSight.LineOfSight(sourceCell, target.Cell, caster.Map, skipFirstCell, validator)) - return true; + foreach (var sourceCell in tempSourceList) + if (GenSight.LineOfSight(sourceCell, target.Cell, caster.Map, skipFirstCell, validator)) + return true; return false; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityProfileWorker.cs b/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityProfileWorker.cs index 207dd52e..7648e886 100644 --- a/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityProfileWorker.cs +++ b/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityProfileWorker.cs @@ -1,6 +1,6 @@ using Verse; -/* +/* * Author: ChJees * Created: 2017-10-19 */ @@ -22,7 +22,7 @@ public class AbilityProfileWorker public virtual bool ValidProfileFor(AbilityUserAIProfileDef profileDef, Pawn pawn) { //Default implementation only cares about checking for matching Traits. - return profileDef.matchingTraits.Count <= 0 || profileDef.matchingTraits.Count > 0 && + return profileDef.matchingTraits.Count == 0 || profileDef.matchingTraits.Any(traitDef => pawn.story.traits.HasTrait(traitDef)); } @@ -38,4 +38,4 @@ public virtual bool CanUseAbility(AbilityUserAIProfileDef profileDef, Pawn pawn, return true; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker.cs b/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker.cs index 5bbb9f7f..078bc125 100644 --- a/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker.cs +++ b/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker.cs @@ -1,7 +1,7 @@ using Verse; using Verse.AI; -/* +/* * Author: ChJees * Created: 2017-10-19 */ @@ -43,17 +43,20 @@ public virtual LocalTargetInfo TargetAbilityFor(AbilityAIDef abilityDef, Pawn pa TraverseParms.For(TraverseMode.NoPassClosedDoors), abilityDef.maxRange, thing => AbilityUtility.AreAllies(pawn, thing)); } - if (pawn.mindState.enemyTarget != null && pawn.mindState.enemyTarget is Pawn targetPawn) + var enemyTarget = pawn.mindState.enemyTarget; + if (enemyTarget is Pawn targetPawn) { if (!targetPawn.Dead) - return pawn.mindState.enemyTarget; + return enemyTarget; } - else + else if (enemyTarget is Corpse) { - if (pawn.mindState.enemyTarget != null && !(pawn.mindState.enemyTarget is Corpse)) - return pawn.mindState.enemyTarget; + return null; + } + else if (enemyTarget != null) + { + return enemyTarget; } - return null; } @@ -79,4 +82,4 @@ public virtual bool CanPawnUseThisAbility(AbilityAIDef abilityDef, Pawn pawn, Lo return true; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker_AreaOfEffect.cs b/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker_AreaOfEffect.cs index a1cadc6d..1cba6c0b 100644 --- a/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker_AreaOfEffect.cs +++ b/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker_AreaOfEffect.cs @@ -4,7 +4,7 @@ using Verse; using Verse.AI; -/* +/* * Author: ChJees * Created: 2017-11-04 */ @@ -107,30 +107,25 @@ public virtual IEnumerable GrabTargets(AbilityAIDef abilityDef, Pawn pawn { //Make a list of candidates. var potentionalTargets = new List(); - Predicate pawnPredicate = null; + Predicate pawnPredicate; if (customPredicate != null) pawnPredicate = customPredicate; else if (abilityDef.canTargetAlly) - pawnPredicate = delegate(Thing thing) + pawnPredicate = thing => { //Count own faction and faction whose goodwill they got above 50% as allies. - if (AbilityUtility.AreAllies(pawn, thing)) - return true; - return false; + return AbilityUtility.AreAllies(pawn, thing); }; else - pawnPredicate = delegate(Thing thing) + pawnPredicate = thing => { - var thingPawn = thing as Pawn; - //Count anything hostile as a target. - if (thingPawn != null) + if (thing is Pawn thingPawn) if (!thingPawn.Downed && thing.HostileTo(pawn)) return true; else if (thing.HostileTo(pawn)) return true; - return false; }; @@ -155,4 +150,4 @@ public virtual IEnumerable GrabTargets(AbilityAIDef abilityDef, Pawn pawn } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker_HealAlly.cs b/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker_HealAlly.cs index 11238c5f..52685df0 100644 --- a/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker_HealAlly.cs +++ b/Source/AllModdingComponents/AbilityUserAI/Workers/AbilityWorker_HealAlly.cs @@ -2,7 +2,7 @@ using Verse; using Verse.AI; -/* +/* * Author: ChJees * Created: 2017-11-05 */ @@ -62,9 +62,7 @@ public virtual Pawn PickBestClosestPawn(AbilityAIDef abilityDef, Pawn pawn) checkedThings.Add(foundThing); - var foundPawn = foundThing as Pawn; - - if (foundPawn != null) + if (foundThing is Pawn foundPawn) if (foundPawn.health.summaryHealth.SummaryHealthPercent < bestHealth) { bestPawn = foundPawn; @@ -75,4 +73,4 @@ public virtual Pawn PickBestClosestPawn(AbilityAIDef abilityDef, Pawn pawn) return bestPawn; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/AbilityButtons.cs b/Source/AllModdingComponents/CompAbilityUser/AbilityButtons.cs index 2d8c5df3..220f9011 100755 --- a/Source/AllModdingComponents/CompAbilityUser/AbilityButtons.cs +++ b/Source/AllModdingComponents/CompAbilityUser/AbilityButtons.cs @@ -4,9 +4,9 @@ namespace AbilityUser { [StaticConstructorOnStartup] - public class AbilityButtons + public static class AbilityButtons { public static readonly Texture2D EmptyTex = SolidColorMaterials.NewSolidColorTexture(Color.clear); public static readonly Texture2D FullTex = SolidColorMaterials.NewSolidColorTexture(0.5f, 0.5f, 0.5f, 0.6f); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/AbilityDefOf.cs b/Source/AllModdingComponents/CompAbilityUser/AbilityDefOf.cs index c92dc946..519f19aa 100755 --- a/Source/AllModdingComponents/CompAbilityUser/AbilityDefOf.cs +++ b/Source/AllModdingComponents/CompAbilityUser/AbilityDefOf.cs @@ -8,5 +8,7 @@ public static class AbilityDefOf { public static JobDef CastAbilitySelf; public static JobDef CastAbilityVerb; + + static AbilityDefOf() => DefOfHelper.EnsureInitializedInCtor(typeof(AbilityDefOf)); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/AbilityUserUtility.cs b/Source/AllModdingComponents/CompAbilityUser/AbilityUserUtility.cs index f9a45486..5df0e66d 100644 --- a/Source/AllModdingComponents/CompAbilityUser/AbilityUserUtility.cs +++ b/Source/AllModdingComponents/CompAbilityUser/AbilityUserUtility.cs @@ -1,61 +1,114 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using HarmonyLib; using Verse; namespace AbilityUser { - // register each class that inherits from CompAbilityUser so their callbacks are called - // then use standard call when generating a pawn to create their CompAbilityUser - - + // Registers each class that inherits from CompAbilityUser so their callbacks are called. + // Also provides CompAbilityUser/CompAbilityItem access utility methods. public static class AbilityUserUtility { - public static List abilityUserChildren; + // Compatibility note: Must remain a public list in case other mods are accessing it. + public static readonly List abilityUserChildren = GenTypes.AllSubclassesNonAbstract(typeof(CompAbilityUser)).ToList(); - public static List GetAllChildrenOf(Type pType) + public static bool TransformPawn(Pawn p) { - var retval = new List(); - var asslist = new List(AppDomain.CurrentDomain.GetAssemblies()); - if (asslist != null) - foreach (var ass in asslist) - if (ass != null) - { - var asschildren = ass.GetTypes() - .Where(t => t.IsClass && t != pType && pType.IsAssignableFrom(t)).ToList(); - if (asschildren != null) retval.AddRange(asschildren); - } - return retval; + static bool ContainsType(List comps, int compCount, Type compClass) + { + for (var i = 0; i < compCount; i++) + { + if (comps[i].GetType() == compClass) + return true; + } + return false; + } + + ref var compsRef = ref compsField(p); + compsRef ??= new List(); + var comps = compsRef; + var compCount = comps.Count; // used in ContainsType to avoid iterating over just-added comps + foreach (var abilityUserType in abilityUserChildren) + { + // Avoid adding the same comp type if the pawn already has it (e.g. defined in XML). + if (ContainsType(comps, compCount, abilityUserType)) + continue; + + // This code used to do a TryTransformPawn check, but since there is no good way to create triggers when + // specific events occur to add the CompAbilityUser to a Pawn, this just adds them (and always returns true), + // and CompAbilityUser's CompTick calls TryTransformPawn until it succeeds (and calls CompAbilityUser.Initialize()). + var thingComp = (ThingComp)Activator.CreateInstance(abilityUserType); + thingComp.parent = p; + comps.Add(thingComp); + // Always initialize with null CompProperties, since no XML def (and no way to determine the exact type anyway). + thingComp.Initialize(null); + //Log.Message($"AbilityUserUtility.TransformPawn({p}): added comp {thingComp}"); + } + return true; } + private static readonly AccessTools.FieldRef> compsField = + AccessTools.FieldRefAccess>("comps"); - public static bool TransformPawn(Pawn p) + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + [Obsolete("This isn't safe to use when there are multiple CompAbilityUsers - " + + "use HasCompAbilityUser or GetCompAbilityUsers or GetExactCompAbilityUser instead")] + public static CompAbilityUser GetCompAbilityUser(this ThingWithComps thing) { - var retval = false; - if (abilityUserChildren == null) - abilityUserChildren = GetAllChildrenOf(typeof(CompAbilityUser)); + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompAbilityUser comp) + return comp; + } + return null; + } - foreach (var t in abilityUserChildren) + public static bool HasCompAbilityUser(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) { - var st = true; - /* - // this code does a check, but since there is no good way to create triggers when specific events occur to - // add the CompAbilityUser to a Pawn, this just adds them and then checks them on each CompTick. - */ - if (st) - { - retval = true; - var thingComp = (ThingComp) Activator.CreateInstance(t); - thingComp.parent = p; - var comps = AccessTools.Field(typeof(ThingWithComps), "comps").GetValue(p); - if (comps != null) - ((List) comps).Add(thingComp); - thingComp.Initialize(null); - } + if (comps[i] is CompAbilityUser) + return true; + } + return false; + } + + // ThingWithComps.GetComps is also slow for the same reason, so implementing a specific non-generic version of it here. + public static IEnumerable GetCompAbilityUsers(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompAbilityUser comp) + yield return comp; + } + } + + public static CompAbilityUser GetExactCompAbilityUser(this ThingWithComps thing, Type compClass) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + var comp = comps[i]; + if (comp.GetType() == compClass) + return comp as CompAbilityUser; + } + return null; + } + + public static IEnumerable GetCompAbilityItems(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompAbilityItem comp) + yield return comp; } - return retval; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/AoEProperties.cs b/Source/AllModdingComponents/CompAbilityUser/AoEProperties.cs index 9db46e2d..67c241fe 100755 --- a/Source/AllModdingComponents/CompAbilityUser/AoEProperties.cs +++ b/Source/AllModdingComponents/CompAbilityUser/AoEProperties.cs @@ -11,4 +11,4 @@ public class TargetAoEProperties public bool startsFromCaster = true; public Type targetClass; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/ApplyHediffs.cs b/Source/AllModdingComponents/CompAbilityUser/ApplyHediffs.cs index 820674dd..a1b9fd2d 100755 --- a/Source/AllModdingComponents/CompAbilityUser/ApplyHediffs.cs +++ b/Source/AllModdingComponents/CompAbilityUser/ApplyHediffs.cs @@ -10,8 +10,8 @@ public class ApplyHediffs : IExposable public void ExposeData() { - Scribe_Values.Look(ref applyChance, "applyChance", -1.0f); - Scribe_Values.Look(ref severity, "severity", 1.0f); + Scribe_Values.Look(ref applyChance, nameof(applyChance), -1.0f); + Scribe_Values.Look(ref severity, nameof(severity), 1.0f); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/ApplyMentalStates.cs b/Source/AllModdingComponents/CompAbilityUser/ApplyMentalStates.cs index 0c18f3ea..f7c6124a 100755 --- a/Source/AllModdingComponents/CompAbilityUser/ApplyMentalStates.cs +++ b/Source/AllModdingComponents/CompAbilityUser/ApplyMentalStates.cs @@ -9,8 +9,8 @@ public class ApplyMentalStates : IExposable public void ExposeData() { - Scribe_Defs.Look(ref mentalStateDef, "mentalStateDef"); - Scribe_Values.Look(ref applyChance, "applyChance", 1.0f); + Scribe_Defs.Look(ref mentalStateDef, nameof(mentalStateDef)); + Scribe_Values.Look(ref applyChance, nameof(applyChance), 1.0f); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/CompAbilityItem.cs b/Source/AllModdingComponents/CompAbilityUser/CompAbilityItem.cs index d58bcde8..9a4d600b 100755 --- a/Source/AllModdingComponents/CompAbilityUser/CompAbilityItem.cs +++ b/Source/AllModdingComponents/CompAbilityUser/CompAbilityItem.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using System.Text; +using RimWorld; using UnityEngine; using Verse; @@ -6,70 +8,110 @@ namespace AbilityUser { public class CompAbilityItem : ThingComp { - public List Abilities = new List() - ; // should these exist or only in CompAbilityUser.temporaryWeaponPowers? - + // TODO: Should these exist or only in CompAbilityUser.temporaryWeaponPowers? + // Abilities is currently never used within the framework (only Props.Abilities is used), + // while AbilityUserTarget is set via Harmony patches. + // For backwards compatibility, in case any other mod is using these, must leave these as-is, + // including the potentially wasteful empty List initialization. + public List Abilities = new List(0); public CompAbilityUser AbilityUserTarget = null; + // Compatibility note: as of 2020-10-20, a mod (A RimWorld of Magic) uses reflection to access this to + // workaround a now-fixed oversight where PostDrawExtraSelectionOverlays constantly logged "NoOverlay". private Graphic Overlay; - public CompProperties_AbilityItem Props => (CompProperties_AbilityItem) props; + public CompProperties_AbilityItem Props => (CompProperties_AbilityItem)props; - public void GetOverlayGraphic() + public virtual Graphic GetOverlayGraphic() { - // Cool effect if you uncomment. Places this graffic behind the item. -// this.Overlay = GraphicDatabase.Get("UI/Glow_Corrupt", ShaderDatabase.MetaOverlay, Vector2.one, Color.white); + // TODO: Remove - UI/Glow_Corrupt texture was never added to JecsTools. + //return GraphicDatabase.Get("UI/Glow_Corrupt", ShaderDatabase.MetaOverlay, Vector2.one, Color.white); + return null; } - public override void PostSpawnSetup(bool respawningAfterLoad) { if (parent.def.tickerType == TickerType.Never) parent.def.tickerType = TickerType.Rare; base.PostSpawnSetup(respawningAfterLoad); - GetOverlayGraphic(); + Overlay = GetOverlayGraphic(); Find.TickManager.RegisterAllTickabilityFor(parent); } + //public override void CompTick() { } + //public override void CompTickRare() { } + public override void PostDrawExtraSelectionOverlays() { - if (Overlay == null) Log.Message("NoOverlay"); if (Overlay != null) { var drawPos = parent.DrawPos; drawPos.y = Altitudes.AltitudeFor(AltitudeLayer.MoteOverhead); var s = new Vector3(2.0f, 2.0f, 2.0f); - var matrix = default(Matrix4x4); - matrix.SetTRS(drawPos, Quaternion.AngleAxis(0, Vector3.up), s); + var matrix = Matrix4x4.TRS(drawPos, Quaternion.AngleAxis(0, Vector3.up), s); Graphics.DrawMesh(MeshPool.plane10, matrix, Overlay.MatSingle, 0); } } - // public override void CompTick() { } - // public override void CompTickRare() { } + public override void Notify_Equipped(Pawn pawn) + { + base.Notify_Equipped(pawn); + var abilityUserClass = Props.AbilityUserClass; + var abilities = Props.Abilities; + //Log.Message(" Found CompAbilityItem, for CompAbilityUser of " + abilityUserClass); + foreach (var cau in pawn.GetCompAbilityUsers()) + { + AddAbilityFunc addAbilityFunc = parent is Apparel ? cau.AddApparelAbility : cau.AddWeaponAbility; + //Log.Message(" Found CompAbilityUser, " + cau + " : " + cau.GetType() + ":" + abilityUserClass); + if (cau.GetType() == abilityUserClass) + { + //Log.Message(" and they match types"); + AbilityUserTarget = cau; + foreach (var abdef in abilities) + addAbilityFunc(abdef); + } + } + } + + private delegate void AddAbilityFunc(AbilityDef abilityDef, bool activenow = true, float savedTicks = -1); - public override void PostExposeData() + public override void Notify_Unequipped(Pawn pawn) { - base.PostExposeData(); + base.Notify_Unequipped(pawn); + //Log.Message(" Found CompAbilityItem, for CompAbilityUser of " + Props.AbilityUserClass); + foreach (var cau in pawn.GetCompAbilityUsers()) + { + RemoveAbilityFunc removeAbilityFunc = parent is Apparel ? cau.RemoveApparelAbility : cau.RemoveWeaponAbility; + //Log.Message(" Found CompAbilityUser, " + cau + " : " + cau.GetType() + ":" + Props.AbilityUserClass); + if (cau.GetType() == Props.AbilityUserClass) + { + //Log.Message(" and they match types"); + foreach (var abdef in Props.Abilities) + removeAbilityFunc(abdef); + } + } } + private delegate void RemoveAbilityFunc(AbilityDef abilityDef); + public override string GetDescriptionPart() { - var str = string.Empty; + var s = new StringBuilder(); if (Props.Abilities.Count == 1) - str += "Item Ability:"; + s.Append("Item Ability:"); else if (Props.Abilities.Count > 1) - str += "Item Abilities:"; + s.Append("Item Abilities:"); foreach (var pa in Props.Abilities) { - str += "\n\n"; - str += pa.label.CapitalizeFirst() + " - "; - str += pa.GetDescription(); + s.Append("\n\n"); + s.Append(pa.label.CapitalizeFirst()); + s.Append(" - "); + s.Append(pa.GetDescription()); } - return str; + return s.ToString(); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/CompAbilityUser.csproj b/Source/AllModdingComponents/CompAbilityUser/CompAbilityUser.csproj index 43d199fb..55ee7aa1 100755 --- a/Source/AllModdingComponents/CompAbilityUser/CompAbilityUser.csproj +++ b/Source/AllModdingComponents/CompAbilityUser/CompAbilityUser.csproj @@ -1,90 +1,7 @@  - - + + - Debug - AnyCPU - {417B8649-7A66-4580-8C75-473E46DA9C7A} - Library - Properties - AbilityUser AbilityUser - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompAbilityUser/CompProperties_AbilityItem.cs b/Source/AllModdingComponents/CompAbilityUser/CompProperties_AbilityItem.cs index 7d2647e7..7a9d31d0 100644 --- a/Source/AllModdingComponents/CompAbilityUser/CompProperties_AbilityItem.cs +++ b/Source/AllModdingComponents/CompAbilityUser/CompProperties_AbilityItem.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Verse; @@ -16,4 +16,4 @@ public CompProperties_AbilityItem() AbilityUserClass = typeof(GenericCompAbilityUser); // default } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/CompProperties_AbilityUser.cs b/Source/AllModdingComponents/CompAbilityUser/CompProperties_AbilityUser.cs index d7064cad..2c216a9b 100644 --- a/Source/AllModdingComponents/CompAbilityUser/CompProperties_AbilityUser.cs +++ b/Source/AllModdingComponents/CompAbilityUser/CompProperties_AbilityUser.cs @@ -9,4 +9,4 @@ public CompProperties_AbilityUser() compClass = typeof(CompAbilityUser); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/AbilityContext.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/AbilityContext.cs index 8abcb55c..9b7d0f3f 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/AbilityContext.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/AbilityContext.cs @@ -5,4 +5,4 @@ public enum AbilityContext Player, AI } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/AbilityEffectUtility.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/AbilityEffectUtility.cs index a3c927b8..833fba4e 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/AbilityEffectUtility.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/AbilityEffectUtility.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using AbilityUser; using RimWorld; using Verse; @@ -10,8 +9,10 @@ static internal class AbilityEffectUtility public static Faction ResolveFaction(SpawnThings spawnables, Pawn caster) { var factionDefToAssign = FactionDefOf.PlayerColony; - if (caster?.Faction is Faction f && f.IsPlayer == false) return f; - if (spawnables.factionDef != null) factionDefToAssign = spawnables.factionDef; + if (caster?.Faction is Faction f && f.IsPlayer == false) + return f; + if (spawnables.factionDef != null) + factionDefToAssign = spawnables.factionDef; if (spawnables.kindDef != null) if (spawnables.kindDef.defaultFactionType != null) factionDefToAssign = spawnables.kindDef.defaultFactionType; @@ -21,7 +22,7 @@ public static Faction ResolveFaction(SpawnThings spawnables, Pawn caster) public static PawnSummoned SpawnPawn(SpawnThings spawnables, Faction faction, Pawn caster, IntVec3 positionHeld) { - var newPawn = (PawnSummoned) PawnGenerator.GeneratePawn(spawnables.kindDef, faction); + var newPawn = (PawnSummoned)PawnGenerator.GeneratePawn(spawnables.kindDef, faction); newPawn.Spawner = caster; newPawn.Temporary = spawnables.temporary; if (newPawn.Faction != Faction.OfPlayerSilentFail && caster?.Faction is Faction f) @@ -32,8 +33,8 @@ public static PawnSummoned SpawnPawn(SpawnThings spawnables, Faction faction, Pa Lord lord = null; if (newPawn.Map.mapPawns.SpawnedPawnsInFaction(faction).Any(p => p != newPawn)) { - Predicate validator = p => p != newPawn && ((Pawn) p).GetLord() != null; - var p2 = (Pawn) GenClosest.ClosestThing_Global(newPawn.Position, + bool validator(Thing p) => p != newPawn && ((Pawn)p).GetLord() != null; + var p2 = (Pawn)GenClosest.ClosestThing_Global(newPawn.Position, newPawn.Map.mapPawns.SpawnedPawnsInFaction(faction), 99999f, validator); lord = p2.GetLord(); } @@ -49,11 +50,9 @@ public static PawnSummoned SpawnPawn(SpawnThings spawnables, Faction faction, Pa public static void SingleSpawnLoop(SpawnThings spawnables, IntVec3 positionHeld, Map mapHeld, Pawn caster) { - //Log.Message("SingleSpawnLoops"); + //Log.Message($"AbilityEffectUtility.SingleSpawnLoop({spawnables}, ...)"); if (spawnables.def != null) { - //Log.Message("2"); - var factionToAssign = ResolveFaction(spawnables, caster); if (spawnables.def.race != null) { @@ -62,12 +61,12 @@ public static void SingleSpawnLoop(SpawnThings spawnables, IntVec3 positionHeld, Log.Error("Missing kinddef"); return; } - Pawn p = SpawnPawn(spawnables, factionToAssign, caster, positionHeld); - //if (this?.Caster?.Faction is Faction f && Faction.OfPlayerSilentFail != f) p.SetFactionDirect(f); + //Pawn p = + SpawnPawn(spawnables, factionToAssign, caster, positionHeld); + //if (caster?.Faction is Faction f && Faction.OfPlayerSilentFail != f) p.SetFactionDirect(f); } else { - //Log.Message("3b"); var thingDef = spawnables.def; ThingDef stuff = null; if (thingDef.MadeFromStuff) @@ -81,88 +80,82 @@ public static void SingleSpawnLoop(SpawnThings spawnables, IntVec3 positionHeld, public static void SpawnSpawnables(List localSpawnThings, Pawn caster, Map mapHeld, IntVec3 positionHeld) { - //Log.Message("SpawnSpawnables"); - if (localSpawnThings != null && localSpawnThings.Count > 0) + //Log.Message($"AbilityEffectUtility.SpawnSpawnables(..., caster={caster}, mapHeld={mapHeld}, positionHeld={positionHeld})"); + if (localSpawnThings != null) foreach (var spawnables in localSpawnThings) - //Log.Message("2S"); if (spawnables.spawnCount == 1) - SingleSpawnLoop(spawnables,positionHeld, mapHeld, caster); + SingleSpawnLoop(spawnables, positionHeld, mapHeld, caster); else for (var i = 0; i < spawnables.spawnCount; i++) - //Log.Message("3S"); SingleSpawnLoop(spawnables, positionHeld, mapHeld, caster); } public static void ApplyHediffs(Pawn victim, Pawn caster, List localApplyHediffs, Projectile_AbilityBase abilityProjectile) { if (localApplyHediffs != null) - if (localApplyHediffs.Count > 0) - foreach (var hediffs in localApplyHediffs) - { - var success = false; - if (Rand.Value <= hediffs.applyChance) - if (victim == caster || abilityProjectile?.CanOverpower(caster, victim) != false) - { - HealthUtility.AdjustSeverity(victim, hediffs.hediffDef, hediffs.severity); - success = true; - } - - if (success) - { - victim.Drawer.Notify_DebugAffected(); - MoteMaker.ThrowText(victim.DrawPos, victim.Map, - hediffs.hediffDef.LabelCap + ": " + StringsToTranslate.AU_CastSuccess, -1f); - } - else + foreach (var hediffs in localApplyHediffs) + { + var success = false; + if (Rand.Value <= hediffs.applyChance) + if (victim == caster || abilityProjectile?.CanOverpower(caster, victim) != false) // note: null != false => true { - MoteMaker.ThrowText(victim.DrawPos, victim.Map, StringsToTranslate.AU_CastFailure, -1f); + HealthUtility.AdjustSeverity(victim, hediffs.hediffDef, hediffs.severity); + success = true; } + + if (success) + { + victim.Drawer.Notify_DebugAffected(); + MoteMaker.ThrowText(victim.DrawPos, victim.Map, + hediffs.hediffDef.LabelCap + ": " + StringsToTranslate.AU_CastSuccess); + } + else + { + MoteMaker.ThrowText(victim.DrawPos, victim.Map, StringsToTranslate.AU_CastFailure); } + } } - + public static void ApplyMentalStates(Pawn victim, Pawn caster, List localApplyMentalStates, AbilityUser.AbilityDef localAbilityDef, Projectile_AbilityBase abilityProjectile) { if (localApplyMentalStates != null) - if (localApplyMentalStates.Count > 0) - foreach (var mentalStateGiver in localApplyMentalStates) - { - var success = false; - var checkValue = Rand.Value; - var str = localAbilityDef.LabelCap + " (" + caster.LabelShort + ")"; - if (checkValue <= mentalStateGiver.applyChance) - if (mentalStateGiver.mentalStateDef == MentalStateDefOf.Berserk && - victim.RaceProps.intelligence < Intelligence.Humanlike) - { - if (caster == victim || abilityProjectile?.CanOverpower(caster, victim) != false) - { - success = true; - victim.mindState.mentalStateHandler.TryStartMentalState( - MentalStateDefOf.Manhunter, str, true); - } - } - else + foreach (var mentalStateGiver in localApplyMentalStates) + { + var success = false; + var checkValue = Rand.Value; + var str = localAbilityDef.LabelCap + " (" + caster.LabelShort + ")"; + if (checkValue <= mentalStateGiver.applyChance) + if (mentalStateGiver.mentalStateDef == MentalStateDefOf.Berserk && + victim.RaceProps.intelligence < Intelligence.Humanlike) + { + if (caster == victim || abilityProjectile?.CanOverpower(caster, victim) != false) // note: null != false => true { - if (caster == victim || abilityProjectile?.CanOverpower(caster, victim) != false) - { - success = true; - victim.mindState.mentalStateHandler.TryStartMentalState( - mentalStateGiver.mentalStateDef, str, true); - } + success = true; + victim.mindState.mentalStateHandler.TryStartMentalState( + MentalStateDefOf.Manhunter, str, true); } - - if (success) - { - victim.Drawer.Notify_DebugAffected(); - MoteMaker.ThrowText(victim.DrawPos, victim.Map, - mentalStateGiver.mentalStateDef.LabelCap + ": " + StringsToTranslate.AU_CastSuccess, - -1f); } else { - MoteMaker.ThrowText(victim.DrawPos, victim.Map, - mentalStateGiver.mentalStateDef.LabelCap + ": " + StringsToTranslate.AU_CastFailure, - -1f); + if (caster == victim || abilityProjectile?.CanOverpower(caster, victim) != false) // note: null != false => true + { + success = true; + victim.mindState.mentalStateHandler.TryStartMentalState( + mentalStateGiver.mentalStateDef, str, true); + } } + + if (success) + { + victim.Drawer.Notify_DebugAffected(); + MoteMaker.ThrowText(victim.DrawPos, victim.Map, + mentalStateGiver.mentalStateDef.LabelCap + ": " + StringsToTranslate.AU_CastSuccess); } + else + { + MoteMaker.ThrowText(victim.DrawPos, victim.Map, + mentalStateGiver.mentalStateDef.LabelCap + ": " + StringsToTranslate.AU_CastFailure); + } + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/JobDriver_CastAbilitySelf.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/JobDriver_CastAbilitySelf.cs index 4a645a1a..3eea4c05 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/JobDriver_CastAbilitySelf.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/JobDriver_CastAbilitySelf.cs @@ -9,19 +9,6 @@ public class JobDriver_CastAbilitySelf : JobDriver { public AbilityContext Context => job.count == 1 ? AbilityContext.Player : AbilityContext.AI; - private List CompAbilityUsers - { - get - { - var results = new List(); - var allCompAbilityUsers = pawn.GetComps(); - if (allCompAbilityUsers.TryRandomElement(out var comp)) - foreach (var compy in allCompAbilityUsers) - results.Add(compy); - return results; - } - } - public override bool TryMakePreToilReservations(bool errorOnFailed) { return true; @@ -33,23 +20,23 @@ protected override IEnumerable MakeNewToils() var verb = pawn.CurJob.verbToUse as Verb_UseAbility; Find.Targeter.targetingSource = verb; - yield return Toils_Combat.CastVerb(TargetIndex.A, false); + yield return Toils_Combat.CastVerb(TargetIndex.A, TargetIndex.B, canHitNonTargetPawns: false); yield return new Toil { - initAction = delegate { verb.Ability.PostAbilityAttempt(); }, - defaultCompleteMode = ToilCompleteMode.Instant + initAction = verb.Ability.PostAbilityAttempt, + defaultCompleteMode = ToilCompleteMode.Instant, }; yield return new Toil { - initAction = delegate + initAction = () => { if (verb.UseAbilityProps.isViolent) { - JobDriver_CastAbilityVerb.CheckForAutoAttack(this.pawn); + JobDriver_CastAbilityVerb.CheckForAutoAttack(pawn); } }, - defaultCompleteMode = ToilCompleteMode.Instant + defaultCompleteMode = ToilCompleteMode.Instant, }; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/JobDriver_CastAbilityVerb.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/JobDriver_CastAbilityVerb.cs index 9689a53e..b5cb1bb2 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/JobDriver_CastAbilityVerb.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/JobDriver_CastAbilityVerb.cs @@ -5,6 +5,7 @@ namespace AbilityUser { + // Based off JobDriver_Wait. public class JobDriver_CastAbilityVerb : JobDriver { public AbilityContext Context => job.count == 1 ? AbilityContext.Player : AbilityContext.AI; @@ -26,7 +27,7 @@ protected override IEnumerable MakeNewToils() if (!pawn.Position.InHorDistOf(TargetA.Cell, pawn.CurJob.verbToUse.verbProps.range) || !Verb.UseAbilityProps.canCastInMelee) { - var getInRangeToil = Toils_Combat.GotoCastPosition(TargetIndex.A, false); + var getInRangeToil = Toils_Combat.GotoCastPosition(TargetIndex.A, TargetIndex.B); yield return getInRangeToil; } @@ -37,23 +38,23 @@ protected override IEnumerable MakeNewToils() Find.Targeter.targetingSource = Verb; } - yield return Toils_Combat.CastVerb(TargetIndex.A, false); + yield return Toils_Combat.CastVerb(TargetIndex.A, TargetIndex.B, canHitNonTargetPawns: false); yield return new Toil { - initAction = delegate + initAction = () => { - if (Verb?.UseAbilityProps?.isViolent == true) + if (Verb.UseAbilityProps.isViolent) { - CheckForAutoAttack(this.pawn); + CheckForAutoAttack(pawn); } }, - defaultCompleteMode = ToilCompleteMode.Instant + defaultCompleteMode = ToilCompleteMode.Instant, }; yield return new Toil { - initAction = delegate { Verb.Ability.PostAbilityAttempt(); }, - defaultCompleteMode = ToilCompleteMode.Instant + initAction = Verb.Ability.PostAbilityAttempt, + defaultCompleteMode = ToilCompleteMode.Instant, }; } @@ -69,11 +70,6 @@ public static void CheckForAutoAttack(Pawn searcher) { return; } -<<<<<<< Updated upstream - bool flag = searcher.story == null || !searcher.WorkTagIsDisabled(WorkTags.Violent); - bool flag2 = searcher.RaceProps.ToolUser && searcher.Faction == Faction.OfPlayer && - !searcher.WorkTagIsDisabled(WorkTags.Firefighting); -======= if (searcher.IsCarryingPawn(null)) { return; @@ -82,30 +78,24 @@ public static void CheckForAutoAttack(Pawn searcher) var flag = searcher.story == null || !searcher.WorkTagIsDisabled(WorkTags.Violent); var flag2 = searcher.RaceProps.ToolUser && searcher.Faction == Faction.OfPlayer && !searcher.WorkTagIsDisabled(WorkTags.Firefighting); ->>>>>>> Stashed changes if (flag || flag2) { Fire fire = null; - for (int i = 0; i < 9; i++) + for (var i = 0; i < 9; i++) { - IntVec3 c = searcher.Position + GenAdj.AdjacentCellsAndInside[i]; + var c = searcher.Position + GenAdj.AdjacentCellsAndInside[i]; if (c.InBounds(searcher.Map)) { - List thingList = c.GetThingList(searcher.MapHeld); - for (int j = 0; j < thingList.Count; j++) + var thingList = c.GetThingList(searcher.MapHeld); + for (var j = 0; j < thingList.Count; j++) { if (flag) { -<<<<<<< Updated upstream - Pawn pawn = thingList[j] as Pawn; - if (pawn != null && !pawn.Downed && searcher.HostileTo(pawn)) -======= if (thingList[j] is Pawn pawn && !pawn.Downed && searcher.HostileTo(pawn) && !searcher.ThreatDisabledBecauseNonAggressiveRoamer(pawn) && GenHostility.IsActiveThreatTo(pawn,searcher.Faction)) ->>>>>>> Stashed changes { searcher.meleeVerbs.TryMeleeAttack(pawn, null, false); //this.collideWithPawns = true; @@ -114,18 +104,11 @@ public static void CheckForAutoAttack(Pawn searcher) } if (flag2) { -<<<<<<< Updated upstream - Fire fire2 = thingList[j] as Fire; - if (fire2 != null && (fire == null || fire2.fireSize < fire.fireSize || i == 8) && - (fire2.parent == null || fire2.parent != searcher)) - { -======= if (thingList[j] is Fire fire2 && fire2 != null && (fire == null || fire2.fireSize < fire.fireSize || i == 8) && (fire2.parent == null || fire2.parent != searcher)) { ->>>>>>> Stashed changes fire = fire2; } } @@ -140,36 +123,26 @@ public static void CheckForAutoAttack(Pawn searcher) if (flag && searcher.Faction != null && (searcher.drafter == null || searcher.drafter.FireAtWill)) { - bool allowManualCastWeapons = !searcher.IsColonist; - Verb verb = searcher.TryGetAttackVerb(null, allowManualCastWeapons); + var allowManualCastWeapons = !searcher.IsColonist; + var verb = searcher.TryGetAttackVerb(null, allowManualCastWeapons); if (verb != null && !verb.verbProps.IsMeleeAttack) { -<<<<<<< Updated upstream - TargetScanFlags targetScanFlags = TargetScanFlags.NeedLOSToPawns | TargetScanFlags.NeedLOSToNonPawns | - TargetScanFlags.NeedThreat; - if (verb.IsIncendiary()) -======= var targetScanFlags = TargetScanFlags.NeedLOSToPawns | TargetScanFlags.NeedLOSToNonPawns | TargetScanFlags.NeedThreat; if (verb.IsIncendiary_Ranged()) ->>>>>>> Stashed changes { targetScanFlags |= TargetScanFlags.NeedNonBurning; } - Thing thing = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(searcher, targetScanFlags, null, + var thing = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(searcher, targetScanFlags, null, verb.verbProps.minRange, verb.verbProps.range); if (thing != null) { searcher.TryStartAttack(thing); -<<<<<<< Updated upstream - return; -======= //this.collideWithPawns = true; ->>>>>>> Stashed changes } } } } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/PawnAbility.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/PawnAbility.cs index 14911ba2..c27b2136 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/PawnAbility.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/PawnAbility.cs @@ -1,7 +1,8 @@ -using System; +//#define DEBUGLOG + +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Diagnostics; using RimWorld; using UnityEngine; using Verse; @@ -9,131 +10,188 @@ namespace AbilityUser { - //public class PawnAbility : ThingWithComps public class PawnAbility : IExposable, IEquatable { - public CompAbilityUser abilityUser; //public for resolving saving / loading issues between versions - private Pawn pawn; - private Texture2D powerButton; - private AbilityDef powerdef; - private int TicksUntilCasting = -1; + // Note: With abilityUser being a public field and AbilityUser being a virtual property, + // the authoritative source for pawn must be AbilityUser, so there's no point having a pawn field. + [Obsolete("Use AbilityUser property instead")] + public CompAbilityUser abilityUser; // public for resolving saving / loading issues between versions + private AbilityDef powerDef; + private int ticksUntilCasting = -1; private Verb_UseAbility verb; + [Conditional("DEBUGLOG")] + private static void DebugMessage(string s) => Log.Message(s); + public PawnAbility() { - //Log.Message("PawnAbility Created: " + this.Def.defName); + DebugMessage($"new PawnAbility()"); } public PawnAbility(CompAbilityUser comp) { - pawn = comp.AbilityUser; + if (comp.Pawn == null) + throw new ArgumentNullException("comp.Pawn cannot be null"); +#pragma warning disable CS0618 // Type or member is obsolete abilityUser = comp; - //Log.Message("PawnAbility Created: " + this.Def.defName); + DebugMessage($"new PawnAbility({comp}) => abilityUser={abilityUser}"); +#pragma warning restore CS0618 // Type or member is obsolete + } + + internal void Initialize(CompAbilityUser abilityUser, AbilityDef powerDef, int ticksUntilCasting) + { + if (abilityUser.Pawn == null) + throw new ArgumentNullException("comp.Pawn cannot be null"); + DebugMessage($"PawnAbility.Initialize({this}, {abilityUser}, {powerDef}, {ticksUntilCasting})"); +#pragma warning disable CS0618 // Type or member is obsolete + this.abilityUser = abilityUser; +#pragma warning restore CS0618 // Type or member is obsolete + this.powerDef = powerDef; + this.ticksUntilCasting = ticksUntilCasting; } public PawnAbility(AbilityData data) { - pawn = data.Pawn; - abilityUser = data.Pawn.AllComps.FirstOrDefault(x => x.GetType() == data.AbilityClass) as CompAbilityUser; - //Log.Message("PawnAbility Created: " + this.Def.defName); + var pawn = data.Pawn; + if (pawn == null) + throw new ArgumentNullException("data.Pawn cannot be null"); +#pragma warning disable CS0618 // Type or member is obsolete + abilityUser = pawn.GetExactCompAbilityUser(data.AbilityClass); + DebugMessage($"new PawnAbility{data} => abilityUser={abilityUser}"); +#pragma warning restore CS0618 // Type or member is obsolete } + [Obsolete("This only works reliably when there's a single CompAbilityUser")] public PawnAbility(Pawn user, AbilityDef pdef) { - pawn = user; - powerdef = pdef; - powerButton = pdef.uiIcon; - //Log.Message("PawnAbility Created: " + this.Def.defName); + if (user == null) + throw new ArgumentNullException("user cannot be null"); + if (pdef == null) + throw new ArgumentNullException("pdef cannot be null"); + abilityUser = user.GetCompAbilityUser(); + powerDef = pdef; + DebugMessage($"new PawnAbility({user}, {pdef}) => abilityUser={abilityUser}"); } + // Note: Since this is virtual, the AbilityUser implementation isn't guaranteed to use abilityUser field, + // but we still set abilityUser in other places in case this implementation is used. public virtual CompAbilityUser AbilityUser { - get +#pragma warning disable CS0618 // Type or member is obsolete + get => abilityUser; + set { - if (abilityUser == null) - abilityUser = (CompAbilityUser) pawn.AllComps.FirstOrDefault(x => x is CompAbilityUser); - return abilityUser; + if (abilityUser != value) + { + abilityUser = value ?? throw new ArgumentNullException("AbilityUser cannot be set to null"); + verb = null; + } } +#pragma warning restore CS0618 // Type or member is obsolete } public Pawn Pawn { - get => pawn; - set => pawn = value; + get => AbilityUser?.Pawn; // can be null during initialization, but is assumed non-null afterwards + set + { + if (value == null) + throw new ArgumentNullException("Pawn cannot be null"); + var abilityUser = AbilityUser; + if (abilityUser == null) + { + Log.ErrorOnce("PawnAbility.AbilityUser is unexpectedly null while setting Pawn - " + + "defaulting it to Pawn's first CompAbilityUser", 601945744); +#pragma warning disable CS0618 // Type or member is obsolete + AbilityUser = value.GetCompAbilityUser(); +#pragma warning restore CS0618 // Type or member is obsolete + } + else if (abilityUser.Pawn != value) + { + DebugMessage($"PawnAbility.set_Pawn({this}, {value}): abilityUser={AbilityUser} => " + + value.GetExactCompAbilityUser(abilityUser.GetType())); + AbilityUser = value.GetExactCompAbilityUser(abilityUser.GetType()); + } + } } public AbilityDef Def { - get => powerdef; - set => powerdef = value; - } - - public List Comps { get; } = new List(); - - public Texture2D PowerButton - { - get + get => powerDef; // can be null during initialization, but is assumed to be non-null afterwards + set { - if (powerButton == null) - powerButton = powerdef.uiIcon; - return powerButton; + if (powerDef != value) + { + powerDef = value ?? throw new ArgumentNullException("Def cannot be set to null"); + verb = null; + } } } + // XXX: This doesn't seem to be used. Lazy-init to avoid unnecessary List construction cost. + private List comps; + public List Comps => comps ??= new List(); + + public Texture2D PowerButton => powerDef.uiIcon; + public int CooldownTicksLeft { - get => TicksUntilCasting; - set => TicksUntilCasting = value; - } //Log.Message(value.ToString()); } } + get => ticksUntilCasting; + set => ticksUntilCasting = value; + } public virtual void Notify_AbilityFailed(bool refund) { - AbilityUser.AbilityUser.jobs.StopAll(); + Pawn.jobs.StopAll(); if (refund) CooldownTicksLeft = -1; } - public int MaxCastingTicks => (int) (powerdef.MainVerb.SecondsToRecharge * GenTicks.TicksPerRealSecond); + public int MaxCastingTicks => (int)(powerDef.MainVerb.SecondsToRecharge * GenTicks.TicksPerRealSecond); public Verb_UseAbility Verb { get { if (verb == null) + InitVerb(Pawn); + else { - var newVerb = (Verb_UseAbility) Activator.CreateInstance(powerdef.MainVerb.verbClass); - newVerb.caster = AbilityUser.AbilityUser; - newVerb.Ability = this; - newVerb.verbProps = powerdef.MainVerb; - verb = newVerb; + var pawn = Pawn; + if (verb.caster != pawn) + InitVerb(pawn); } return verb; } } - - //Added on 12/3/17 to prevent hash errors. - - public bool Equals(PawnAbility other) + private void InitVerb(Pawn pawn) { - if (other.GetUniqueLoadID() == GetUniqueLoadID()) return true; - return false; + var newVerb = (Verb_UseAbility)Activator.CreateInstance(powerDef.MainVerb.verbClass); + newVerb.caster = pawn; + newVerb.Ability = this; + newVerb.verbProps = powerDef.MainVerb; + DebugMessage($"PawnAbility.InitVerb({this}, {pawn}) => {newVerb}"); + verb = newVerb; } public void ExposeData() { - //base.ExposeData(); - Scribe_Values.Look(ref TicksUntilCasting, "pawnAbilityTicksUntilcasting", -1); - Scribe_References.Look(ref pawn, "pawnAbilityPawn"); - Scribe_Defs.Look(ref powerdef, "pawnAbilityPowerDef"); + Scribe_Values.Look(ref ticksUntilCasting, "pawnAbilityTicksUntilcasting", -1); + // pawnAbilityPawn is no longer necessary, but for backwards compatibility, still save it. + if (Scribe.mode == LoadSaveMode.Saving) + { + var pawn = Pawn; + Scribe_References.Look(ref pawn, "pawnAbilityPawn"); + } + Scribe_Defs.Look(ref powerDef, "pawnAbilityPowerDef"); + DebugMessage($"PawnAbility.ExposeData({this}) for mode={Scribe.mode}"); } public void Tick() { - if (powerdef?.PassiveProps?.Worker is PassiveEffectWorker w) - w.Tick(abilityUser); - if (Verb != null) - Verb.VerbTick(); + powerDef.PassiveProps?.Worker?.Tick(AbilityUser); + Verb.VerbTick(); if (CooldownTicksLeft > -1 && !Find.TickManager.Paused) CooldownTicksLeft--; } @@ -151,44 +209,40 @@ public virtual bool CanOverpowerTarget(AbilityContext context, LocalTargetInfo t public virtual Job UseAbility(AbilityContext context, LocalTargetInfo target) { - var reason = ""; - if (target.Thing != null && !CanOverpowerTarget(context, target, out reason)) + if (target.Thing != null && !CanOverpowerTarget(context, target, out var _)) return null; var job = GetJob(context, target); if (context == AbilityContext.Player) - pawn.jobs.TryTakeOrderedJob(job); + Pawn.jobs.TryTakeOrderedJob(job); return job; } public virtual Job GetJob(AbilityContext context, LocalTargetInfo target) { - Job job; - job = powerdef.GetJob(verb.UseAbilityProps.AbilityTargetCategory, target); + var verb = Verb; + var job = powerDef.GetJob(verb.UseAbilityProps.AbilityTargetCategory, target); job.playerForced = true; job.verbToUse = verb; job.count = context == AbilityContext.Player ? 1 : 0; //Count 1 for Player : 0 for AI - if (target != null) - if (target.Thing is Pawn pawn2) - job.killIncappedTarget = pawn2.Downed; + if (target.Thing is Pawn targetPawn) + job.killIncappedTarget = targetPawn.Downed; return job; } public bool TryCastAbility(AbilityContext context, LocalTargetInfo target) { //Can our body cast? - var reason = ""; - if (!CanCastPowerCheck(context, out reason)) + if (!CanCastPowerCheck(context, out var _)) return false; - + //If we're a player, let's target. if (context == AbilityContext.Player) { + var verb = Verb; + var casterPawn = verb.CasterPawn; var targeter = Find.Targeter; - if (verb.CasterIsPawn && targeter.targetingSource != null ) - // Tad : Commented out for now. - // && targeter.targetingSource.targetParams .verbProps == verb.verbProps) + if (targeter.targetingSource?.GetVerb?.verbProps == verb.verbProps) { - var casterPawn = verb.CasterPawn; if (!targeter.IsPawnTargeting(casterPawn)) targeter.targetingSourceAdditionalPawns.Add(casterPawn); } @@ -201,69 +255,56 @@ public bool TryCastAbility(AbilityContext context, LocalTargetInfo target) return true; } + // This method and CanCastPowerCheck are based off VerbTracker.CreateVerbTargetCommand. public Command_PawnAbility GetGizmo() { - var command_CastPower = new Command_PawnAbility(abilityUser, this, CooldownTicksLeft) + var verb = Verb; + var verbProps = verb.UseAbilityProps; + var command_CastPower = new Command_PawnAbility(AbilityUser, this, CooldownTicksLeft) { - verb = Verb, - defaultLabel = powerdef.LabelCap + verb = verb, + defaultLabel = powerDef.LabelCap, + defaultDesc = powerDef.GetDescription() + "\n" + PostAbilityVerbCompDesc(verbProps) + "\n", + targetingParams = powerDef.MainVerb.targetParams, + icon = powerDef.uiIcon, + action = target => TryCastAbility(AbilityContext.Player, + GenUI.TargetsAt(UI.MouseMapPosition(), verbProps.targetParams).FirstOrFallback(target)), }; - command_CastPower.curTicks = CooldownTicksLeft; - - //GetDesc - var s = new StringBuilder(); - s.AppendLine(powerdef.GetDescription()); - s.AppendLine(PostAbilityVerbCompDesc(Verb.UseAbilityProps)); - command_CastPower.defaultDesc = s.ToString(); - s = null; - command_CastPower.targetingParams = powerdef.MainVerb.targetParams; - command_CastPower.icon = powerdef.uiIcon; - command_CastPower.action = delegate(Thing target) - { - var tInfo = GenUI.TargetsAt(UI.MouseMapPosition(), Verb.verbProps.targetParams, false)?.First() ?? - target; - TryCastAbility(AbilityContext.Player, tInfo); - }; - - var reason = ""; - if (!CanCastPowerCheck(AbilityContext.Player, out reason)) + if (!CanCastPowerCheck(AbilityContext.Player, out var reason)) command_CastPower.Disable(reason); return command_CastPower; } public virtual bool CanCastPowerCheck(AbilityContext context, out string reason) { - reason = ""; - - if (context == AbilityContext.Player && Verb.caster.Faction != Faction.OfPlayer) + var casterPawn = verb.CasterPawn; + if (context == AbilityContext.Player && casterPawn.Faction != Faction.OfPlayer) { reason = "CannotOrderNonControlled".Translate(); return false; } - if (Verb.CasterPawn.WorkTagIsDisabled(WorkTags.Violent) && - powerdef.MainVerb.isViolent) + if (powerDef.MainVerb.isViolent && casterPawn.WorkTagIsDisabled(WorkTags.Violent)) { - reason = "IsIncapableOfViolence".Translate(Verb.CasterPawn.Name.ToStringShort); + reason = "IsIncapableOfViolence".Translate(casterPawn.LabelShort, casterPawn); return false; } if (CooldownTicksLeft > 0) { - reason = "AU_PawnAbilityRecharging".Translate(Verb.CasterPawn.Name.ToStringShort); + reason = "AU_PawnAbilityRecharging".Translate(casterPawn.LabelShort); return false; } - //else if (!Verb.CasterPawn.drafter.Drafted) + //else if (!casterPawn.drafter.Drafted) //{ - // reason = "IsNotDrafted".Translate(new object[] - // { - // Verb.CasterPawn.Name.ToStringShort - // }); + // reason = "IsNotDrafted".Translate(casterPawn.LabelShort, casterPawn); //} - - return true; + else + { + reason = ""; + return true; + } } - public virtual void PostAbilityAttempt() { CooldownTicksLeft = MaxCastingTicks; @@ -279,25 +320,37 @@ public virtual string PostAbilityVerbDesc() return ""; } + [Obsolete("Formerly used in Equals implementation - no longer serves any purpose")] public static string GenerateID(Pawn pawn, AbilityDef def) { return def.defName + "_" + pawn.GetUniqueLoadID(); } + [Obsolete("Formerly used in Equals implementation - no longer serves any purpose")] public string GetUniqueLoadID() { return GenerateID(Pawn, Def); } + public override bool Equals(object obj) + { + return Equals(obj as PawnAbility); + } + + public bool Equals(PawnAbility other) + { + static bool DefEquals(Def a, Def b) => a == b || a != null && b != null && a.defName == b.defName; + return other != null && DefEquals(Def, other.Def) && Equals(AbilityUser, other.AbilityUser); + } + public override int GetHashCode() { - var num = 66; - num = Gen.HashCombineInt(num, Def.shortHash); - if (Pawn != null) - num = Gen.HashCombineInt(num, Pawn.thingIDNumber); - if (Verb.AbilityProjectileDef != null) - num = Gen.HashCombineInt(num, Verb.AbilityProjectileDef.shortHash); - return num; + return Gen.HashCombineInt(Gen.HashCombineInt(66, Def?.shortHash ?? 0), AbilityUser?.GetHashCode() ?? 0); + } + + public override string ToString() + { + return $"{GetType().Name}(Pawn={Pawn}, Def={Def}, CooldownTicksLeft={CooldownTicksLeft})"; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_Ability.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_Ability.cs index 23d69e42..b2864e64 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_Ability.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_Ability.cs @@ -13,7 +13,7 @@ public Vector3 ProjectileDrawPos { if (selectedTarget != null) return selectedTarget.DrawPos; - if (targetVec != null) + if (targetVec != default) return targetVec; return ExactPosition; } @@ -21,18 +21,13 @@ public Vector3 ProjectileDrawPos public override void Draw() { - if (selectedTarget != null || targetVec != null) + if (selectedTarget != null || targetVec != default) { - var vector = ProjectileDrawPos; - var distance = destination - origin; - var curpos = destination - Position.ToVector3(); - var angle = 0f; - var mat = Graphic.MatSingle; + var drawPos = ProjectileDrawPos; + drawPos.y = 3; var s = new Vector3(2.5f, 1f, 2.5f); - var matrix = default(Matrix4x4); - vector.y = 3; - matrix.SetTRS(vector, Quaternion.AngleAxis(angle, Vector3.up), s); - Graphics.DrawMesh(MeshPool.plane10, matrix, mat, 0); + var matrix = Matrix4x4.TRS(drawPos, Quaternion.AngleAxis(0f, Vector3.up), s); + Graphics.DrawMesh(MeshPool.plane10, matrix, Graphic.MatSingle, 0); } else { @@ -46,10 +41,10 @@ public override void Impact_Override(Thing hitThing) base.Impact_Override(hitThing); if (hitThing != null) { - var damageAmountBase = def.projectile.GetDamageAmount(1f); - var equipmentDef = this.equipmentDef; - var dinfo = new DamageInfo(def.projectile.damageDef, damageAmountBase, this.def.projectile.GetArmorPenetration(1f), ExactRotation.eulerAngles.y, - launcher, null, equipmentDef); + var dinfo = new DamageInfo(def.projectile.damageDef, def.projectile.GetDamageAmount(1f), + def.projectile.GetArmorPenetration(1f), ExactRotation.eulerAngles.y, + launcher, weapon: equipmentDef); + //Log.Message($"Projectile_Ability.Impact_Override({this}, {hitThing}) dinfo={dinfo}"); hitThing.TakeDamage(dinfo); PostImpactEffects(hitThing); } @@ -64,14 +59,14 @@ public virtual bool IsInIgnoreHediffList(Hediff hediff) if (hediff != null) if (hediff.def != null) { - var compAbility = Caster.TryGetComp(); - if (compAbility != null) - if (compAbility.IgnoredHediffs() != null) - if (compAbility.IgnoredHediffs().Contains(hediff.def)) + foreach (var abilityUser in Caster.GetCompAbilityUsers()) + { + if (abilityUser.IgnoredHediffs() != null) + if (abilityUser.IgnoredHediffs().Contains(hediff.def)) return true; + } } - return false; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_AbilityBase.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_AbilityBase.cs index 15f9fa81..5a58c95c 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_AbilityBase.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_AbilityBase.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; -using RimWorld; +using System.Collections.Generic; using UnityEngine; using Verse; -using Verse.AI.Group; using Verse.Sound; namespace AbilityUser @@ -20,16 +17,7 @@ public class Projectile_AbilityBase : Projectile public Vector3 targetVec; public Pawn Caster => launcher as Pawn; - public ProjectileDef_Ability Mpdef - { - get - { - ProjectileDef_Ability mpdef = null; - if (def is ProjectileDef_Ability) - mpdef = def as ProjectileDef_Ability; - return mpdef; - } - } + public ProjectileDef_Ability Mpdef => def as ProjectileDef_Ability; public override void ExposeData() { @@ -43,7 +31,7 @@ public override void ExposeData() // Verse.Projectile public override void Tick() { - //Log.Message("Tick"); + //Log.Message($"Projectile_AbilityBase.Tick({this})"); if (landed) return; ticksToImpact--; @@ -64,7 +52,7 @@ public override void Tick() /// protected void ApplyDamage(Thing hitThing) { - //Log.Message("ApplyDamage"); + //Log.Message($"Projectile_AbilityBase.ApplyDamage({this}, {hitThing})"); if (hitThing != null) Impact(hitThing); else @@ -80,27 +68,22 @@ protected void ImpactSomething() if (def.projectile.flyOverhead) { var roofDef = Map.roofGrid.RoofAt(DestinationCell); - if (roofDef != null && roofDef.isThickRoof) - if (def.projectile != null) - if (def.projectile.soundHitThickRoof != null) - { - var info = SoundInfo.InMap(new TargetInfo(DestinationCell, Map, false), - MaintenanceType.None); - def.projectile.soundHitThickRoof.PlayOneShot(info); - return; - } + if (roofDef != null && roofDef.isThickRoof && + // TODO: Are these null checks necessary? Projectile.ImpactSomething doesn't have it. + def.projectile != null && def.projectile.soundHitThickRoof != null) + { + def.projectile.soundHitThickRoof.PlayOneShot(SoundInfo.InMap(new TargetInfo(DestinationCell, Map))); + return; + } } // Impact the initial targeted pawn. if (intendedTarget != null) { - if (intendedTarget.Thing is Pawn pawn && pawn.Downed && (origin - destination).magnitude > 5f && - Rand.Value < 0.2f) - { + if (intendedTarget.Thing is Pawn pawn && pawn.Downed && (origin - destination).magnitude > 5f && Rand.Value < 0.2f) Impact(null); - return; - } - Impact(intendedTarget.Thing); + else + Impact(intendedTarget.Thing); } else { @@ -109,16 +92,20 @@ protected void ImpactSomething() if (thing != null) { Impact(thing); - return; } - // Impact any cover object. - foreach (var current in Map.thingGrid.ThingsAt(DestinationCell)) - if (current.def.fillPercent > 0f || current.def.passability != Traversability.Standable) + else + { + // Impact any cover object. + foreach (var current in Map.thingGrid.ThingsAt(DestinationCell)) { - Impact(current); - return; + if (current.def.fillPercent > 0f || current.def.passability != Traversability.Standable) + { + Impact(current); + return; + } } - Impact(null); + Impact(null); + } } } @@ -130,21 +117,14 @@ public virtual bool CanOverpower(Pawn caster, Thing hitThing) public void ApplyHediffsAndMentalStates(Pawn victim, Pawn caster, List localApplyMentalStates, AbilityDef localAbilityDef) { - try - { - //Log.Message("ApplyHediffsAndMentalStates"); - AbilityEffectUtility.ApplyMentalStates(victim, caster, localApplyMentalStates, localAbilityDef, this); - AbilityEffectUtility.ApplyHediffs(victim, caster, localApplyHediffs, null); - } - catch (NullReferenceException e) - { - Log.Message(e.ToString()); - } + //Log.Message($"Projectile_AbilityBase.ApplyHediffsAndMentalStates({this}, ...)"); + AbilityEffectUtility.ApplyMentalStates(victim, caster, localApplyMentalStates, localAbilityDef, this); + AbilityEffectUtility.ApplyHediffs(victim, caster, localApplyHediffs, null); } public virtual void Impact_Override(Thing hitThing) { - //Log.Message("ImpactOverride"); + //Log.Message($"Projectile_AbilityBase.Impact_Override({this}, {hitThing})"); if (hitThing != null) if (hitThing is Pawn victim) if (Mpdef != null) @@ -158,31 +138,33 @@ public virtual void Impact_Override(Thing hitThing) ApplyHediffsAndMentalStates(Caster, Caster, localApplyMentalStates, localAbilityDef); } - public void Launch(Thing launcher, AbilityDef abilityDef, Vector3 origin, LocalTargetInfo targ, - ProjectileHitFlags hitFlags, Thing equipment = null, List applyHediffs = null, + public void Launch(Thing launcher, AbilityDef abilityDef, Vector3 origin, LocalTargetInfo targ, ProjectileHitFlags hitFlags, + bool preventFriendlyFire = false, Thing equipment = null, List applyHediffs = null, List applyMentalStates = null, List spawnThings = null) { - //Log.Message("Projectile_AbilityBase"); + //Log.Message($"Projectile_AbilityBase.Launch({this}, ...)"); localApplyHediffs = applyHediffs; localApplyMentalStates = applyMentalStates; localSpawnThings = spawnThings; localAbilityDef = abilityDef; - base.Launch(launcher, targ, targ, hitFlags, equipment); //TODO + Launch(launcher, targ, targ, hitFlags, preventFriendlyFire, equipment); //TODO } protected override void Impact(Thing hitThing, bool blockedByShield = false) { - //Log.Message("Impact"); + //Log.Message($"Projectile_AbilityBase.Impact({this}, {hitThing})"); Impact_Override(hitThing); if (hitThing != null) - if (extraDamages != null && extraDamages.Count > 0) + if (extraDamages != null) foreach (var damage in extraDamages) { - var extraDinfo = new DamageInfo(damage.damageDef, damage.damage, this.def.projectile.GetArmorPenetration(1f), ExactRotation.eulerAngles.y, - launcher, null, equipmentDef); + var extraDinfo = new DamageInfo(damage.damageDef, damage.damage, + def.projectile.GetArmorPenetration(1f), ExactRotation.eulerAngles.y, + launcher, weapon: equipmentDef); + //Log.Message($"Projectile_AbilityBase.Impact({this}, {hitThing}) extraDinfo={extraDinfo}"); hitThing.TakeDamage(extraDinfo); } base.Impact(hitThing, blockedByShield); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_AbilityLaser.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_AbilityLaser.cs index a40fc93c..188d7c40 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_AbilityLaser.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/Projectile_AbilityLaser.cs @@ -9,7 +9,7 @@ public class Projectile_AbilityLaser : Projectile_AbilityBase { public bool canStartFire; public float drawingIntensity; - public Matrix4x4 drawingMatrix = default(Matrix4x4); + public Matrix4x4 drawingMatrix; public Vector3 drawingPosition; public Vector3 drawingScale; public Material drawingTexture; @@ -63,7 +63,7 @@ public void GetParametersFromXml() public override void ExposeData() { base.ExposeData(); - Scribe_Values.Look(ref tickCounter, "tickCounter", 0); + Scribe_Values.Look(ref tickCounter, nameof(tickCounter)); if (Scribe.mode == LoadSaveMode.PostLoadInit) GetParametersFromXml(); @@ -81,7 +81,7 @@ public override void Tick() { if (tickCounter == 0) { - this.hitThing = intendedTarget.Thing; + hitThing = intendedTarget.Thing; GetParametersFromXml(); PerformPreFiringTreatment(); } @@ -103,19 +103,20 @@ public override void Tick() GetPostFiringDrawingParameters(); } if (tickCounter == preFiringDuration + postFiringDuration && !Destroyed) - Destroy(DestroyMode.Vanish); + Destroy(); if (launcher != null) if (launcher is Pawn) { var launcherPawn = launcher as Pawn; if (launcherPawn.Dead && !Destroyed) - Destroy(DestroyMode.Vanish); + Destroy(); } tickCounter++; } catch { - if (!Destroyed) Destroy(DestroyMode.Vanish); + if (!Destroyed) + Destroy(); } } @@ -149,7 +150,7 @@ public virtual void GetPostFiringDrawingParameters() if (postFiringDuration != 0) drawingIntensity = postFiringInitialIntensity + (postFiringFinalIntensity - postFiringInitialIntensity) * - ((tickCounter - (float) preFiringDuration) / postFiringDuration); + ((tickCounter - (float)preFiringDuration) / postFiringDuration); } /// @@ -159,17 +160,16 @@ protected void DetermineImpactExactPosition() { // We split the trajectory into small segments of approximatively 1 cell size. var trajectory = destination - origin; - var numberOfSegments = (int) trajectory.magnitude; + var numberOfSegments = (int)trajectory.magnitude; var trajectorySegment = trajectory / trajectory.magnitude; var temporaryDestination = origin; // Last valid tested position in case of an out of boundaries shot. var exactTestedPosition = origin; - var testedPosition = exactTestedPosition.ToIntVec3(); for (var segmentIndex = 1; segmentIndex <= numberOfSegments; segmentIndex++) { exactTestedPosition += trajectorySegment; - testedPosition = exactTestedPosition.ToIntVec3(); + var testedPosition = exactTestedPosition.ToIntVec3(); if (!exactTestedPosition.InBounds(Map)) { @@ -231,7 +231,7 @@ protected void DetermineImpactExactPosition() } temporaryDestination = exactTestedPosition; - if (hitThing != null) Log.Message("Hit thig = " + hitThing.ToString()); + //if (hitThing != null) Log.Message("Hit thing = " + hitThing.ToString()); } } @@ -256,9 +256,10 @@ public override void Impact_Override(Thing hitThing) //Log.Message("Hit thing found: " + hitThing.ToString() ); var damageAmountBase = def.projectile.GetDamageAmount(1f); - var dinfo = new DamageInfo(def.projectile.damageDef, damageAmountBase, this.def.projectile.GetArmorPenetration(1f), ExactRotation.eulerAngles.y, - launcher, null, equipmentDef, DamageInfo.SourceCategory.ThingOrUnknown, hitThing); - BattleLogEntry_RangedImpact battleLogEntry_RangedImpact = new BattleLogEntry_RangedImpact(this.launcher, hitThing, this.intendedTarget.Thing, this.launcher.def, this.def, this.targetCoverDef); + var dinfo = new DamageInfo(def.projectile.damageDef, damageAmountBase, + def.projectile.GetArmorPenetration(1f), ExactRotation.eulerAngles.y, + launcher, weapon: equipmentDef, intendedTarget: hitThing); + var battleLogEntry_RangedImpact = new BattleLogEntry_RangedImpact(launcher, hitThing, intendedTarget.Thing, launcher.def, def, targetCoverDef); Find.BattleLog.Add(battleLogEntry_RangedImpact); hitThing.TakeDamage(dinfo).AssociateWithLog(battleLogEntry_RangedImpact); //Log.Message("Hit thing taken damage: " + dinfo.Amount.ToString() + " " + dinfo.Def.label); @@ -269,21 +270,20 @@ public override void Impact_Override(Thing hitThing) if (hitThing is Pawn pawn) { PostImpactEffects(launcher as Pawn, pawn); - MoteMaker.ThrowMicroSparks(destination, Map); - MoteMaker.MakeStaticMote(destination, Map, ThingDefOf.Mote_ShotHit_Dirt, 1f); + FleckMaker.ThrowMicroSparks(destination, Map); + FleckMaker.Static(destination, Map, FleckDefOf.ShotHit_Dirt); } } else { - var info = SoundInfo.InMap(new TargetInfo(Position, Map, false), MaintenanceType.None); - SoundDefOf.BulletImpact_Ground.PlayOneShot(info); - MoteMaker.MakeStaticMote(ExactPosition, Map, ThingDefOf.Mote_ShotHit_Dirt, 1f); - MoteMaker.ThrowMicroSparks(ExactPosition, Map); + SoundDefOf.BulletImpact_Ground.PlayOneShot(SoundInfo.InMap(new TargetInfo(Position, Map))); + FleckMaker.Static(ExactPosition, Map, FleckDefOf.ShotHit_Dirt); + FleckMaker.ThrowMicroSparks(ExactPosition, Map); } - var pawn1 = hitThing as Pawn; - if (pawn1?.stances != null && pawn1.BodySize <= this.def.projectile.stoppingPower + 0.001f) + var hitPawn = hitThing as Pawn; + if (hitPawn?.stances != null && hitPawn.BodySize <= def.projectile.stoppingPower + 0.001f) { - pawn1.stances.StaggerFor(95); + hitPawn.stances.StaggerFor(95); } } @@ -306,4 +306,4 @@ public override void Draw() FadedMaterialPool.FadedVersionOf(drawingTexture, drawingIntensity), 0); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/Verb_UseAbility.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/Verb_UseAbility.cs index ec844cc4..b0404a70 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/Verb_UseAbility.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/Verb_UseAbility.cs @@ -1,6 +1,9 @@ -using System; +//#define DEBUGLOG + +using System; using System.Collections.Generic; -using System.Linq; +using System.Diagnostics; +using HarmonyLib; using RimWorld; using Verse; using Verse.Sound; @@ -10,55 +13,74 @@ namespace AbilityUser public class Verb_UseAbility : Verb_LaunchProjectile { public List TargetsAoE = new List(); - public Action timeSavingActionVariable = null; + public Action timeSavingActionVariable = null; public PawnAbility Ability { get; set; } = null; - public VerbProperties_Ability UseAbilityProps => (VerbProperties_Ability) verbProps; + public VerbProperties_Ability UseAbilityProps => (VerbProperties_Ability)verbProps; public ProjectileDef_Ability AbilityProjectileDef => UseAbilityProps.defaultProjectile as ProjectileDef_Ability; - public CompAbilityUser AbilityUserComp => CasterPawn.TryGetComp(); + public CompAbilityUser AbilityUserComp + { + get + { + var abilityUser = Ability?.AbilityUser; + if (abilityUser == null) + { + Log.ErrorOnce("Verb_UseAbility.Ability?.AbilityUser is unexpectedly null - " + + "defaulting Verb_UseAbility.AbilityUserComp to CasterPawn's first CompAbilityUser", 21938760); +#pragma warning disable CS0618 // Type or member is obsolete + abilityUser = CasterPawn.GetCompAbilityUser(); +#pragma warning restore CS0618 // Type or member is obsolete + } + return abilityUser; + } + } protected override int ShotsPerBurst => verbProps.burstShotCount; + [Conditional("DEBUGLOG")] + private static void DebugMessage(string s) => Log.Message(s); + public override float HighlightFieldRadiusAroundTarget(out bool needLOSToCenter) { needLOSToCenter = true; - var result = verbProps?.defaultProjectile?.projectile?.explosionRadius ?? 1; - if (UseAbilityProps.abilityDef.MainVerb.TargetAoEProperties != null) - if (UseAbilityProps.abilityDef.MainVerb.TargetAoEProperties.showRangeOnSelect) - result = UseAbilityProps.abilityDef.MainVerb.TargetAoEProperties.range; - return result; + var targetAoEProperties = UseAbilityProps.abilityDef.MainVerb.TargetAoEProperties; + return targetAoEProperties?.showRangeOnSelect ?? false + ? targetAoEProperties.range + : verbProps.defaultProjectile?.projectile?.explosionRadius ?? 1; } protected virtual void UpdateTargets() { TargetsAoE.Clear(); - if (UseAbilityProps.AbilityTargetCategory == AbilityTargetCategory.TargetAoE) + var props = UseAbilityProps; + if (props.AbilityTargetCategory == AbilityTargetCategory.TargetAoE) { //Log.Message("AoE Called"); - if (UseAbilityProps.TargetAoEProperties == null) + var targetAoEProperties = props.TargetAoEProperties; + if (targetAoEProperties == null) Log.Error("Tried to Cast AoE-Ability without defining a target class"); - var targets = new List(); + List targets; //Handle TargetAoE start location. var aoeStartPosition = caster.PositionHeld; - if (!UseAbilityProps.TargetAoEProperties.startsFromCaster) + if (!targetAoEProperties.startsFromCaster) aoeStartPosition = currentTarget.Cell; //Handle friendly fire targets. - if (!UseAbilityProps.TargetAoEProperties.friendlyFire) + if (!targetAoEProperties.friendlyFire) { - targets = caster.Map.listerThings.AllThings.Where(x => - x.Position.InHorDistOf(aoeStartPosition, UseAbilityProps.TargetAoEProperties.range) && - UseAbilityProps.TargetAoEProperties.targetClass.IsAssignableFrom(x.GetType()) && - x.Faction.HostileTo(Faction.OfPlayer)).ToList(); + targets = caster.Map.listerThings.AllThings.FindAll(x => + x.Position.InHorDistOf(aoeStartPosition, targetAoEProperties.range) && + targetAoEProperties.targetClass.IsAssignableFrom(x.GetType()) && + x.Faction.HostileTo(Faction.OfPlayer)); } - else if (UseAbilityProps.TargetAoEProperties.targetClass == typeof(Plant) || - UseAbilityProps.TargetAoEProperties.targetClass == typeof(Building)) + else if (targetAoEProperties.targetClass == typeof(Plant) || + targetAoEProperties.targetClass == typeof(Building)) { - targets = caster.Map.listerThings.AllThings.Where(x => - x.Position.InHorDistOf(aoeStartPosition, UseAbilityProps.TargetAoEProperties.range) && - UseAbilityProps.TargetAoEProperties.targetClass.IsAssignableFrom(x.GetType())).ToList(); + targets = caster.Map.listerThings.AllThings.FindAll(x => + x.Position.InHorDistOf(aoeStartPosition, targetAoEProperties.range) && + targetAoEProperties.targetClass.IsAssignableFrom(x.GetType())); foreach (var targ in targets) { var tinfo = new LocalTargetInfo(targ); @@ -68,20 +90,19 @@ protected virtual void UpdateTargets() } else { - targets.Clear(); - targets = caster.Map.listerThings.AllThings.Where(x => - x.Position.InHorDistOf(aoeStartPosition, UseAbilityProps.TargetAoEProperties.range) && - UseAbilityProps.TargetAoEProperties.targetClass.IsAssignableFrom(x.GetType()) && - (x.HostileTo(Faction.OfPlayer) || UseAbilityProps.TargetAoEProperties.friendlyFire)).ToList(); + targets = caster.Map.listerThings.AllThings.FindAll(x => + x.Position.InHorDistOf(aoeStartPosition, targetAoEProperties.range) && + targetAoEProperties.targetClass.IsAssignableFrom(x.GetType()) && + (x.HostileTo(Faction.OfPlayer) || targetAoEProperties.friendlyFire)); } - var maxTargets = UseAbilityProps.abilityDef.MainVerb.TargetAoEProperties.maxTargets; - var randTargets = new List(targets.InRandomOrder()); - for (var i = 0; i < maxTargets && i < randTargets.Count(); i++) + var maxTargets = props.abilityDef.MainVerb.TargetAoEProperties.maxTargets; + GenList.Shuffle(targets); + for (var i = 0; i < maxTargets && i < targets.Count; i++) { - var tinfo = new TargetInfo(randTargets[i]); - if (UseAbilityProps.targetParams.CanTarget(tinfo)) - TargetsAoE.Add(new LocalTargetInfo(randTargets[i])); + var tinfo = new TargetInfo(targets[i]); + if (props.targetParams.CanTarget(tinfo)) + TargetsAoE.Add(new LocalTargetInfo(targets[i])); } } else @@ -91,34 +112,9 @@ protected virtual void UpdateTargets() } } - private bool CausesTimeSlowdown(LocalTargetInfo castTarg) - { - if (!verbProps.CausesTimeSlowdown) - { - return false; - } - if (!castTarg.HasThing) - { - return false; - } - Thing thing = castTarg.Thing; - if (thing.def.category != ThingCategory.Pawn && (thing.def.building == null || !thing.def.building.IsTurret)) - { - return false; - } - bool flag = (thing as Pawn)?.Downed ?? false; - if (thing.Faction != Faction.OfPlayer || !caster.HostileTo(Faction.OfPlayer)) - { - if (caster.Faction == Faction.OfPlayer && thing.HostileTo(Faction.OfPlayer)) - { - return !flag; - } - return false; - } - return true; - } - - public bool PreCastShotCheck(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack, bool canHitNonTargetPawns) + // Based off Verb.TryStartCastOn. + public bool PreCastShotCheck(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack = false, + bool canHitNonTargetPawns = true, bool preventFriendlyFire = false) { if (caster == null) { @@ -133,30 +129,31 @@ public bool PreCastShotCheck(LocalTargetInfo castTarg, LocalTargetInfo destTarg, { return false; } - if (CausesTimeSlowdown(castTarg)) + if (causesTimeSlowdown(this, castTarg)) { Find.TickManager.slower.SignalForceNormalSpeed(); } this.surpriseAttack = surpriseAttack; - this.canHitNonTargetPawnsNow = canHitNonTargetPawns; - this.currentTarget = castTarg; - this.currentDestination = destTarg; + canHitNonTargetPawnsNow = canHitNonTargetPawns; + this.preventFriendlyFire = preventFriendlyFire; + currentTarget = castTarg; + currentDestination = destTarg; if (CasterIsPawn && verbProps.warmupTime > 0f) { + var casterPawn = CasterPawn; if (verbProps.requireLineOfSight) { - ShootLine resultingLine; - if (!TryFindShootLineFromTo(caster.Position, castTarg, out resultingLine)) + if (!TryFindShootLineFromTo(casterPawn.Position, castTarg, out var resultingLine)) { Messages.Message("AU_NoLineOfSight".Translate(), MessageTypeDefOf.RejectInput); return false; } - CasterPawn.Drawer.Notify_WarmingCastAlongLine(resultingLine, caster.Position); + casterPawn.Drawer.Notify_WarmingCastAlongLine(resultingLine, casterPawn.Position); } - float statValue = CasterPawn.GetStatValue(StatDefOf.AimingDelayFactor); - int ticks = (verbProps.warmupTime * statValue).SecondsToTicks(); - CasterPawn.stances.SetStance(new Stance_Warmup(ticks, castTarg, this)); + var statValue = casterPawn.GetStatValue(StatDefOf.AimingDelayFactor); + var ticks = (verbProps.warmupTime * statValue).SecondsToTicks(); + casterPawn.stances.SetStance(new Stance_Warmup(ticks, castTarg, this)); } else { @@ -165,14 +162,23 @@ public bool PreCastShotCheck(LocalTargetInfo castTarg, LocalTargetInfo destTarg, return true; } - public bool PreCastShot(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack, bool canHitNonTargetPawns) + // Note: This is an open instance delegate where the first argument is the instance. + private static readonly Func causesTimeSlowdown = + (Func)AccessTools.Method(typeof(Verb), "CausesTimeSlowdown") + .CreateDelegate(typeof(Func)); + + public bool PreCastShot(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack = false, + bool canHitNonTargetPawns = true, bool preventFriendlyFire = false) { - if (PreCastShotCheck(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns)) + var result = PreCastShotCheck(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire); + DebugMessage($"Verb_UseAbility.PreCastShotCheck({this}, castTarg={castTarg}, destTarg={destTarg}, " + + $"surpriseAttack={surpriseAttack}, canHitNonTargetPawns={canHitNonTargetPawns}, " + + $"preventFriendlyFire={preventFriendlyFire}) => {result}"); + if (result == false) { - return true; + Ability.Notify_AbilityFailed(refund: true); } - Ability.Notify_AbilityFailed(true); - return false; + return result; } public virtual void PostCastShot(bool inResult, out bool outResult) @@ -184,77 +190,64 @@ public virtual void PostCastShot(bool inResult, out bool outResult) protected override bool TryCastShot() { - //Log.Message("Cast"); + DebugMessage($"TryCastShot({this})"); var result = false; TargetsAoE.Clear(); UpdateTargets(); - var burstShots = ShotsPerBurst; - if (UseAbilityProps.AbilityTargetCategory != AbilityTargetCategory.TargetAoE && TargetsAoE.Count > 1) + var props = UseAbilityProps; + if (props.AbilityTargetCategory != AbilityTargetCategory.TargetAoE && TargetsAoE.Count > 1) TargetsAoE.RemoveRange(0, TargetsAoE.Count - 1); - if (UseAbilityProps.mustHaveTarget && TargetsAoE.Count == 0) + if (props.mustHaveTarget && TargetsAoE.Count == 0) { Messages.Message("AU_NoTargets".Translate(), MessageTypeDefOf.RejectInput); - Ability.Notify_AbilityFailed(true); + Ability.Notify_AbilityFailed(refund: true); return false; } for (var i = 0; i < TargetsAoE.Count; i++) { - // for (int j = 0; j < burstshots; j++) - // { + //for (var j = 0; j < burstshots; j++) + //{ + var target = TargetsAoE[i]; + DebugMessage($"TryCastShot({this}) target={target} ({target.Thing}), defaultProjectile={verbProps.defaultProjectile}"); if (verbProps.defaultProjectile != null) //ranged attacks WILL have projectiles { - //Log.Message("Yes Projectile"); - var attempt = TryLaunchProjectile(verbProps.defaultProjectile, TargetsAoE[i]); - ////Log.Message(TargetsAoE[i].ToString()); - if (attempt != null) - { - if (attempt == true) result = true; - if (attempt == false) result = false; - } + var attempt = TryLaunchProjectile(verbProps.defaultProjectile, target); + if (attempt.HasValue) + result = attempt.GetValueOrDefault(); } else //melee attacks WON'T have projectiles { - //Log.Message("No Projectile"); - var victim = TargetsAoE[i].Thing; + var victim = target.Thing; if (victim != null) { - //Log.Message("Yes victim"); if (victim is Pawn pawnVictim) { - //Log.Message("Yes victim is pawn"); - AbilityEffectUtility.ApplyMentalStates(pawnVictim, CasterPawn, UseAbilityProps.mentalStatesToApply, UseAbilityProps.abilityDef, null); - AbilityEffectUtility.ApplyHediffs(pawnVictim, CasterPawn, UseAbilityProps.hediffsToApply, null); - AbilityEffectUtility.SpawnSpawnables(UseAbilityProps.thingsToSpawn, pawnVictim, victim.MapHeld, victim.PositionHeld); + var casterPawn = CasterPawn; + AbilityEffectUtility.ApplyMentalStates(pawnVictim, casterPawn, props.mentalStatesToApply, props.abilityDef, null); + AbilityEffectUtility.ApplyHediffs(pawnVictim, casterPawn, props.hediffsToApply, null); + AbilityEffectUtility.SpawnSpawnables(props.thingsToSpawn, pawnVictim, victim.MapHeld, victim.PositionHeld); } } else { - //Log.Message("Victim is null"); - AbilityEffectUtility.SpawnSpawnables(UseAbilityProps.thingsToSpawn, CasterPawn, CasterPawn.MapHeld, CasterPawn.PositionHeld); + var casterPawn = CasterPawn; + AbilityEffectUtility.SpawnSpawnables(props.thingsToSpawn, casterPawn, casterPawn.MapHeld, casterPawn.PositionHeld); } } - // } + //} } PostCastShot(result, out result); if (result == false) { - Ability.Notify_AbilityFailed(UseAbilityProps.refundsPointsAfterFailing); + Ability.Notify_AbilityFailed(props.refundsPointsAfterFailing); } return result; } - private bool debugMode = false; - - private void DebugMessage(string s) - { - if (debugMode) Log.Message(s); - } - - + // Loosely based off Verb_LaunchProjectile.TryCastShot. public bool TryLaunchProjectileCheck(ThingDef projectileDef, LocalTargetInfo launchTarget) { - DebugMessage(launchTarget.ToString()); var flag = TryFindShootLineFromTo(caster.Position, launchTarget, out var shootLine); if (verbProps.requireLineOfSight && verbProps.stopBurstWithoutLos && !flag) { @@ -263,49 +256,47 @@ public bool TryLaunchProjectileCheck(ThingDef projectileDef, LocalTargetInfo lau } var drawPos = caster.DrawPos; var projectile = (Projectile_AbilityBase)GenSpawn.Spawn(projectileDef, shootLine.Source, caster.Map); - projectile.extraDamages = UseAbilityProps.extraDamages; - projectile.localSpawnThings = UseAbilityProps.thingsToSpawn; - verbProps.soundCast?.PlayOneShot(new TargetInfo(caster.Position, caster.Map, false)); + var props = UseAbilityProps; + projectile.extraDamages = props.extraDamages; + projectile.localSpawnThings = props.thingsToSpawn; + verbProps.soundCast?.PlayOneShot(new TargetInfo(caster.Position, caster.Map)); verbProps.soundCastTail?.PlayOneShotOnCamera(); if (DebugViewSettings.drawShooting) - MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToHit", -1f); - ProjectileHitFlags projectileHitFlags4 = ProjectileHitFlags.IntendedTarget; - if (this.canHitNonTargetPawnsNow) + MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToHit"); // TODO: Translate()? + var projectileHitFlags = ProjectileHitFlags.IntendedTarget; + if (canHitNonTargetPawnsNow) { - projectileHitFlags4 |= ProjectileHitFlags.NonTargetPawns; + projectileHitFlags |= ProjectileHitFlags.NonTargetPawns; } - if (!this.currentTarget.HasThing || this.currentTarget.Thing.def.Fillage == FillCategory.Full) + if (!currentTarget.HasThing || currentTarget.Thing.def.Fillage == FillCategory.Full) { - projectileHitFlags4 |= ProjectileHitFlags.NonTargetWorld; + projectileHitFlags |= ProjectileHitFlags.NonTargetWorld; } - DebugMessage(launchTarget.ToString()); - projectile.Launch(caster, Ability.Def, drawPos, launchTarget, projectileHitFlags4, null, - UseAbilityProps.hediffsToApply, - UseAbilityProps.mentalStatesToApply, UseAbilityProps.thingsToSpawn); + projectile.Launch(caster, Ability.Def, drawPos, launchTarget, projectileHitFlags, preventFriendlyFire, equipment: null, + props.hediffsToApply, props.mentalStatesToApply, props.thingsToSpawn); return true; } - + protected bool? TryLaunchProjectile(ThingDef projectileDef, LocalTargetInfo launchTarget) { if (TryLaunchProjectileCheck(projectileDef, launchTarget)) { + DebugMessage($"Verb_UseAbility.TryLaunchProjectileCheck({this}, projectileDef={projectileDef}, launchTarget={launchTarget}) => true"); return true; } + DebugMessage($"Verb_UseAbility.TryLaunchProjectileCheck({this}, projectileDef={projectileDef}, launchTarget={launchTarget}) => false"); Ability.Notify_AbilityFailed(true); return false; } public override void WarmupComplete() { - if (verbTracker == null) - verbTracker = CasterPawn.verbTracker; + verbTracker ??= CasterPawn.verbTracker; burstShotsLeft = ShotsPerBurst; state = VerbState.Bursting; TryCastNextBurstShot(); - //Find.BattleLog.Add(new BattleLogEntry_RangedFire(this.caster, - // (!this.currentTarget.HasThing) ? null : this.currentTarget.Thing, - // (base.EquipmentSource == null) ? null : base.EquipmentSource.def, this.Projectile, - // this.ShotsPerBurst > 1)); + //Find.BattleLog.Add(new BattleLogEntry_RangedFire(caster, currentTarget.Thing, + // EquipmentSource?.def, Projectile, ShotsPerBurst > 1)); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Controller/Verb_UseAbility_TrueBurst.cs b/Source/AllModdingComponents/CompAbilityUser/Controller/Verb_UseAbility_TrueBurst.cs index d5ee40d1..2433b8c0 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Controller/Verb_UseAbility_TrueBurst.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Controller/Verb_UseAbility_TrueBurst.cs @@ -8,36 +8,33 @@ public class Verb_UseAbility_TrueBurst : Verb_UseAbility //// Made it so burst is not burst per each target, but back to the regular burst-over-time. //protected override bool TryCastShot() //{ - // this.ability.CooldownTicksLeft = (int)this.UseAbilityProps.SecondsToRecharge * GenTicks.TicksPerRealSecond; - // bool result = false; - // this.TargetsAoE.Clear(); + // ability.CooldownTicksLeft = (int)UseAbilityProps.SecondsToRecharge * GenTicks.TicksPerRealSecond; + // var result = false; + // TargetsAoE.Clear(); // UpdateTargets(); - // int burstShots = this.ShotsPerBurst; - // if (this.UseAbilityProps.AbilityTargetCategory != AbilityTargetCategory.TargetAoE && this.TargetsAoE.Count > 1) + // //var burstShots = ShotsPerBurst; + // if (UseAbilityProps.AbilityTargetCategory != AbilityTargetCategory.TargetAoE && TargetsAoE.Count > 1) // { - // this.TargetsAoE.RemoveRange(0, this.TargetsAoE.Count - 1); + // TargetsAoE.RemoveRange(0, TargetsAoE.Count - 1); // } - // for (int i = 0; i < this.TargetsAoE.Count; i++) + // for (var i = 0; i < TargetsAoE.Count; i++) // { - // // for (int j = 0; j < burstshots; j++) - // // { - // bool? attempt = TryLaunchProjectile(this.verbProps.projectileDef, this.TargetsAoE[i]); + // //for (var j = 0; j < burstshots; j++) + // //{ + // var attempt = TryLaunchProjectile(verbProps.projectileDef, TargetsAoE[i]); // ////Log.Message(TargetsAoE[i].ToString()); - // if (attempt != null) - // { - // if (attempt == true) result = true; - // if (attempt == false) result = false; - // } - // // } + // if (attempt.HasValue) + // result = attempt.GetValueOrDefault(); + // //} // } // // here, might want to have this set each time so people don't force stop on last burst and not hit the cooldown? - // //this.burstShotsLeft = 0; - // //if (this.burstShotsLeft == 0) + // //burstShotsLeft = 0; + // //if (burstShotsLeft == 0) // //{ // //} // PostCastShot(result, out result); // return result; //} } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/ExtraDamage.cs b/Source/AllModdingComponents/CompAbilityUser/ExtraDamage.cs index 641c7540..cc4d7201 100644 --- a/Source/AllModdingComponents/CompAbilityUser/ExtraDamage.cs +++ b/Source/AllModdingComponents/CompAbilityUser/ExtraDamage.cs @@ -10,9 +10,9 @@ public class ExtraDamage : IExposable public void ExposeData() { - Scribe_Values.Look(ref damage, "damage", -1); - Scribe_Defs.Look(ref damageDef, "damageDef"); - Scribe_Values.Look(ref chance, "chance", -1f); + Scribe_Values.Look(ref damage, nameof(damage), -1); + Scribe_Defs.Look(ref damageDef, nameof(damageDef)); + Scribe_Values.Look(ref chance, nameof(chance), -1f); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/FlyingObject.cs b/Source/AllModdingComponents/CompAbilityUser/FlyingObject.cs index 7a8818af..3341b9a9 100644 --- a/Source/AllModdingComponents/CompAbilityUser/FlyingObject.cs +++ b/Source/AllModdingComponents/CompAbilityUser/FlyingObject.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Collections.Generic; using RimWorld; using UnityEngine; using Verse; @@ -9,32 +10,68 @@ namespace AbilityUser /// A special version of a projectile. /// This one "stores" a base object and "delivers" it. /// + // Based off Projectile (and parts of Projectile_Explosive and Bullet). public class FlyingObject : ThingWithComps { - protected Thing usedTarget; - + // TODO: Deprecate/move these settings into a CompProperties_FlyingObject (derived from ProjectileProperties)? public bool damageLaunched = true; - protected Vector3 destination; + [Obsolete("Use Props.speed")] + protected float speed = 30f; + public int timesToDamage = 3; + public float accuracyRadius = 0.3f; + [Obsolete("Use Props.extraDamages")] + public DamageInfo? impactDamage; // this can also be set via Launch method + [Obsolete("Use Props.explosionRadius > 0f")] public bool explosion; - protected Thing flyingThing; - public DamageInfo? impactDamage; - protected Thing launcher; + private ProjectileProperties props; + + // These are set by the Launch method. protected Vector3 origin; - protected float speed = 30.0f; + protected Vector3 destination; protected int ticksToImpact; - public int timesToDamage = 3; + protected Thing usedTarget; // TODO: should be a LocalTargetInfo? + protected Thing flyingThing; + protected ThingDef equipmentDef; + protected Thing launcher; - protected int StartingTicksToImpact + // TODO: should be CompProperties_FlyingObject (derived from ProjectileProperties)? + public ProjectileProperties Props { get { - var num = Mathf.RoundToInt((origin - destination).magnitude / (speed / 100f)); - if (num < 1) - num = 1; - return num; + if (props == null) + { + props = new ProjectileProperties() + // Legacy defaults +#pragma warning disable CS0618 // Type or member is obsolete + { + speed = speed, + }; + if (impactDamage is DamageInfo dinfo) + { + props.extraDamages = DamageInfoToExtraDamages(dinfo); + if (explosion) +#pragma warning restore CS0618 // Type or member is obsolete + { + props.damageDef = DamageDefOf.Stun; + props.explosionRadius = 0.9f; + } + }; + } + return props; } } + protected float StartingTicksToImpact + { + get + { + var ticks = (origin - destination).magnitude / Props.SpeedTilesPerTick; + if (ticks <= 0f) + ticks = 0.001f; + return ticks; + } + } protected IntVec3 DestinationCell => new IntVec3(destination); @@ -42,27 +79,30 @@ public virtual Vector3 ExactPosition { get { - var b = (destination - origin) * (1f - ticksToImpact / (float) StartingTicksToImpact); - return origin + b + Vector3.up * def.Altitude; + var b = (destination - origin).Yto0() * Mathf.Clamp01(1f - ticksToImpact / StartingTicksToImpact); + return origin.Yto0() + b + Vector3.up * def.Altitude; } } - public virtual Quaternion ExactRotation => Quaternion.LookRotation(destination - origin); + public virtual Quaternion ExactRotation => Quaternion.LookRotation((destination - origin).Yto0()); public override Vector3 DrawPos => ExactPosition; public override void ExposeData() { base.ExposeData(); - Scribe_Values.Look(ref origin, "origin", default(Vector3), false); - Scribe_Values.Look(ref destination, "destination", default(Vector3), false); - Scribe_Values.Look(ref ticksToImpact, "ticksToImpact", 0, false); - Scribe_Values.Look(ref timesToDamage, "timesToDamage", 0, false); - Scribe_Values.Look(ref damageLaunched, "damageLaunched", true); - Scribe_Values.Look(ref explosion, "explosion", false); - Scribe_References.Look(ref usedTarget, "usedTarget", false); - Scribe_References.Look(ref launcher, "launcher", false); - Scribe_References.Look(ref flyingThing, "flyingThing"); + Scribe_Values.Look(ref origin, nameof(origin)); + Scribe_Values.Look(ref destination, nameof(destination)); + Scribe_Values.Look(ref ticksToImpact, nameof(ticksToImpact)); + Scribe_Values.Look(ref timesToDamage, nameof(timesToDamage)); + Scribe_Values.Look(ref damageLaunched, nameof(damageLaunched), true); +#pragma warning disable CS0618 // Type or member is obsolete + Scribe_Values.Look(ref explosion, nameof(explosion)); +#pragma warning restore CS0618 // Type or member is obsolete + Scribe_Deep.Look(ref props, nameof(props)); + Scribe_References.Look(ref usedTarget, nameof(usedTarget)); + Scribe_References.Look(ref launcher, nameof(launcher)); + Scribe_References.Look(ref flyingThing, nameof(flyingThing)); } public void Launch(Thing launcher, LocalTargetInfo targ, Thing flyingThing, DamageInfo? impactDamage) @@ -75,56 +115,79 @@ public void Launch(Thing launcher, LocalTargetInfo targ, Thing flyingThing) Launch(launcher, Position.ToVector3Shifted(), targ, flyingThing); } + // TODO: New Launch overload that corresponds to latest Projectile.Launch signature? public void Launch(Thing launcher, Vector3 origin, LocalTargetInfo targ, Thing flyingThing, DamageInfo? newDamageInfo = null) { //Despawn the object to fly - if (flyingThing.Spawned) flyingThing.DeSpawn(); + if (flyingThing.Spawned) + flyingThing.DeSpawn(); this.launcher = launcher; this.origin = origin; - impactDamage = newDamageInfo; - this.flyingThing = flyingThing; - if (targ.Thing != null) - usedTarget = targ.Thing; - destination = targ.Cell.ToVector3Shifted() + - new Vector3(Rand.Range(-0.3f, 0.3f), 0f, Rand.Range(-0.3f, 0.3f)); - ticksToImpact = StartingTicksToImpact; + if (newDamageInfo is DamageInfo impactDamage) + { + Props.extraDamages = DamageInfoToExtraDamages(impactDamage); + equipmentDef = impactDamage.Weapon; + } + this.flyingThing ??= flyingThing; + usedTarget = targ.Thing; + destination = targ.Cell.ToVector3Shifted(); + if (accuracyRadius > 0f) + { + destination.x += Rand.Range(-accuracyRadius, accuracyRadius); + destination.z += Rand.Range(-accuracyRadius, accuracyRadius); + } + ticksToImpact = Math.Min(1, Mathf.CeilToInt(StartingTicksToImpact)); + //Log.Message($"FlyingObject.Launch({this})"); + } + + private static List DamageInfoToExtraDamages(DamageInfo dinfo) + { + return new List + { + new Verse.ExtraDamage + { + def = dinfo.Def, + amount = dinfo.Amount, + armorPenetration = dinfo.ArmorPenetrationInt, + } + }; } public override void Tick() { + //if (ticksToImpact % 10 == 0) Log.Message($"FlyingObject.Tick({this})"); base.Tick(); - var exactPosition = ExactPosition; ticksToImpact--; - if (!ExactPosition.InBounds(Map)) + var exactPosition = ExactPosition; + if (!exactPosition.InBounds(Map)) { ticksToImpact++; - Position = ExactPosition.ToIntVec3(); - Destroy(DestroyMode.Vanish); - return; + exactPosition = ExactPosition; + Position = exactPosition.ToIntVec3(); + Destroy(); } - - Position = ExactPosition.ToIntVec3(); - if (ticksToImpact <= 0) + else if (ticksToImpact <= 0) { - if (DestinationCell.InBounds(Map)) - Position = DestinationCell; + var destinationCell = DestinationCell; + Position = destinationCell.InBounds(Map) ? destinationCell : exactPosition.ToIntVec3(); ImpactSomething(); } + else + { + // TODO: There should be an option to check for impact when entering a new cell. + Position = exactPosition.ToIntVec3(); + } } public override void Draw() { if (flyingThing != null) { - if (flyingThing is Pawn) + if (flyingThing is Pawn pawn) { - if (DrawPos == null) return; - if (!DrawPos.ToIntVec3().IsValid) return; - var pawn = flyingThing as Pawn; pawn.Drawer.DrawAt(DrawPos); - //Graphics.DrawMesh(MeshPool.plane10, this.DrawPos, this.ExactRotation, this.flyingThing.def.graphic.MatFront, 0); } else { @@ -136,16 +199,14 @@ public override void Draw() private void ImpactSomething() { + //Log.Message($"FlyingObject.ImpactSomething({this})"); if (usedTarget != null) { - var pawn = usedTarget as Pawn; - if (pawn != null && pawn.GetPosture() != PawnPosture.Standing && + if (usedTarget is Pawn pawn && pawn.GetPosture() != PawnPosture.Standing && (origin - destination).MagnitudeHorizontalSquared() >= 20.25f && Rand.Value > 0.2f) - { Impact(null); - return; - } - Impact(usedTarget); + else + Impact(usedTarget); } else { @@ -155,22 +216,19 @@ private void ImpactSomething() protected virtual void Impact(Thing hitThing) { - if (hitThing == null) - if (Position.GetThingList(Map).FirstOrDefault(x => x == usedTarget) is Pawn p) - hitThing = p; + var map = Map; + var pos = Position; + var props = Props; + if (damageLaunched) + hitThing = flyingThing; + else if (hitThing == null && usedTarget != null && pos.GetThingList(map).Contains(usedTarget)) + hitThing = usedTarget; - if (impactDamage != null) + if (!props.extraDamages.NullOrEmpty()) { + // Based off Bullet. for (var i = 0; i < timesToDamage; i++) -<<<<<<< Updated upstream - if (damageLaunched) - flyingThing.TakeDamage(impactDamage.Value); - else - hitThing.TakeDamage(impactDamage.Value); - if (explosion) - GenExplosion.DoExplosion(Position, Map, 0.9f, DamageDefOf.Stun, this); -======= { foreach (var extraDamage in props.extraDamages) { @@ -232,10 +290,12 @@ public override string ToString() foreach (var extraDamage in props.extraDamages) impactDamageStrs.Add($"({Gen.GetNonNullFieldsDebugInfo(extraDamage)})"); propsStr = propsStr.Replace(props.extraDamages.ToStringSafe(), "{" + impactDamageStrs.ToStringSafeEnumerable() + "}"); ->>>>>>> Stashed changes } - GenSpawn.Spawn(flyingThing, Position, Map); - Destroy(DestroyMode.Vanish); + return $"{base.ToString()}(flyingThing={flyingThing.ToStringSafe()}, usedTarget={usedTarget?.ToStringSafe()}, " + + $"equipmentDef={equipmentDef.ToStringSafe()}, launcher={launcher.ToStringSafe()}, " + + $"origin={origin}, destination={destination}, pos={ExactPosition}, ticksToImpact={ticksToImpact}, " + + $"damageLaunched={damageLaunched}, timesToDamage={timesToDamage}, accuracyRadius={accuracyRadius}, " + + $"props={propsStr})"; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/FlyingObject_Equipable.cs b/Source/AllModdingComponents/CompAbilityUser/FlyingObject_Equipable.cs index 82ad0db6..320a1e72 100644 --- a/Source/AllModdingComponents/CompAbilityUser/FlyingObject_Equipable.cs +++ b/Source/AllModdingComponents/CompAbilityUser/FlyingObject_Equipable.cs @@ -1,4 +1,5 @@ -using Verse; +using RimWorld; +using Verse; using Verse.Sound; namespace AbilityUser @@ -10,34 +11,36 @@ protected override void Impact(Thing hitThing) if (flyingThing != null) { GenSpawn.Spawn(flyingThing, Position, Map); - if (launcher != null) - if (launcher is Pawn equipper) - if (equipper.equipment != null) - if (flyingThing is ThingWithComps flyingThingWithComps) - Equip(equipper, flyingThingWithComps); + if (launcher is Pawn {equipment: not null} equipper && flyingThing is ThingWithComps flyingThingWithComps) + Equip(equipper, flyingThingWithComps); } - Destroy(DestroyMode.Vanish); + Destroy(); } public void Equip(Pawn equipper, ThingWithComps thingWithComps) { - var flag = false; - ThingWithComps thingWithComps2; - if (thingWithComps.def.stackLimit > 1 && thingWithComps.stackCount > 1) + if (thingWithComps.def.IsApparel) { - thingWithComps2 = (ThingWithComps) thingWithComps.SplitOff(1); + var apparel = (Apparel)thingWithComps; + equipper.apparel.Wear(apparel); + equipper.outfits?.forcedHandler.SetForced(apparel, true); } else { - thingWithComps2 = thingWithComps; - flag = true; + ThingWithComps thingWithComps2; + if (thingWithComps.def.stackLimit > 1 && thingWithComps.stackCount > 1) + { + thingWithComps2 = (ThingWithComps)thingWithComps.SplitOff(1); + } + else + { + thingWithComps2 = thingWithComps; + thingWithComps2.DeSpawn(); + } + equipper.equipment.MakeRoomFor(thingWithComps2); + equipper.equipment.AddEquipment(thingWithComps2); + thingWithComps.def.soundInteract?.PlayOneShot(new TargetInfo(equipper.Position, equipper.Map)); } - equipper.equipment.MakeRoomFor(thingWithComps2); - equipper.equipment.AddEquipment(thingWithComps2); - if (thingWithComps.def.soundInteract != null) - thingWithComps.def.soundInteract.PlayOneShot(new TargetInfo(equipper.Position, equipper.Map, false)); - if (flag) - thingWithComps.DeSpawn(); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Model/AbilityData.cs b/Source/AllModdingComponents/CompAbilityUser/Model/AbilityData.cs index dcdc61a5..55625ee7 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Model/AbilityData.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Model/AbilityData.cs @@ -40,23 +40,56 @@ public List AllPowers if (allPowers == null) { allPowers = new List(); - if (!Powers.NullOrEmpty()) + if (Powers != null) allPowers.AddRange(Powers); - if (!TemporaryApparelPowers.NullOrEmpty()) + if (TemporaryApparelPowers != null) allPowers.AddRange(TemporaryApparelPowers); - if (!TemporaryWeaponPowers.NullOrEmpty()) + if (TemporaryWeaponPowers != null) allPowers.AddRange(TemporaryWeaponPowers); + //Log.Message($"AbilityData.AllPowers({this}) refresh => {allPowers.Count} powers"); } return allPowers; } set => allPowers = value; } + public int Count + { + get + { + if (allPowers != null) + return allPowers.Count; + var count = 0; + if (Powers != null) + count += Powers.Count; + if (TemporaryApparelPowers != null) + count += TemporaryApparelPowers.Count; + if (TemporaryWeaponPowers != null) + count += TemporaryWeaponPowers.Count; + return count; + } + } + public void ExposeData() { - Scribe_References.Look(ref pawn, "abilityDataPawn" + this.GetType().ToString()); - Scribe_Values.Look(ref abilityClass, "abilityDataClass" + this.GetType().ToString(), null); - Scribe_Collections.Look(ref powers, "abilityDataPowers" + this.GetType().ToString(), LookMode.Deep, this); + var typeString = GetType().ToString(); + Scribe_References.Look(ref pawn, "abilityDataPawn" + typeString); + Scribe_Values.Look(ref abilityClass, "abilityDataClass" + typeString); + Scribe_Collections.Look(ref powers, "abilityDataPowers" + typeString, LookMode.Deep, this); + } + + public override string ToString() + { + return $"(AbilityClass={AbilityClass.Name}, Pawn={Pawn}, {AllPowersToString()})"; + } + + public string AllPowersToString() + { + if (Count == 0) + return "(no powers)"; + return string.Format("Powers={{{0}}}, TemporaryApparelPowers={{{1}}}, TemporaryWeaponPowers={{{2}}}", + Powers.ToStringSafeEnumerable(), TemporaryApparelPowers.ToStringSafeEnumerable(), + TemporaryWeaponPowers.ToStringSafeEnumerable()); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Model/AbilityDef.cs b/Source/AllModdingComponents/CompAbilityUser/Model/AbilityDef.cs index edfb9f9d..080af2e2 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Model/AbilityDef.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Model/AbilityDef.cs @@ -16,66 +16,44 @@ public class AbilityDef : Def public string uiIconPath; - public override int GetHashCode() - { - return Gen.HashCombineInt(defName.GetHashCode(), "AbilityDef".GetHashCode()); - } - public override void PostLoad() { base.PostLoad(); - LongEventHandler.ExecuteWhenFinished(delegate + LongEventHandler.ExecuteWhenFinished(() => { if (!uiIconPath.NullOrEmpty()) - uiIcon = ContentFinder.Get(uiIconPath, true); - //else if (this.DrawMatSingle != null && this.DrawMatSingle != BaseContent.BadMat) - //{ - // this.uiIcon = (Texture2D)this.DrawMatSingle.mainTexture; - //} + uiIcon = ContentFinder.Get(uiIconPath); + //else if (DrawMatSingle != null && DrawMatSingle != BaseContent.BadMat) + // uiIcon = (Texture2D)DrawMatSingle.mainTexture; }); } public Job GetJob(AbilityTargetCategory cat, LocalTargetInfo target) { - switch (cat) + return JobMaker.MakeJob(cat switch { - case AbilityTargetCategory.TargetSelf: - { - return new Job(AbilityDefOf.CastAbilitySelf, target); - } - case AbilityTargetCategory.TargetAoE: - { - return new Job(AbilityDefOf.CastAbilityVerb, target); - } - case AbilityTargetCategory.TargetThing: - { - return new Job(AbilityDefOf.CastAbilityVerb, target); - } - default: - { - return new Job(AbilityDefOf.CastAbilityVerb, target); - } - } + AbilityTargetCategory.TargetSelf => AbilityDefOf.CastAbilitySelf, + _ => AbilityDefOf.CastAbilityVerb, + }, target); } public virtual string GetDescription() { - var result = ""; var coolDesc = GetBasics(); var AoEDesc = GetAoEDesc(); - //string postDesc = PostAbilityVerbDesc(); + //var postDesc = PostAbilityVerbDesc(); var desc = new StringBuilder(); desc.AppendLine(description); - if (coolDesc != "") desc.AppendLine(coolDesc); - if (AoEDesc != "") desc.AppendLine(AoEDesc); - //if (postDesc != "") desc.AppendLine(postDesc); - result = desc.ToString(); - return result; + if (coolDesc.Length != 0) + desc.AppendLine(coolDesc); + if (AoEDesc.Length != 0) + desc.AppendLine(AoEDesc); + //if (postDesc.Length != 0) desc.AppendLine(postDesc); + return desc.ToString(); } public virtual string GetAoEDesc() { - var result = ""; var def = MainVerb; if (def != null) if (def.TargetAoEProperties != null) @@ -92,35 +70,27 @@ public virtual string GetAoEDesc() s.AppendLine("\t" + StringsToTranslate.AU_AoEMaxTargets + def.TargetAoEProperties.maxTargets); if (def.TargetAoEProperties.startsFromCaster) s.AppendLine("\t" + StringsToTranslate.AU_AoEStartsFromCaster); - result = s.ToString(); + return s.ToString(); } - return result; + return ""; } public string GetBasics() { - var result = ""; var def = MainVerb; if (def != null) { var s = new StringBuilder(); s.AppendLine(StringsToTranslate.AU_Cooldown + def.SecondsToRecharge.ToString("N0") + " " + "SecondsLower".Translate()); - switch (def.AbilityTargetCategory) + s.AppendLine(StringsToTranslate.AU_Type + def.AbilityTargetCategory switch { - case AbilityTargetCategory.TargetAoE: - s.AppendLine(StringsToTranslate.AU_Type + StringsToTranslate.AU_TargetAoE); - break; - case AbilityTargetCategory.TargetSelf: - s.AppendLine(StringsToTranslate.AU_Type + StringsToTranslate.AU_TargetSelf); - break; - case AbilityTargetCategory.TargetThing: - s.AppendLine(StringsToTranslate.AU_Type + StringsToTranslate.AU_TargetThing); - break; - case AbilityTargetCategory.TargetLocation: - s.AppendLine(StringsToTranslate.AU_Type + StringsToTranslate.AU_TargetLocation); - break; - } + AbilityTargetCategory.TargetAoE => StringsToTranslate.AU_TargetAoE, + AbilityTargetCategory.TargetSelf => StringsToTranslate.AU_TargetSelf, + AbilityTargetCategory.TargetThing => StringsToTranslate.AU_TargetThing, + AbilityTargetCategory.TargetLocation => StringsToTranslate.AU_TargetLocation, + _ => throw new NotImplementedException(), + }); if (def.tooltipShowProjectileDamage) if (def.defaultProjectile != null) if (def.defaultProjectile.projectile != null) @@ -132,7 +102,7 @@ public string GetBasics() def.defaultProjectile.projectile.damageDef.LabelCap); } if (def.tooltipShowExtraDamages) - if (def.extraDamages != null && def.extraDamages.Count > 0) + if (def.extraDamages != null) if (def.extraDamages.Count == 1) { s.AppendLine(StringsToTranslate.AU_Extra + " " + "Damage".Translate() + ": " + @@ -140,7 +110,7 @@ public string GetBasics() s.AppendLine(StringsToTranslate.AU_Extra + " " + "Damage".Translate() + " " + StringsToTranslate.AU_Type + def.extraDamages[0].damageDef.LabelCap); } - else + else if (def.extraDamages.Count > 1) { s.AppendLine(StringsToTranslate.AU_Extra + " " + "Damage".Translate() + ": "); foreach (var extraDam in def.extraDamages) @@ -152,14 +122,14 @@ public string GetBasics() } } if (def.tooltipShowMentalStatesToApply) - if (def.mentalStatesToApply != null && def.mentalStatesToApply.Count > 0) + if (def.mentalStatesToApply != null) if (def.mentalStatesToApply.Count == 1) { s.AppendLine(StringsToTranslate.AU_MentalStateChance + ": " + def.mentalStatesToApply[0].mentalStateDef.LabelCap + " " + def.mentalStatesToApply[0].applyChance.ToStringPercent()); } - else + else if (def.mentalStatesToApply.Count > 1) { s.AppendLine(StringsToTranslate.AU_MentalStateChance); foreach (var mentalState in def.mentalStatesToApply) @@ -168,13 +138,13 @@ public string GetBasics() } if (def.tooltipShowHediffsToApply) { - if (def.hediffsToApply != null && def.hediffsToApply.Count > 0) + if (def.hediffsToApply != null) if (def.hediffsToApply.Count == 1) { s.AppendLine(StringsToTranslate.AU_EffectChance + def.hediffsToApply[0].hediffDef.LabelCap + " " + def.hediffsToApply[0].applyChance.ToStringPercent()); } - else + else if (def.hediffsToApply.Count > 1) { s.AppendLine(StringsToTranslate.AU_EffectChance); foreach (var hediff in def.hediffsToApply) @@ -184,7 +154,7 @@ public string GetBasics() if (hediff.hediffDef.HasComp(typeof(HediffComp_Disappears))) { var intDuration = - ((HediffCompProperties_Disappears) hediff.hediffDef.CompPropsFor( + ((HediffCompProperties_Disappears)hediff.hediffDef.CompPropsFor( typeof(HediffComp_Disappears))).disappearsAfterTicks.max; duration = intDuration.TicksToSeconds(); } @@ -201,9 +171,9 @@ public string GetBasics() s.AppendLine(StringsToTranslate.AU_BurstShotCount + " " + def.burstShotCount); } - result = s.ToString(); + return s.ToString(); } - return result; + return ""; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Model/CompAbilityUser.cs b/Source/AllModdingComponents/CompAbilityUser/Model/CompAbilityUser.cs index 6e26622f..dc69fb16 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Model/CompAbilityUser.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Model/CompAbilityUser.cs @@ -1,7 +1,10 @@ -using System; +// Uncomment following for testing GeneratePawns Harmony patch for CompAbilityUser.CombatPoints-based rebalancing +//#define COMBAT_POINTS_TEST + +using System; using System.Collections.Generic; -using System.Linq; using RimWorld; +using UnityEngine; using Verse; namespace AbilityUser @@ -15,70 +18,62 @@ Credit goes where credit is due. public class CompAbilityUser : CompUseEffect { - protected static bool classRegisteredWithUtility = false; - - //public LocalTargetInfo CurTarget; - //public AbilityDef curPower; - //public Verb_UseAbility curVerb; - //public Rot4 curRotation; - private AbilityData abilityData; + [Obsolete("Use AbilityUser property instead")] public Pawn abilityUserSave; + [Obsolete("Use Initialized property instead")] public bool IsInitialized; - public virtual AbilityData AbilityData - { - get - { - if (abilityData == null) - abilityData = new AbilityData(this); - return abilityData; - } - } + public virtual AbilityData AbilityData => abilityData ??= new AbilityData(this); - public Pawn Pawn => AbilityUser; +#pragma warning disable CS0618 // Type or member is obsolete + public Pawn Pawn => abilityUserSave ??= (Pawn)parent; +#pragma warning restore CS0618 // Type or member is obsolete - public Pawn AbilityUser + [Obsolete("Use Pawn property instead")] + public Pawn AbilityUser => Pawn; + + public bool Initialized { - get - { - if (abilityUserSave == null) - abilityUserSave = parent as Pawn; - return abilityUserSave; - } +#pragma warning disable CS0618 // Type or member is obsolete + get => IsInitialized; + protected set => IsInitialized = value; +#pragma warning restore CS0618 // Type or member is obsolete } - public CompProperties_AbilityUser Props => (CompProperties_AbilityUser) props; - - //public List AbilityVerbs = new List(); + public CompProperties_AbilityUser Props => (CompProperties_AbilityUser)props; public void AddPawnAbility(AbilityDef abilityDef, bool activenow = true, float savedTicks = -1) { - AddAbilityInternal(abilityDef, AbilityData.Powers, activenow, savedTicks); + AddAbilityInternal(abilityDef, AbilityData.Powers, savedTicks); } public void AddWeaponAbility(AbilityDef abilityDef, bool activenow = true, float savedTicks = -1) { - AddAbilityInternal(abilityDef, AbilityData.TemporaryWeaponPowers, activenow, savedTicks); + AddAbilityInternal(abilityDef, AbilityData.TemporaryWeaponPowers, savedTicks); } public void AddApparelAbility(AbilityDef abilityDef, bool activenow = true, float savedTicks = -1) { - AddAbilityInternal(abilityDef, AbilityData.TemporaryApparelPowers, activenow, savedTicks); + AddAbilityInternal(abilityDef, AbilityData.TemporaryApparelPowers, savedTicks); } - private void AddAbilityInternal(AbilityDef abilityDef, List thelist, bool activenow, - float savedTicks) + private void AddAbilityInternal(AbilityDef abilityDef, List abilities, float savedTicks) { - var pa = (PawnAbility) Activator.CreateInstance(abilityDef.abilityClass); - pa.Pawn = AbilityUser; - pa.Def = abilityDef; - thelist.Add(pa); + abilities.Add(CreateAbility(abilityDef, savedTicks)); UpdateAbilities(); } + private PawnAbility CreateAbility(AbilityDef abilityDef, float savedTicks) + { + // For backwards compatibility, must still use the parameterless constructor. + var pa = (PawnAbility)Activator.CreateInstance(abilityDef.abilityClass); + pa.Initialize(this, abilityDef, Mathf.RoundToInt(savedTicks)); + return pa; + } + public void RemovePawnAbility(AbilityDef abilityDef) { RemoveAbilityInternal(abilityDef, AbilityData.Powers); @@ -94,14 +89,19 @@ public void RemoveApparelAbility(AbilityDef abilityDef) RemoveAbilityInternal(abilityDef, AbilityData.TemporaryApparelPowers); } - private void RemoveAbilityInternal(AbilityDef abilityDef, List thelist) + private void RemoveAbilityInternal(AbilityDef abilityDef, List abilities) { - var abilityToRemove = thelist.FirstOrDefault(x => x.Def == abilityDef); - if (abilityToRemove != null) - thelist.Remove(abilityToRemove); - abilityToRemove = AbilityData.Powers.FirstOrDefault(x => x.Def == abilityDef); - if (abilityToRemove != null) - AbilityData.Powers.Remove(abilityToRemove); + var abilityToRemoveIndex = abilities.FindIndex(x => x.Def == abilityDef); + if (abilityToRemoveIndex != -1) + abilities.RemoveAt(abilityToRemoveIndex); + // TODO: Is always removing from AbilityData.Powers really necessary? + var powers = AbilityData.Powers; + if (abilities != powers) + { + abilityToRemoveIndex = powers.FindIndex(x => x.Def == abilityDef); + if (abilityToRemoveIndex != -1) + powers.RemoveAt(abilityToRemoveIndex); + } UpdateAbilities(); } @@ -113,19 +113,22 @@ public override void PostSpawnSetup(bool respawningAfterLoad) public override void CompTick() { base.CompTick(); - if (!IsInitialized && TryTransformPawn()) + if (!Initialized && TryTransformPawn()) Initialize(); - if (IsInitialized) - if (AbilityData?.AllPowers != null && AbilityData?.AllPowers.Count > 0) - foreach (var power in AbilityData.AllPowers) - power.Tick(); + if (Initialized) + { + var allPowers = AbilityData.AllPowers; + foreach (var power in allPowers) + power.Tick(); + } } public override IEnumerable CompGetGizmosExtra() { - for (var i = 0; i < AbilityData?.AllPowers.Count; i++) + var allPowers = AbilityData.AllPowers; + for (var i = 0; i < allPowers.Count; i++) { - var ability = AbilityData?.AllPowers[i]; + var ability = allPowers[i]; if (ability.ShouldShowGizmo()) yield return ability.GetGizmo(); } @@ -133,58 +136,77 @@ public override IEnumerable CompGetGizmosExtra() public override void PostExposeData() { - Scribe_Values.Look(ref IsInitialized, "abilityUserIsInitialized" + this.GetType().ToString(), false); - Scribe_Deep.Look(ref abilityData, "abilityData" + this.GetType().ToString(), this); + var typeString = GetType().ToString(); +#pragma warning disable CS0618 // Type or member is obsolete + Scribe_Values.Look(ref IsInitialized, "abilityUserIsInitialized" + typeString); +#pragma warning restore CS0618 // Type or member is obsolete + Scribe_Deep.Look(ref abilityData, nameof(abilityData) + typeString, this); if (Scribe.mode == LoadSaveMode.PostLoadInit) { - var tempAbilities = new List(AbilityData.Powers); - if (!tempAbilities.NullOrEmpty()) - foreach (var pa in tempAbilities) - if (pa.Def.abilityClass != pa.GetType()) - { - RemovePawnAbility(pa.Def); - AddPawnAbility(pa.Def); - } + var dirty = false; + var powers = AbilityData.Powers; + for (var i = 0; i < powers.Count; i++) + { + var pa = powers[i]; + if (pa.Def.abilityClass != pa.GetType()) + { + powers[i] = CreateAbility(pa.Def, pa.CooldownTicksLeft); + dirty = true; + } + } + if (dirty) + UpdateAbilities(); } } public void UpdateAbilities() { - if (IsInitialized) + if (Initialized) { - //this.AbilityVerbs.Clear(); - var abList = new List(); - if (!AbilityData.Powers.NullOrEmpty()) abList.AddRange(AbilityData.Powers); - if (!AbilityData.TemporaryWeaponPowers.NullOrEmpty()) - abList.AddRange(AbilityData.TemporaryWeaponPowers); - if (!AbilityData.TemporaryApparelPowers.NullOrEmpty()) - abList.AddRange(AbilityData.TemporaryApparelPowers); - - AbilityData.AllPowers = abList; + // This forces get access of AbilityData.AllPowers to refresh its list. + AbilityData.AllPowers = null; } } - // override this in your children. this is used to determine if this pawn - // should be instantiated with this type of CompAbilityUser. By default, - // returns true. + // Override this in your implementation. This is used to determine if this pawn + // should be initialized with this type of CompAbilityUser. By default, returns false. public virtual bool TryTransformPawn() { return false; } - - // Allows inherited classes to determine "true" combat points for characters that spawn with these components + +#if COMBAT_POINTS_TEST + private float? cachedCombatPoints; +#endif + + // Allows inherited classes to determine "true" combat points for characters that spawn with these components. + // Note: This is called before the parent pawn is spawned and thus Initialize (and PostInitialize) isn't called + // yet (unless already explicitly called in e.g. a PostPostMake override). public virtual float CombatPoints() { +#if COMBAT_POINTS_TEST + if (cachedCombatPoints == null) + { + if (!Initialized) + Initialize(); + cachedCombatPoints = (Pawn.trader != null ? 100 : 0) + AbilityData.AllPowers.Count * 25; + //Log.Message($"CompAbilityUser.CombatPoints({this}) => {cachedCombatPoints}"); + } + return cachedCombatPoints.GetValueOrDefault(); +#else return 0; +#endif } //In some cases, a special ability user might spawn as a single character raid and cause havoc. //To avoid this, a special check occurs to disable the ability user, should this situation occur. public virtual void DisableAbilityUser() { - +#if COMBAT_POINTS_TEST + cachedCombatPoints = 0; +#endif } #region virtual @@ -193,21 +215,31 @@ public virtual void PostInitialize() { } + // Note: To avoid duplicate initialization and working Initialized property value, + // subclasses should override PostInitialize instead of this method. public virtual void Initialize() { - // Log.Warning(" CompAbilityUser.Initialize "); + //Log.Message($"CompAbilityUser.Initialize({this})"); +#pragma warning disable CS0618 // Type or member is obsolete IsInitialized = true; - //this.abilityPowerManager = new AbilityPowerManager(this); +#pragma warning restore CS0618 // Type or member is obsolete PostInitialize(); } + [ThreadStatic] + private static List defaultIgnoredHediffs; + + // Compatibility note: This should've returned IList (and empty array by default), + // but such a change would break binary compatibility. public virtual List IgnoredHediffs() { - var result = new List(); - return result; + if (defaultIgnoredHediffs == null) + defaultIgnoredHediffs = new List(0); // ThreadStatic field always needs to be lazy-init + else + defaultIgnoredHediffs.Clear(); // ensure default list is empty - should be cheap operation if already empty + return defaultIgnoredHediffs; } - public virtual bool CanCastPowerCheck(Verb_UseAbility verbAbility, out string reason) { reason = ""; @@ -219,7 +251,6 @@ public virtual string PostAbilityVerbCompDesc(VerbProperties_Ability verbDef) return ""; } - public virtual string PostAbilityVerbDesc() { return ""; @@ -228,10 +259,27 @@ public virtual string PostAbilityVerbDesc() public virtual float GrappleModifier => 0f; #endregion virtual + + public override bool Equals(object obj) + { + return obj is CompAbilityUser other && + GetType() == other.GetType() && + parent.thingIDNumber == other.parent.thingIDNumber; + } + + public override int GetHashCode() + { + // Stable hash code based off type and parent. + return Gen.HashCombineInt(Gen.HashCombineInt(-66, GenText.StableStringHash(GetType().Name)), parent.thingIDNumber); + } + + public override string ToString() + { + return $"{GetType().Name}(Pawn={Pawn}, AbilityData={abilityData?.AllPowersToString() ?? "null"})"; + } } - // Exists for items to add powers to as it will always be on every Pawn - // and initiated. + // Exists for items to add powers to as it will always be on every Pawn and initialized. public class GenericCompAbilityUser : CompAbilityUser { public override bool TryTransformPawn() @@ -239,4 +287,4 @@ public override bool TryTransformPawn() return true; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/Model/VerbProperties_Ability.cs b/Source/AllModdingComponents/CompAbilityUser/Model/VerbProperties_Ability.cs index 5623350b..bfe9570a 100644 --- a/Source/AllModdingComponents/CompAbilityUser/Model/VerbProperties_Ability.cs +++ b/Source/AllModdingComponents/CompAbilityUser/Model/VerbProperties_Ability.cs @@ -38,4 +38,4 @@ public class VerbProperties_Ability : VerbProperties public bool tooltipShowProjectileDamage = true; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/PassiveEffectProperties.cs b/Source/AllModdingComponents/CompAbilityUser/PassiveEffectProperties.cs index e4145ed9..ed68ff1b 100644 --- a/Source/AllModdingComponents/CompAbilityUser/PassiveEffectProperties.cs +++ b/Source/AllModdingComponents/CompAbilityUser/PassiveEffectProperties.cs @@ -19,11 +19,11 @@ public PassiveEffectWorker Worker { if (passiveEffectWorkerInt == null) { - passiveEffectWorkerInt = (PassiveEffectWorker) Activator.CreateInstance(worker); + passiveEffectWorkerInt = (PassiveEffectWorker)Activator.CreateInstance(worker); passiveEffectWorkerInt.Props = this; } return passiveEffectWorkerInt; } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/PassiveEffectWorker.cs b/Source/AllModdingComponents/CompAbilityUser/PassiveEffectWorker.cs index 9b18320a..70f65bb5 100644 --- a/Source/AllModdingComponents/CompAbilityUser/PassiveEffectWorker.cs +++ b/Source/AllModdingComponents/CompAbilityUser/PassiveEffectWorker.cs @@ -10,9 +10,9 @@ public class PassiveEffectWorker public virtual void DoEffect(CompAbilityUser abilityUser) { - if (Props?.hediffs is List hList && !hList.NullOrEmpty()) + if (Props?.hediffs is List hList) foreach (var h in hList) - HealthUtility.AdjustSeverity(abilityUser.AbilityUser, h, 1f); + HealthUtility.AdjustSeverity(abilityUser.Pawn, h, 1f); } public virtual bool TryDoEffect(CompAbilityUser abilityUser) @@ -25,12 +25,12 @@ public virtual bool CanDoEffect(CompAbilityUser abilityUser) { if (abilityUser == null) return false; - var pawn = abilityUser.AbilityUser; + var pawn = abilityUser.Pawn; if (pawn == null) return false; if (pawn.jobs == null) return false; - if (Props.awakeOnly && pawn?.CurJob?.def == JobDefOf.LayDown || pawn.Downed) + if (Props.awakeOnly && pawn.CurJob?.def == JobDefOf.LayDown || pawn.Downed) return false; if (pawn.mindState == null) return false; @@ -41,22 +41,16 @@ public virtual bool CanDoEffect(CompAbilityUser abilityUser) public virtual void Tick(CompAbilityUser abilityUser) { - var rate = -1; - switch (Props.tickerType) + var rate = Props.tickerType switch { - case TickerType.Rare: - rate = 250; - break; - case TickerType.Normal: - rate = 60; - break; - case TickerType.Long: - rate = 2000; - break; - } + TickerType.Normal => GenTicks.TicksPerRealSecond, // TODO: shouldn't this be 1 instead? + TickerType.Rare => GenTicks.TickRareInterval, + TickerType.Long => GenTicks.TickLongInterval, + _ => -1, + }; if (rate != -1) if (Find.TickManager.TicksGame % rate == 0 && CanDoEffect(abilityUser)) TryDoEffect(abilityUser); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/PawnAbilityTargetCategory.cs b/Source/AllModdingComponents/CompAbilityUser/PawnAbilityTargetCategory.cs index 40d723fd..387878f7 100755 --- a/Source/AllModdingComponents/CompAbilityUser/PawnAbilityTargetCategory.cs +++ b/Source/AllModdingComponents/CompAbilityUser/PawnAbilityTargetCategory.cs @@ -7,4 +7,4 @@ public enum AbilityTargetCategory TargetLocation, TargetAoE } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/PawnSummoned.cs b/Source/AllModdingComponents/CompAbilityUser/PawnSummoned.cs index eafd50f0..a9229dcf 100644 --- a/Source/AllModdingComponents/CompAbilityUser/PawnSummoned.cs +++ b/Source/AllModdingComponents/CompAbilityUser/PawnSummoned.cs @@ -34,7 +34,6 @@ public virtual void PostSummonSetup() { } - public override void Tick() { base.Tick(); @@ -46,7 +45,8 @@ public override void Tick() if (temporary) { ticksLeft--; - if (ticksLeft <= 0) Destroy(); + if (ticksLeft <= 0) + Destroy(); if (Spawned) if (effecter == null) @@ -56,13 +56,12 @@ public override void Tick() } else { - LocalTargetInfo target = this; if (Spawned) effecter.EffectTick(this, TargetInfo.Invalid); - var mote = ((SubEffecter_ProgressBar) effecter.children[0]).mote; + var mote = ((SubEffecter_ProgressBar)effecter.children[0]).mote; if (mote != null) { - var result = 1f - (TicksToDestroy - ticksLeft) / (float) TicksToDestroy; + var result = 1f - (TicksToDestroy - ticksLeft) / (float)TicksToDestroy; mote.progress = Mathf.Clamp01(result); mote.offsetZ = -0.5f; @@ -73,16 +72,16 @@ public override void Tick() public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish) { - if (effecter != null) effecter.Cleanup(); + effecter?.Cleanup(); base.DeSpawn(mode); } public override void ExposeData() { base.ExposeData(); - Scribe_Values.Look(ref temporary, "temporary", false); - Scribe_Values.Look(ref ticksLeft, "ticksLeft", 0); - Scribe_Values.Look(ref ticksToDestroy, "ticksToDestroy", 1800); + Scribe_Values.Look(ref temporary, nameof(temporary)); + Scribe_Values.Look(ref ticksLeft, nameof(ticksLeft)); + Scribe_Values.Look(ref ticksToDestroy, nameof(ticksToDestroy), 1800); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/ProjectileDef_Ability.cs b/Source/AllModdingComponents/CompAbilityUser/ProjectileDef_Ability.cs index 04be6c38..39940c45 100644 --- a/Source/AllModdingComponents/CompAbilityUser/ProjectileDef_Ability.cs +++ b/Source/AllModdingComponents/CompAbilityUser/ProjectileDef_Ability.cs @@ -8,4 +8,4 @@ public class ProjectileDef_Ability : ThingDef public float HealFailChance = 0.3f; public bool IsBeamProjectile = false; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/ProjectileDef_LaserProjectile.cs b/Source/AllModdingComponents/CompAbilityUser/ProjectileDef_LaserProjectile.cs index 1940bc1d..32fd2c30 100755 --- a/Source/AllModdingComponents/CompAbilityUser/ProjectileDef_LaserProjectile.cs +++ b/Source/AllModdingComponents/CompAbilityUser/ProjectileDef_LaserProjectile.cs @@ -12,4 +12,4 @@ public class ProjectileDef_AbilityLaser : ProjectileDef_Ability public float StartFireChance; public string warmupGraphicPathSingle = null; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/SpawnThings.cs b/Source/AllModdingComponents/CompAbilityUser/SpawnThings.cs index 41bc54be..98c06e71 100644 --- a/Source/AllModdingComponents/CompAbilityUser/SpawnThings.cs +++ b/Source/AllModdingComponents/CompAbilityUser/SpawnThings.cs @@ -13,11 +13,16 @@ public class SpawnThings : IExposable public void ExposeData() { - Scribe_Defs.Look(ref def, "def"); - Scribe_Defs.Look(ref kindDef, "kindDef"); - Scribe_Defs.Look(ref factionDef, "factionDef"); - Scribe_Values.Look(ref spawnCount, "spawnCount", 1); - Scribe_Values.Look(ref temporary, "temporary", false); + Scribe_Defs.Look(ref def, nameof(def)); + Scribe_Defs.Look(ref kindDef, nameof(kindDef)); + Scribe_Defs.Look(ref factionDef, nameof(factionDef)); + Scribe_Values.Look(ref spawnCount, nameof(spawnCount), 1); + Scribe_Values.Look(ref temporary, nameof(temporary)); + } + + public override string ToString() + { + return $"(def={def}, factionDef={factionDef}, kindDef={kindDef}, spawnCount={spawnCount}, temporary={temporary})"; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/StringsToTranslate.cs b/Source/AllModdingComponents/CompAbilityUser/StringsToTranslate.cs index 26e186a0..3491f887 100755 --- a/Source/AllModdingComponents/CompAbilityUser/StringsToTranslate.cs +++ b/Source/AllModdingComponents/CompAbilityUser/StringsToTranslate.cs @@ -1,8 +1,8 @@ namespace AbilityUser { + // TODO: These should be translation keys public static class StringsToTranslate { -// public static readonly string AU_AoEProperties = "Area of Effect Properties"; public static readonly string AU_TargetClass = "Targets: "; @@ -24,4 +24,4 @@ public static class StringsToTranslate public static readonly string AU_CastFailure = "Cast Failed"; public static readonly string AU_DISABLED = "DISABLED"; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/View/Command_PawnAbility.cs b/Source/AllModdingComponents/CompAbilityUser/View/Command_PawnAbility.cs index 06d877e6..6de6ed8a 100644 --- a/Source/AllModdingComponents/CompAbilityUser/View/Command_PawnAbility.cs +++ b/Source/AllModdingComponents/CompAbilityUser/View/Command_PawnAbility.cs @@ -34,65 +34,67 @@ public void BeginTargetingWithVerb(Verb_UseAbility verbToAdd, TargetingParameter Texture2D mouseAttachment = null) { verbToAdd.timeSavingActionVariable = this.action; - // Tad changed - // Find.Targeter.targetingVerb = verbToAdd; - // Find.Targeter.targetingVerbAdditionalPawns = null; - Find.Targeter.targetingSource = verbToAdd; - Find.Targeter.targetingSourceAdditionalPawns = null; - AccessTools.Field(typeof(Targeter), "action").SetValue(Find.Targeter, action); - AccessTools.Field(typeof(Targeter), "targetParams").SetValue(Find.Targeter, targetParams); - AccessTools.Field(typeof(Targeter), "caster").SetValue(Find.Targeter, caster); - AccessTools.Field(typeof(Targeter), "actionWhenFinished").SetValue(Find.Targeter, actionWhenFinished); - AccessTools.Field(typeof(Targeter), "mouseAttachment").SetValue(Find.Targeter, mouseAttachment); + var targeter = Find.Targeter; + targeter.targetingSource = verbToAdd; + targeter.targetingSourceAdditionalPawns = null; + targeterActionField(targeter) = action; + targeterCasterField(targeter) = caster; + targeterTargetParamsField(targeter) = targetParams; + targeterActionWhenFinishedField(targeter) = actionWhenFinished; + targeterMouseAttachmentField(targeter) = mouseAttachment; } + private static readonly AccessTools.FieldRef> targeterActionField = + AccessTools.FieldRefAccess>("action"); + private static readonly AccessTools.FieldRef targeterCasterField = + AccessTools.FieldRefAccess("caster"); + private static readonly AccessTools.FieldRef targeterTargetParamsField = + AccessTools.FieldRefAccess("targetParams"); + private static readonly AccessTools.FieldRef targeterActionWhenFinishedField = + AccessTools.FieldRefAccess("actionWhenFinished"); + private static readonly AccessTools.FieldRef targeterMouseAttachmentField = + AccessTools.FieldRefAccess("mouseAttachment"); public override void ProcessInput(Event ev) { SoundDefOf.Tick_Tiny.PlayOneShotOnCamera(); Find.Targeter.StopTargeting(); - BeginTargetingWithVerb(verb, verb.verbProps.targetParams, delegate(LocalTargetInfo info) + BeginTargetingWithVerb(verb, verb.verbProps.targetParams, info => { action.Invoke(info.Thing); - if (CurActivateSound != null) - CurActivateSound.PlayOneShotOnCamera(); - }, compAbilityUser.AbilityUser, null, null); - //(info.Thing ?? null); + CurActivateSound?.PlayOneShotOnCamera(); + }, compAbilityUser.Pawn); } //public override bool GroupsWith(Gizmo other) //{ - // if (other is Command_PawnAbility p && p.pawnAbility.Def.abilityClass == this.pawnAbility.Def.abilityClass) - // return true; - // return false; + // return other is Command_PawnAbility p && p.pawnAbility.Def.abilityClass == pawnAbility.Def.abilityClass; //} - public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth) + protected override GizmoResult GizmoOnGUIInt(Rect butRect, GizmoRenderParms parms) { - var rect = new Rect(topLeft.x, topLeft.y, this.GetWidth(maxWidth), 75f); + // TODO: This is based off Command.GizmoOnGUI at version ~A17, so it's very outdated. Actually use parms and other modern features. var isMouseOver = false; - if (Mouse.IsOver(rect)) + if (Mouse.IsOver(butRect)) { isMouseOver = true; GUI.color = GenUI.MouseoverColor; } - var badTex = icon; - if (badTex == null) badTex = BaseContent.BadTex; + var badTex = icon ?? BaseContent.BadTex; - GUI.DrawTexture(rect, BGTex); - MouseoverSounds.DoRegion(rect, SoundDefOf.Mouseover_Command); + GUI.DrawTexture(butRect, BGTex); + MouseoverSounds.DoRegion(butRect, SoundDefOf.Mouseover_Command); GUI.color = IconDrawColor; - Widgets.DrawTextureFitted(new Rect(rect), badTex, iconDrawScale * 0.85f, iconProportions, iconTexCoords); + Widgets.DrawTextureFitted(new Rect(butRect), badTex, iconDrawScale * 0.85f, iconProportions, iconTexCoords); GUI.color = Color.white; var isUsed = false; - //Rect rectFil = new Rect(topLeft.x, topLeft.y, this.Width, this.Width); var keyCode = hotKey != null ? hotKey.MainKey : KeyCode.None; if (keyCode != KeyCode.None && !GizmoGridDrawer.drawnHotKeys.Contains(keyCode)) { - var rect2 = new Rect(rect.x + 5f, rect.y + 5f, rect.width - 10f, 18f); - Widgets.Label(rect2, keyCode.ToStringReadable()); + var hotkeyRect = new Rect(butRect.x + 5f, butRect.y + 5f, butRect.width - 10f, 18f); + Widgets.Label(hotkeyRect, keyCode.ToStringReadable()); GizmoGridDrawer.drawnHotKeys.Add(keyCode); if (hotKey.KeyDownEvent) { @@ -100,17 +102,17 @@ public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth) Event.current.Use(); } } - if (Widgets.ButtonInvisible(rect, false)) isUsed = true; + if (Widgets.ButtonInvisible(butRect, false)) + isUsed = true; var labelCap = LabelCap; if (!labelCap.NullOrEmpty()) { - var num = Text.CalcHeight(labelCap, rect.width); - num -= 2f; - var rect3 = new Rect(rect.x, rect.yMax - num + 12f, rect.width, num); - GUI.DrawTexture(rect3, TexUI.GrayTextBG); + var labelHeight = Text.CalcHeight(labelCap, butRect.width) - 2f; + var labelRect = new Rect(butRect.x, butRect.yMax - labelHeight + 12f, butRect.width, labelHeight); + GUI.DrawTexture(labelRect, TexUI.GrayTextBG); GUI.color = Color.white; Text.Anchor = TextAnchor.UpperCenter; - Widgets.Label(rect3, labelCap); + Widgets.Label(labelRect, labelCap); Text.Anchor = TextAnchor.UpperLeft; GUI.color = Color.white; } @@ -119,17 +121,17 @@ public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth) { TipSignal tip = Desc; if (disabled && !disabledReason.NullOrEmpty()) - tip.text = tip.text + "\n" + StringsToTranslate.AU_DISABLED + ": " + disabledReason; - TooltipHandler.TipRegion(rect, tip); + tip.text += "\n" + StringsToTranslate.AU_DISABLED + ": " + disabledReason; + TooltipHandler.TipRegion(butRect, tip); } if (pawnAbility.CooldownTicksLeft != -1 && pawnAbility.CooldownTicksLeft < pawnAbility.MaxCastingTicks) { - var math = curTicks / (float) pawnAbility.MaxCastingTicks; - Widgets.FillableBar(rect, math, AbilityButtons.FullTex, AbilityButtons.EmptyTex, false); + var math = curTicks / (float)pawnAbility.MaxCastingTicks; + Widgets.FillableBar(butRect, math, AbilityButtons.FullTex, AbilityButtons.EmptyTex, false); } if (!HighlightTag.NullOrEmpty() && (Find.WindowStack.FloatMenu == null || - !Find.WindowStack.FloatMenu.windowRect.Overlaps(rect))) - UIHighlighter.HighlightOpportunity(rect, HighlightTag); + !Find.WindowStack.FloatMenu.windowRect.Overlaps(butRect))) + UIHighlighter.HighlightOpportunity(butRect, HighlightTag); if (isUsed) { if (disabled) @@ -144,8 +146,7 @@ public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth) TutorSystem.Notify_Event(TutorTagSelect); return result; } - if (isMouseOver) return new GizmoResult(GizmoState.Mouseover, null); - return new GizmoResult(GizmoState.Clear, null); + return new GizmoResult(isMouseOver ? GizmoState.Mouseover : GizmoState.Clear, null); } public void FillableBarBottom(Rect rect, float fillPercent, Texture2D fillTex, Texture2D bgTex, bool doBorder) @@ -161,4 +162,4 @@ public void FillableBarBottom(Rect rect, float fillPercent, Texture2D fillTex, T GUI.DrawTexture(rect, bgTex); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAbilityUser/_HarmonyPatches.cs b/Source/AllModdingComponents/CompAbilityUser/_HarmonyPatches.cs index 002e3dc4..30f93bbb 100644 --- a/Source/AllModdingComponents/CompAbilityUser/_HarmonyPatches.cs +++ b/Source/AllModdingComponents/CompAbilityUser/_HarmonyPatches.cs @@ -1,5 +1,8 @@ -using System; +//#define DEBUGLOG + +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using HarmonyLib; using RimWorld; @@ -14,65 +17,23 @@ public class AbilityUserMod : Mod public AbilityUserMod(ModContentPack content) : base(content) { var harmony = new Harmony("jecstools.jecrell.abilityuser"); - harmony.Patch(AccessTools.Method(typeof(Targeter), nameof(Targeter.TargeterUpdate)), null, - new HarmonyMethod(typeof(AbilityUserMod), nameof(TargeterUpdate_PostFix)), null); + var type = typeof(AbilityUserMod); + + harmony.Patch(AccessTools.Method(typeof(Targeter), nameof(Targeter.TargeterUpdate)), + postfix: new HarmonyMethod(type, nameof(TargeterUpdate_PostFix))); harmony.Patch(AccessTools.Method(typeof(Targeter), nameof(Targeter.ProcessInputEvents)), - new HarmonyMethod(typeof(AbilityUserMod), nameof(ProcessInputEvents_PreFix)), null); + prefix: new HarmonyMethod(type, nameof(ProcessInputEvents_PreFix))); harmony.Patch(AccessTools.Method(typeof(Targeter), "ConfirmStillValid"), - new HarmonyMethod(typeof(AbilityUserMod), nameof(ConfirmStillValid)), null); + prefix: new HarmonyMethod(type, nameof(ConfirmStillValid))); // Initializes the AbilityUsers on Pawns - harmony.Patch(AccessTools.Method(typeof(ThingWithComps), nameof(ThingWithComps.InitializeComps)), null, - new HarmonyMethod(typeof(AbilityUserMod), nameof(InitializeComps_PostFix)), null); - - // when the Pawn_EquipmentTracker is notified of a new item, see if that has CompAbilityItem. - harmony.Patch( - AccessTools.Method(typeof(Pawn_EquipmentTracker), nameof(Pawn_EquipmentTracker.Notify_EquipmentAdded)), - null, - new HarmonyMethod(typeof(AbilityUserMod), nameof(Notify_EquipmentAdded_PostFix)), null); - // when the Pawn_EquipmentTracker is notified of one less item, see if that has CompAbilityItem. - harmony.Patch( - AccessTools.Method(typeof(Pawn_EquipmentTracker), - nameof(Pawn_EquipmentTracker.Notify_EquipmentRemoved)), null, - new HarmonyMethod(typeof(AbilityUserMod), nameof(Notify_EquipmentRemoved_PostFix)), null); - - // when the Pawn_ApparelTracker is notified of a new item, see if that has CompAbilityItem. - harmony.Patch( - AccessTools.Method(typeof(Pawn_ApparelTracker), nameof(Pawn_ApparelTracker.Notify_ApparelAdded)), null, - new HarmonyMethod(typeof(AbilityUserMod), nameof(Notify_ApparelAdded_PostFix)), null); - // when the Pawn_ApparelTracker is notified of one less item, see if that has CompAbilityItem. - harmony.Patch( - AccessTools.Method(typeof(Pawn_ApparelTracker), nameof(Pawn_ApparelTracker.Notify_ApparelRemoved)), - null, - new HarmonyMethod(typeof(AbilityUserMod), nameof(Notify_ApparelRemoved_PostFix)), null); + harmony.Patch(AccessTools.Method(typeof(ThingWithComps), nameof(ThingWithComps.InitializeComps)), + postfix: new HarmonyMethod(type, nameof(InitializeComps_PostFix))); harmony.Patch(AccessTools.Method(typeof(ShortHashGiver), "GiveShortHash"), - new HarmonyMethod(typeof(AbilityUserMod), nameof(GiveShortHash_PrePatch)), null); + prefix: new HarmonyMethod(type, nameof(GiveShortHash_PrePatch))); harmony.Patch(AccessTools.Method(typeof(PawnGroupKindWorker), nameof(PawnGroupKindWorker.GeneratePawns), -<<<<<<< Updated upstream - new Type[] {typeof(PawnGroupMakerParms), typeof(PawnGroupMaker), typeof(bool)}), null, - new HarmonyMethod(typeof(AbilityUserMod), nameof(GeneratePawns_PostFix))); - - //RimWorld v1.0.1964 - harmony.Patch(AccessTools.Property(typeof(Verb), nameof(Verb.UIIcon)).GetGetMethod(), - new HarmonyMethod(typeof(AbilityUserMod), nameof(get_UIIcon)), null); - - harmony.Patch( - AccessTools.Property(typeof(Verb_LaunchProjectile), nameof(Verb_LaunchProjectile.Projectile)) - .GetGetMethod(), - new HarmonyMethod(typeof(AbilityUserMod), nameof(get_Projectile_Prefix)), null); - - harmony.Patch( - AccessTools.Property(typeof(Verb), nameof(Verb.DirectOwner)) - .GetGetMethod(), - new HarmonyMethod(typeof(AbilityUserMod), nameof(get_DirectOwner_Prefix)), null); - - harmony.Patch( - AccessTools.Method(typeof(Verb), nameof(Verb.TryStartCastOn), new Type[] { typeof(LocalTargetInfo), typeof(LocalTargetInfo), typeof(bool), typeof(bool) }) - , - new HarmonyMethod(typeof(AbilityUserMod), nameof(TryStartCastOn_Prefix), null)); -======= new[] { typeof(PawnGroupMakerParms), typeof(PawnGroupMaker), typeof(bool) }), postfix: new HarmonyMethod(type, nameof(GeneratePawns_PostFix))); @@ -88,25 +49,31 @@ public AbilityUserMod(ModContentPack content) : base(content) harmony.Patch(AccessTools.Method(typeof(Verb), nameof(Verb.TryStartCastOn), new[] { typeof(LocalTargetInfo), typeof(LocalTargetInfo), typeof(bool), typeof(bool), typeof(bool), typeof(bool) }), prefix: new HarmonyMethod(type, nameof(TryStartCastOn_Prefix))); ->>>>>>> Stashed changes } +#if DEBUGLOG + private const bool isDebugLog = true; +#else + private const bool isDebugLog = false; +#endif - public static bool TryStartCastOn_Prefix(Verb __instance, LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack, bool canHitNonTargetPawns, ref bool __result) + [Conditional("DEBUGLOG")] + private static void DebugMessage(string s) => Log.Message(s); + + public static bool TryStartCastOn_Prefix(Verb __instance, LocalTargetInfo castTarg, LocalTargetInfo destTarg, + bool surpriseAttack, bool canHitNonTargetPawns, bool preventFriendlyFire, ref bool __result) { - if (!(__instance is Verb_UseAbility vua)) - return true; - else + if (__instance is Verb_UseAbility vua) { - var result = vua.PreCastShot(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns); - __result = result; + __result = vua.PreCastShot(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire); return false; - } + } + return true; } public static bool get_DirectOwner_Prefix(Verb __instance, ref IVerbOwner __result) { - if (__instance is Verb_UseAbility vua) + if (__instance is Verb_UseAbility) { __result = __instance.CasterPawn; return false; @@ -115,7 +82,7 @@ public static bool get_DirectOwner_Prefix(Verb __instance, ref IVerbOwner __resu } public static bool get_Projectile_Prefix(Verb_LaunchProjectile __instance, ref ThingDef __result) { - if (__instance is Verb_UseAbility vua) + if (__instance is Verb_UseAbility) { __result = __instance.verbProps.defaultProjectile; return false; @@ -134,244 +101,307 @@ public static bool get_UIIcon(Verb __instance, ref Texture2D __result) return true; } - // RimWorld.PawnGroupKindWorker_Normal - public static void GeneratePawns_PostFix(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, - bool errorOnZeroResults, ref List __result) + private struct PawnAbilityPointsEntry { - //Anyone special? - if (__result?.Count > 0 && - __result.FindAll(x => x.TryGetComp() is CompAbilityUser cu && cu.CombatPoints() > 0) is - List specialPawns && specialPawns?.Count > 0) + public readonly Pawn pawn; + public readonly CompAbilityUser[] comps; + public readonly float basePoints; + public readonly float points; + + private PawnAbilityPointsEntry(Pawn pawn, CompAbilityUser[] comps, float basePoints, float points) { - //Log.Message("Special Pawns Detected"); - //Log.Message("------------------"); + this.pawn = pawn; + this.comps = comps; + this.basePoints = basePoints; + this.points = points; + } - //Points - var previousPoints = parms.points; - //Log.Message("Points: " + previousPoints); + public bool IsSpecial => points > basePoints; - //Log.Message("Average Characters"); - //Log.Message("------------------"); + public static PawnAbilityPointsEntry For(Pawn pawn) + { + var comps = pawn.GetCompAbilityUsers().ToArray(); + var basePoints = pawn.kindDef.combatPower; + var points = basePoints; + foreach (var comp in comps) + points += comp.CombatPoints(); + return new PawnAbilityPointsEntry(pawn, comps, basePoints, points); + } - //Anyone average? - int avgPawns = 0; - var avgCombatPoints = new Dictionary(); - if (__result.FindAll(x => x.TryGetComp() == null) is List averagePawns) + public PawnAbilityPointsEntry DisableAbilityUser() + { + var basePoints = pawn.kindDef.combatPower; + var points = basePoints; + foreach (var comp in comps) { - avgPawns = averagePawns.Count; - averagePawns.ForEach(x => - { - avgCombatPoints.Add(x, x.kindDef.combatPower); - //Log.Message(x.LabelShort + " : " + x.kindDef.combatPower); - }); + comp.DisableAbilityUser(); + points += comp.CombatPoints(); } + return new PawnAbilityPointsEntry(pawn, comps, basePoints, points); + } - //Log.Message("------------------"); - //Log.Message("Special Characters"); - //Log.Message("------------------"); + public override string ToString() + { + var pointStr = points == basePoints ? $"{points}" : $"{points}={basePoints}+{points - basePoints}"; + return $"({pawn}, kindDef={pawn.kindDef}, role={pawn.GetTraderCaravanRole()}, #comps={comps.Length}, points={pointStr})"; + } + } - //What's your powers? - var specCombatPoints = new Dictionary(); - specialPawns.ForEach(x => - { - var combatValue = x.kindDef.combatPower; - foreach (var thingComp in x.AllComps.FindAll(y => y is CompAbilityUser)) - { - //var compAbilityUser = (CompAbilityUser) thingComp; - var val = Traverse.Create(thingComp).Method("CombatPoints").GetValue(); - combatValue += val; //compAbilityUser.CombatPoints(); - } - specCombatPoints.Add(x, combatValue); - //Log.Message(x.LabelShort + " : " + combatValue); - }); + private struct PawnAbilityPointsEntries + { + public List list; // allocated only if necessary + public int count; + public float points; - //Special case -- single raider/character should not be special to avoid problems (e.g. Werewolf raid destroys everyone). - if (avgPawns == 0 && specCombatPoints.Sum(x => x.Value) > 0 && specialPawns.Count == 1) + public void Add(PawnAbilityPointsEntry entry, bool addToList = true) + { + if (addToList) { - //Log.Message("Special case called: Single character"); - specialPawns.First().TryGetComp().DisableAbilityUser(); - return; + list ??= new List(); + list.Add(entry); } + count++; + points += entry.points; + } - //Special case -- no special characters. - if (specialPawns?.Count <= 0) - return; - - //Should we rebalance? - int tryLimit = avgPawns + specialPawns.Count + 1; - int initTryLimit = tryLimit; - var tempAvgCombatPoints = new Dictionary(avgCombatPoints); - var tempSpecCombatPoints = new Dictionary(specCombatPoints); - var removedCharacters = new List(); - while (previousPoints < tempAvgCombatPoints.Sum(x => x.Value) + tempSpecCombatPoints.Sum(x => x.Value)) + public void Remove(PawnAbilityPointsEntry entry) + { + if (list?.Remove(entry) ?? false) { - //Log.Message("------------------"); - //Log.Message("Rebalance Attempt # " + (initTryLimit - tryLimit + 1)); - //Log.Message("------------------"); - //Log.Message("Scenario Points: " + previousPoints + ". Total Points: " + tempAvgCombatPoints.Sum(x => x.Value) + tempSpecCombatPoints.Sum(x => x.Value)); - - //In-case some stupid stuff occurs - --tryLimit; - if (tryLimit < 0) - break; + count--; + points -= entry.points; + } + } - //If special characters outnumber the avg characters, try removing some of the special characters instead. - if (tempSpecCombatPoints.Count >= tempAvgCombatPoints.Count) + public override string ToString() + { + var str = $"#pawns = {count}, points = {points}"; + ToStringAppendList(ref str); + return str; + } + + [Conditional("DEBUGLOG")] + private void ToStringAppendList(ref string str) + { + if (list != null) + str += list.Join(entry => $"\n\t{entry}", ""); + } + } + + [Conditional("DEBUGLOG")] + private static void DebugAdd(ref PawnAbilityPointsEntries entries, PawnAbilityPointsEntry entry, bool addToList = true) => + entries.Add(entry, addToList); + + [Conditional("DEBUGLOG")] + private static void DebugAdd(ref int x, int y) => x += y; + + [Conditional("DEBUGLOG")] + private static void DebugProfileStart(ref long startTimestamp) => startTimestamp = Stopwatch.GetTimestamp(); + + [Conditional("DEBUGLOG")] + private static void DebugProfileStop(string format, long startTimestamp) => + DebugMessage(string.Format(format, (Stopwatch.GetTimestamp() - startTimestamp) * 1000 / Stopwatch.Frequency)); + + // RimWorld.PawnGroupKindWorker + public static void GeneratePawns_PostFix(PawnGroupMakerParms parms, List __result) + { + // PawnGroupKindWorker.GeneratePawns is about the earliest we can patch, since we need pawns + // to be generated (yet not yet spawned) so that CompAbilityUsers are available on these pawns. + // This is why we can't simply patch PawnGenOption.Cost or PawnGroupMakerUtility.ChoosePawnGenOptionsByPoints. + + if (__result.Count == 0) + return; + + var startTimestamp = 0L; + DebugProfileStart(ref startTimestamp); + RebalanceGeneratedPawns(parms, __result); + DebugProfileStop(rgpMsgPrefix + "Elapsed time: {0} msecs", startTimestamp); + } + + private const string rgpMsgPrefix = nameof(CompAbilityUser) + "." + nameof(RebalanceGeneratedPawns) + ": "; + + private static void RebalanceGeneratedPawns(PawnGroupMakerParms parms, List pawns) + { + // PawnGroupKindWorker does not guaranteed that the sum of pawn points (pawn.kindDef.combatPower) <= parms.points. + // Chattel pawns (slaves and animals) are not included in parms.points yet are in __result. + // Also, PawnGroupKindWorker_Trader decrements parms.points for trader pawns, effectively likewise excluding them. + var targetPoints = parms.points; // parms.points + special trader points (see below) + var targetCount = 0; // debug only, represents the pawns contributing to targetPoints + var origCount = 0; // debug only, represents the pawns contributing to parms.points + + // Partition into special and normal pawns, calculating combat points for each. + // Note: entry lists are allocated only if necessary. + var specials = new PawnAbilityPointsEntries(); + var normals = new PawnAbilityPointsEntries(); + var excluded = new PawnAbilityPointsEntries(); // debug only + foreach (var pawn in pawns) + { + var entry = PawnAbilityPointsEntry.For(pawn); + // parms.points is not used for slaves and animals, so exclude them. + // Using GetTraderCaravanRole() for this, since Humanoid Alien Races patches this method to account for alienslavekinds. + var traderCaravanRole = pawn.GetTraderCaravanRole(); + if (traderCaravanRole == TraderCaravanRole.Chattel || traderCaravanRole == TraderCaravanRole.Carrier) + { + DebugAdd(ref excluded, entry); + } + // Not using TraderCaravanRole.Trader for determining traders - non-null pawn.traders is the authoritative source. + else if (pawn.trader == null) + { + if (entry.IsSpecial) + specials.Add(entry); + else + normals.Add(entry); + DebugAdd(ref origCount, 1); + DebugAdd(ref targetCount, 1); + } + else + { + // PawnGroupKindWorker_Trader reduces parms.points by trader's cost, so exclude them as well. + if (entry.IsSpecial) { - var toRemove = tempSpecCombatPoints?.Keys?.RandomElement(); - if (toRemove != null) - { - //Log.Message("Removed: " + toRemove.LabelShort + " : " + tempSpecCombatPoints[toRemove]); - removedCharacters.Add(toRemove); - tempSpecCombatPoints.Remove(toRemove); - } + // Not excluding 'special' traders yet, to allow them to be disabled into normal traders in below rebalancing loop. + specials.Add(entry); + // Since they're not excluded yet, include them in targetPoints (and targetCount); + // this will be "undone" if disabled in below rebalancing loop. + DebugAdd(ref targetCount, 1); + targetPoints += entry.basePoints; } - //If average characters outnumber special characters, then check if the combat value of avg is greater. - else if (tempSpecCombatPoints.Count < tempAvgCombatPoints.Count) + else + DebugAdd(ref excluded, entry, isDebugLog); + } + } + + if (specials.count > 0) + { + DebugMessage(rgpMsgPrefix + "Target: " + (targetCount != origCount + ? $"#pawns = {origCount} orig + {targetCount - origCount} special trader = {targetCount}, " + + $"points = {parms.points} orig + {targetPoints - parms.points} special trader = {targetPoints}" + : $"#pawns = {targetCount}, points = {targetPoints}")); + DebugMessage(rgpMsgPrefix + "Special: " + specials); + DebugMessage(rgpMsgPrefix + "Normal: " + normals); + DebugMessage(rgpMsgPrefix + "Excluded: " + excluded); + + // Rebalancing loop: + // Until # special pawns = 0 or # pawns <= 1 or special pawn + normal pawn points <= target points: + // If # special pawns > # normal pawns or special pawn points > normal pawn points: + // Try to disable a random special pawn into a normal pawn. + // If this fails, remove the special pawn instead. + // Except if the special pawn being disabled is a trader, just exclude them like normal traders even if disabling fails. + // Else: + // Remove a random normal pawn. + var iterCount = 0; // debug only + var destroyed = new PawnAbilityPointsEntries(); // debug only + while (true) + { + var condition = specials.count > 0 && specials.count + normals.count > 1 && + specials.points + normals.points > targetPoints; + DebugMessage(rgpMsgPrefix + (condition ? $"Rebalance iteration {++iterCount}" : "Final")); + DebugMessage(rgpMsgPrefix + "#pawns: " + (targetCount != origCount + ? $"{origCount} orig + {targetCount - origCount} special trader = {targetCount}" + : $"{targetCount} orig") + + $", {specials.count} special + {normals.count} normal = {specials.count + normals.count}, " + + $"{excluded.count} excluded, {destroyed.count} destroyed"); + DebugMessage(rgpMsgPrefix + "points: " + (targetPoints != parms.points + ? $"{parms.points} orig + {targetPoints - parms.points} special trader = {targetPoints}" + : $"{targetPoints} orig") + + $", {specials.points} special + {normals.points} normal = {specials.points + normals.points}, " + + $"{excluded.points} excluded, {destroyed.points} destroyed"); + if (!condition) + break; + + if (specials.count >= normals.count || specials.points >= normals.points) { - //Remove a random average character if the average characters have more combat points for a score - if (tempAvgCombatPoints.Sum(x => x.Value) > tempSpecCombatPoints.Sum(x => x.Value)) + var entry = specials.list.RandomElement(); + var pawn = entry.pawn; + specials.Remove(entry); + var newEntry = entry.DisableAbilityUser(); + if (pawn.trader != null) { - var toRemove = tempAvgCombatPoints?.Keys?.RandomElement(); - if (toRemove != null) + if (newEntry.IsSpecial) + { + Log.Warning(rgpMsgPrefix + "DisableAbilityUser on 'special' trader pawn {entry} into " + + $"'normal' trader pawn {newEntry} may not have worked, but keeping this pawn due to trader status"); + // Even if disabling didn't work, exclude them like normal trader pawns from more rebalancing, but do NOT + // "undo" their inclusion in targetPoints, so that rebalancing still has to account for their base points. + } + else { - //Log.Message("Removed: " + toRemove.LabelShort + " : " + tempSpecCombatPoints[toRemove]); - removedCharacters.Add(toRemove); - tempAvgCombatPoints.Remove(toRemove); + DebugMessage(rgpMsgPrefix + "Disabled special trader pawn {entry} into normal trader pawn {newEntry}"); + // Once disabled, exclude them like normal trader pawns from more rebalancing, + // and "undo" their inclusion in targetPoints (and targetCount). + targetPoints -= newEntry.basePoints; + DebugAdd(ref targetCount, -1); } + DebugAdd(ref excluded, newEntry, addToList: false); } else { - var toRemove = tempSpecCombatPoints?.Keys?.RandomElement(); - //Log.Message("Removed: " + toRemove.LabelShort + " : " + tempSpecCombatPoints[toRemove]); - if (toRemove != null) + if (newEntry.IsSpecial) { - removedCharacters.Add(toRemove); - tempSpecCombatPoints.Remove(toRemove); + Log.Warning(rgpMsgPrefix + "DisableAbilityUser on 'special' pawn {entry} into 'normal' pawn {newEntry} " + + "may not have worked, so destroying this pawn"); + pawn.DestroyOrPassToWorld(); + pawns.Remove(pawn); + DebugAdd(ref destroyed, newEntry, addToList: false); + } + else + { + DebugMessage(rgpMsgPrefix + "Disabled special non-trader pawn {entry} into normal non-trader pawn {newEntry}"); + normals.Add(newEntry); } } } + else + { + // Note: Since specCount < avgCount, there's at least one normal pawn. + var entry = normals.list.RandomElement(); + var pawn = entry.pawn; + DebugMessage(rgpMsgPrefix + "Destroyed normal non-trader pawn {entry}"); + normals.Remove(entry); + pawn.DestroyOrPassToWorld(); + pawns.Remove(pawn); + DebugAdd(ref destroyed, entry, addToList: false); + } } - avgCombatPoints = tempAvgCombatPoints; - specCombatPoints = tempSpecCombatPoints; - -// Log.Message("------------"); -// Log.Message("Final Report"); -// Log.Message("------------"); -// Log.Message("Scenario Points: " + previousPoints + ". Total Points: " + tempAvgCombatPoints.Sum(x => x.Value) + tempSpecCombatPoints.Sum(x => x.Value)); -// Log.Message("------------"); -// Log.Message("Characters"); -// Log.Message("------------------"); - __result.ForEach(x => - { - var combatValue = x.kindDef.combatPower + x?.TryGetComp()?.CombatPoints() ?? 0f; - //Log.Message(x.LabelShort + " : " + combatValue); - }); - foreach (var x in removedCharacters) - { - if (x.TryGetComp() is CompAbilityUser cu && cu.CombatPoints() > 0) - cu.DisableAbilityUser(); - else x.DestroyOrPassToWorld(); - } - removedCharacters.Clear(); - avgCombatPoints.Clear(); - specCombatPoints.Clear(); + DebugMessage(rgpMsgPrefix + "Result: #pawns = {pawns.Count}" + + pawns.Join(pawn => $"\n\t{PawnAbilityPointsEntry.For(pawn)}", "")); } } - //static HarmonyPatches() - //{ - - //} - - //Verse.ShortHashGiver + // Verse.ShortHashGiver public static bool GiveShortHash_PrePatch(Def def, Type defType) { - //Log.Message("Shorthash called"); + DebugMessage($"GiveShortHash_PrePatch({def}, {defType})"); if (def.shortHash != 0) - if (defType.IsAssignableFrom(typeof(AbilityDef)) || defType == typeof(AbilityDef) || - def is AbilityDef) + if (def is AbilityDef || typeof(AbilityDef).IsAssignableFrom(defType)) return false; return true; } - public static void Notify_EquipmentAdded_PostFix(Pawn_EquipmentTracker __instance, ThingWithComps eq) - { - foreach (var cai in eq.GetComps() - ) //((Pawn)__instance.ParentHolder).GetComps() ) - //Log.Message("Notify_EquipmentAdded_PostFix 1 : "+eq.ToString()); - //Log.Message(" Found CompAbilityItem, for CompAbilityUser of "+cai.Props.AbilityUserClass.ToString()); - - foreach (var cau in ((Pawn) __instance.ParentHolder).GetComps()) - //Log.Message(" Found CompAbilityUser, "+cau.ToString() +" : "+ cau.GetType()+":"+cai.Props.AbilityUserClass ); //Props.AbilityUserTarget.ToString()); - if (cau.GetType() == cai.Props.AbilityUserClass) - { - //Log.Message(" and they match types " ); - cai.AbilityUserTarget = cau; - foreach (var abdef in cai.Props.Abilities) cau.AddWeaponAbility(abdef); - } - } - - public static void Notify_EquipmentRemoved_PostFix(Pawn_EquipmentTracker __instance, ThingWithComps eq) - { - foreach (var cai in eq.GetComps() - ) //((Pawn)__instance.ParentHolder).GetComps() ) - //Log.Message("Notify_EquipmentAdded_PostFix 1 : "+eq.ToString()); - //Log.Message(" Found CompAbilityItem, for CompAbilityUser of "+cai.Props.AbilityUserClass.ToString()); - - foreach (var cau in ((Pawn) __instance.ParentHolder).GetComps()) - //Log.Message(" Found CompAbilityUser, "+cau.ToString() +" : "+ cau.GetType()+":"+cai.Props.AbilityUserClass ); //Props.AbilityUserTarget.ToString()); - if (cau.GetType() == cai.Props.AbilityUserClass) - foreach (var abdef in cai.Props.Abilities) cau.RemoveWeaponAbility(abdef); - } - - public static void Notify_ApparelAdded_PostFix(Pawn_ApparelTracker __instance, Apparel apparel) - { - foreach (var cai in apparel.GetComps() - ) //((Pawn)__instance.ParentHolder).GetComps() ) - foreach (var cau in ((Pawn) __instance.ParentHolder).GetComps()) - if (cau.GetType() == cai.Props.AbilityUserClass) - { - cai.AbilityUserTarget = cau; - foreach (var abdef in cai.Props.Abilities) cau.AddApparelAbility(abdef); - } - } - - public static void Notify_ApparelRemoved_PostFix(Pawn_ApparelTracker __instance, Apparel apparel) - { - foreach (var cai in apparel.GetComps() - ) //((Pawn)__instance.ParentHolder).GetComps() ) - foreach (var cau in ((Pawn) __instance.ParentHolder).GetComps()) - if (cau.GetType() == cai.Props.AbilityUserClass) - foreach (var abdef in cai.Props.Abilities) cau.RemoveApparelAbility(abdef); - } - // RimWorld.Targeter - public static bool ConfirmStillValid(Targeter __instance) + public static bool ConfirmStillValid(Targeter __instance, Pawn ___caster) { - if (__instance.targetingSource is Verb_UseAbility) + if (__instance.targetingSource is Verb_UseAbility v) { - var caster = Traverse.Create(__instance).Field("caster").GetValue(); - - if (caster != null && (caster.Map != Find.CurrentMap || caster.Destroyed || - !Find.Selector.IsSelected(caster) || - caster.Faction != Faction.OfPlayerSilentFail)) + if (___caster != null && (___caster.Map != Find.CurrentMap || ___caster.Destroyed || + !Find.Selector.IsSelected(___caster) || + ___caster.Faction != Faction.OfPlayerSilentFail)) // TODO: is this last condition still needed? __instance.StopTargeting(); - if (__instance.targetingSource != null) + if (v != null) { var selector = Find.Selector; - if (__instance.targetingSource.CasterPawn.Map != Find.CurrentMap || - __instance.targetingSource.CasterPawn.Destroyed || - !selector.IsSelected(__instance.targetingSource.CasterPawn)) + if (v.Caster.Map != Find.CurrentMap || + v.Caster.Destroyed || + !selector.IsSelected(v.Caster) || + (!v.GetVerb?.Available() ?? false)) { __instance.StopTargeting(); } else { - if (!__instance.targetingSourceAdditionalPawns.NullOrEmpty()) - for (var i = 0; i < __instance.targetingSourceAdditionalPawns.Count; i++) - if (__instance.targetingSourceAdditionalPawns[i].Destroyed || - !selector.IsSelected(__instance.targetingSourceAdditionalPawns[i])) + if (__instance.targetingSourceAdditionalPawns != null) + foreach (var additionalPawn in __instance.targetingSourceAdditionalPawns) + if (additionalPawn.Destroyed || !selector.IsSelected(additionalPawn)) { __instance.StopTargeting(); break; @@ -383,84 +413,75 @@ public static bool ConfirmStillValid(Targeter __instance) return true; } - // RimWorld.Targeter - public static bool ProcessInputEvents_PreFix(Targeter __instance) + public static bool ProcessInputEvents_PreFix(Targeter __instance, Func ___targetValidator, + bool ___playSoundOnAction, ref bool ___needsStopTargetingCall) { if (__instance.targetingSource is Verb_UseAbility v) { if (v.UseAbilityProps.AbilityTargetCategory == AbilityTargetCategory.TargetSelf) { - var caster = (Pawn) __instance.targetingSource.CasterPawn; - v.Ability.TryCastAbility(AbilityContext.Player, - caster); // caster, source.First(), caster.GetComp(), (Verb_UseAbility)__instance.targetingSource, ((Verb_UseAbility)(__instance.targetingSource)).ability.powerdef as AbilityDef)?.Invoke(); - SoundDefOf.Tick_High.PlayOneShotOnCamera(); + var caster = v.Caster; + v.Ability.TryCastAbility(AbilityContext.Player, caster); + if (___playSoundOnAction) + SoundDefOf.Tick_High.PlayOneShotOnCamera(); __instance.StopTargeting(); Event.current.Use(); return false; } - AccessTools.Method(typeof(Targeter), "ConfirmStillValid").Invoke(__instance, null); - if (Event.current.type == EventType.MouseDown) - if (Event.current.button == 0 && __instance.IsTargeting) + targeterConfirmStillValidMethod(__instance); + if (!__instance.IsTargeting) + return false; + if (Event.current.type == EventType.MouseDown && Event.current.button == 0) + { + var target = targeterCurrentTargetUnderMouseMethod(__instance, false); + ___needsStopTargetingCall = true; + if (!v.ValidateTarget(target)) { - var obj = (LocalTargetInfo) AccessTools.Method(typeof(Targeter), "CurrentTargetUnderMouse") - .Invoke(__instance, new object[] {false}); - if (obj.IsValid) - v.Ability.TryCastAbility(AbilityContext.Player, obj); - SoundDefOf.Tick_High.PlayOneShotOnCamera(null); - __instance.StopTargeting(); Event.current.Use(); return false; - //if (__instance.targetingSource is Verb_UseAbility) - //{ - // Verb_UseAbility abilityVerb = __instance.targetingSource as Verb_UseAbility; - // if (abilityVerb.Ability.Def.MainVerb.AbilityTargetCategory != AbilityTargetCategory.TargetSelf) - // { - // TargetingParameters targetParams = abilityVerb.Ability.Def.MainVerb.targetParams; - // if (targetParams != null) - // { - // IEnumerable source = GenUI.TargetsAtMouse(targetParams, false); - - // if (source != null && source.Count() > 0) - // { - - // if (source.Any()) - // { - - // Pawn caster = (Pawn)__instance.targetingSource.caster; - // abilityVerb.Ability.TryCastAbility(AbilityContext.Player, source.First());// caster, source.First(), caster.GetComp(), (Verb_UseAbility)__instance.targetingSource, ((Verb_UseAbility)(__instance.targetingSource)).ability.powerdef as AbilityDef)?.Invoke(); - // SoundDefOf.Tick_High.PlayOneShotOnCamera(); - // __instance.StopTargeting(); - // Event.current.Use(); - // return false; - // } - // } - // } - // } - // else - // { - // Pawn caster = (Pawn)__instance.targetingSource.caster; - // abilityVerb.Ability.TryCastAbility(AbilityContext.Player, null);// caster.GetComp(), (Verb_UseAbility)__instance.targetingSource, ((Verb_UseAbility)(__instance.targetingSource)).ability.powerdef as AbilityDef)?.Invoke(); - // SoundDefOf.Tick_High.PlayOneShotOnCamera(); - // __instance.StopTargeting(); - // Event.current.Use(); - // return false; - // } - //} - //} } + if (___targetValidator != null) + { + if (___targetValidator(target)) + v.Ability.TryCastAbility(AbilityContext.Player, target); + else + ___needsStopTargetingCall = false; + } + else if (target.IsValid) + v.Ability.TryCastAbility(AbilityContext.Player, target); + if (___playSoundOnAction) + SoundDefOf.Tick_High.PlayOneShotOnCamera(null); + if (v.DestinationSelector != null) + __instance.BeginTargeting(v.DestinationSelector, v); + else if (v.MultiSelect && Event.current.shift) + __instance.BeginTargeting(v); + else if (__instance.targetingSourceParent != null && __instance.targetingSourceParent.MultiSelect && Event.current.shift) + __instance.BeginTargeting(__instance.targetingSourceParent); + if (___needsStopTargetingCall) + __instance.StopTargeting(); + Event.current.Use(); + return false; + } } return true; } + // Note: These are open instance delegates where the first argument is the instance. + private static readonly Action targeterConfirmStillValidMethod = + (Action)AccessTools.Method(typeof(Targeter), "ConfirmStillValid").CreateDelegate(typeof(Action)); + private static readonly Func targeterCurrentTargetUnderMouseMethod = + (Func)AccessTools.Method(typeof(Targeter), "CurrentTargetUnderMouse") + .CreateDelegate(typeof(Func)); + public static void TargeterUpdate_PostFix(Targeter __instance) { if (__instance.targetingSource is Verb_UseAbility tVerb && tVerb.verbProps is VerbProperties_Ability tVerbProps) { - if (tVerbProps?.range > 0) - GenDraw.DrawRadiusRing(tVerb.CasterPawn.PositionHeld, tVerbProps.range); - if (tVerbProps?.TargetAoEProperties?.range > 0 && Find.CurrentMap is Map map && + if (tVerbProps.range > 0) + GenDraw.DrawRadiusRing(tVerb.Caster.PositionHeld, tVerbProps.range); + if (tVerbProps.TargetAoEProperties?.range > 0 && Find.CurrentMap is Map map && UI.MouseCell().InBounds(map)) GenDraw.DrawRadiusRing(UI.MouseCell(), tVerbProps.TargetAoEProperties.range); } @@ -468,23 +489,15 @@ public static void TargeterUpdate_PostFix(Targeter __instance) public static void InitializeComps_PostFix(ThingWithComps __instance) { - if (__instance is Pawn p) InternalAddInAbilityUsers(p); + if (__instance is Pawn p) + InternalAddInAbilityUsers(p); } - //// Catches loading of Pawns - //public static void ExposeData_PostFix(Pawn __instance) - //{ HarmonyPatches.internalAddInAbilityUsers(__instance); } - - //// Catches generation of Pawns - //public static void GeneratePawn_PostFix(PawnGenerationRequest request, Pawn __result) - //{ HarmonyPatches.internalAddInAbilityUsers(__result); } - // Add in any AbilityUser Components, if the Pawn is accepting public static void InternalAddInAbilityUsers(Pawn pawn) { - // Log.Message("Trying to add AbilityUsers to Pawn"); if (pawn != null && pawn.RaceProps != null && pawn.RaceProps.Humanlike) AbilityUserUtility.TransformPawn(pawn); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompActivatableEffect/ActivatableEffectUtility.cs b/Source/AllModdingComponents/CompActivatableEffect/ActivatableEffectUtility.cs new file mode 100644 index 00000000..4d4360c3 --- /dev/null +++ b/Source/AllModdingComponents/CompActivatableEffect/ActivatableEffectUtility.cs @@ -0,0 +1,21 @@ +using Verse; + +namespace CompActivatableEffect +{ + public static class ActivatableEffectUtility + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static CompActivatableEffect GetCompActivatableEffect(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompActivatableEffect comp) + return comp; + } + return null; + } + } +} diff --git a/Source/AllModdingComponents/CompActivatableEffect/CompActivatableEffect.cs b/Source/AllModdingComponents/CompActivatableEffect/CompActivatableEffect.cs index 18f6dda1..e2256777 100644 --- a/Source/AllModdingComponents/CompActivatableEffect/CompActivatableEffect.cs +++ b/Source/AllModdingComponents/CompActivatableEffect/CompActivatableEffect.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using HarmonyLib; using RimWorld; using UnityEngine; using Verse; @@ -6,6 +8,7 @@ namespace CompActivatableEffect { + public class CompActivatableEffect : CompUseEffect { public enum State @@ -14,18 +17,33 @@ public enum State Activated } + public CompProperties_ActivatableEffect Props => (CompProperties_ActivatableEffect)props; + private State currentState = State.Deactivated; public bool IsInitialized; private Sustainer sustainer; - public CompEquippable GetEquippable => parent.GetComp(); + private CompEquippable compEquippable; + private Func compDeflectorIsAnimatingNow; + private Func compDeflectorAnimationDeflectionTicks; + private CompOversizedWeapon.CompOversizedWeapon compOversizedWeapon; + + private static readonly Type compDeflectorType = GenTypes.GetTypeInAnyAssembly("CompDeflector.CompDeflector"); - public Pawn GetPawn => GetEquippable.verbTracker.PrimaryVerb.CasterPawn; + public CompEquippable GetEquippable => compEquippable; + + public CompOversizedWeapon.CompOversizedWeapon GetOversizedWeapon => compOversizedWeapon; + + public Pawn GetPawn => GetEquippable.verbTracker.PrimaryVerb.CasterPawn; //public List GetVerbs => GetEquippable.verbTracker.AllVerbs; + public bool CompDeflectorIsAnimatingNow => compDeflectorIsAnimatingNow?.Invoke() ?? false; + + public int CompDeflectorAnimationDeflectionTicks => compDeflectorAnimationDeflectionTicks?.Invoke() ?? 0; + public bool GizmosOnEquip => Props.gizmosOnEquip; public State CurrentState => currentState; @@ -61,22 +79,15 @@ public virtual bool TryDeactivate() public virtual void PlaySound(SoundDef soundToPlay) { - SoundInfo info; - if (Props.gizmosOnEquip) - info = SoundInfo.InMap(new TargetInfo(GetPawn.PositionHeld, GetPawn.MapHeld, false), - MaintenanceType.None); - else - info = SoundInfo.InMap(new TargetInfo(parent.PositionHeld, parent.MapHeld, false), - MaintenanceType.None); - soundToPlay?.PlayOneShot(info); + var pawn = Props.gizmosOnEquip ? GetPawn : parent; + soundToPlay?.PlayOneShot(SoundInfo.InMap(new TargetInfo(pawn.PositionHeld, pawn.MapHeld))); } private void StartSustainer() { - if (!Props.sustainerSound.NullOrUndefined() && sustainer == null) + if (!Props.sustainerSound.NullOrUndefined()) { - var info = SoundInfo.InMap(GetPawn, MaintenanceType.None); - sustainer = Props.sustainerSound.TrySpawnSustainer(info); + sustainer ??= Props.sustainerSound.TrySpawnSustainer(SoundInfo.InMap(GetPawn)); } } @@ -93,7 +104,8 @@ public virtual void Activate() { graphicInt = null; currentState = State.Activated; - if (Props.activateSound != null) PlaySound(Props.activateSound); + if (Props.activateSound != null) + PlaySound(Props.activateSound); StartSustainer(); showNow = true; } @@ -101,7 +113,8 @@ public virtual void Activate() public virtual void Deactivate() { currentState = State.Deactivated; - if (Props.deactivateSound != null) PlaySound(Props.deactivateSound); + if (Props.deactivateSound != null) + PlaySound(Props.deactivateSound); EndSustainer(); showNow = false; graphicInt = null; @@ -109,10 +122,56 @@ public virtual void Deactivate() public bool IsActive() { - if (currentState == State.Activated) return true; - return false; + return currentState == State.Activated; + } + + // Caching comps needs to happen after all comps are created. Ideally, this would be done right after + // ThingWithComps.InitializeComps(). This requires overriding two hooks: PostPostMake and PostExposeData. + + public override void PostPostMake() + { + base.PostPostMake(); + CacheComps(); } + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref showNow, nameof(showNow)); + Scribe_Values.Look(ref currentState, nameof(currentState)); + if (Scribe.mode == LoadSaveMode.LoadingVars) + CacheComps(); + } + + private void CacheComps() + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + // For the optional CompDeflector, we have to use the slower IsAssignableFrom reflection check. + var comps = parent.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + var comp = comps[i]; + if (comp is CompEquippable compEquippable) + this.compEquippable = compEquippable; + else if (comp is CompOversizedWeapon.CompOversizedWeapon compOversizedWeapon) + this.compOversizedWeapon = compOversizedWeapon; + else if (compDeflectorType != null) + { + var compType = comp.GetType(); + if (compDeflectorType.IsAssignableFrom(compType)) + { + compDeflectorIsAnimatingNow = + (Func)AccessTools.PropertyGetter(compType, "IsAnimatingNow").CreateDelegate(typeof(Func), comp); + compDeflectorAnimationDeflectionTicks = + (Func)AccessTools.PropertyGetter(compType, "AnimationDeflectionTicks").CreateDelegate(typeof(Func), comp); + } + } + } + } + + // This is called on the first tick - not rolled into above Initialize since it's still needed in case subclasses implement it. public virtual void Initialize() { IsInitialized = true; @@ -121,8 +180,10 @@ public virtual void Initialize() public override void CompTick() { - if (!IsInitialized) Initialize(); - if (IsActive()) ActiveTick(); + if (!IsInitialized) + Initialize(); + if (IsActive()) + ActiveTick(); base.CompTick(); } @@ -139,14 +200,14 @@ public IEnumerable EquippedGizmos() { defaultLabel = Props.DeactivateLabel, icon = IconDeactivate, - action = delegate { TryDeactivate(); } + action = () => TryDeactivate(), }; else yield return new Command_Action { defaultLabel = Props.ActivateLabel, icon = IconActivate, - action = delegate { TryActivate(); } + action = () => TryActivate(), }; } @@ -154,29 +215,19 @@ public override IEnumerable CompGetGizmosExtra() { if (!GizmosOnEquip) { - //Iterate Base Functions - var enumerator = base.CompGetGizmosExtra().GetEnumerator(); - while (enumerator.MoveNext()) - { - var current = enumerator.Current; + foreach (var current in base.CompGetGizmosExtra()) yield return current; - } - //Iterate ActivationActions - var enumerator2 = EquippedGizmos().GetEnumerator(); - while (enumerator2.MoveNext()) - { - var current = enumerator2.Current; + foreach (var current in EquippedGizmos()) yield return current; - } } } - public override void PostExposeData() + public override void Notify_Unequipped(Pawn pawn) { - base.PostExposeData(); - Scribe_Values.Look(ref showNow, "showNow", false); - Scribe_Values.Look(ref currentState, "currentState", State.Deactivated); + base.Notify_Unequipped(pawn); + if (CurrentState == State.Activated) + TryDeactivate(); } #region Graphics @@ -191,44 +242,26 @@ public bool ShowNow get => showNow; } - public Texture2D IconActivate - { - get - { - var resolvedTexture = TexCommand.GatherSpotActive; - if (!Props.uiIconPathActivate.NullOrEmpty()) - resolvedTexture = ContentFinder.Get(Props.uiIconPathActivate, true); - return resolvedTexture; - } - } - - public Texture2D IconDeactivate - { - get - { - var resolvedTexture = TexCommand.ClearPrioritizedWork; - if (!Props.uiIconPathDeactivate.NullOrEmpty()) - resolvedTexture = ContentFinder.Get(Props.uiIconPathDeactivate, true); - return resolvedTexture; - } - } + public Texture2D IconActivate => !Props.uiIconPathActivate.NullOrEmpty() + ? ContentFinder.Get(Props.uiIconPathActivate) + : TexCommand.GatherSpotActive; - public CompProperties_ActivatableEffect Props => (CompProperties_ActivatableEffect) props; + public Texture2D IconDeactivate => !Props.uiIconPathDeactivate.NullOrEmpty() + ? ContentFinder.Get(Props.uiIconPathDeactivate) + : TexCommand.ClearPrioritizedWork; public virtual Graphic Graphic { set => graphicInt = value; get { - Graphic badGraphic; if (graphicInt == null) { if (Props.graphicData == null) { Log.ErrorOnce(parent.def + " has no SecondLayer graphicData but we are trying to access it.", 764532); - badGraphic = BaseContent.BadGraphic; - return badGraphic; + return BaseContent.BadGraphic; } var newColor1 = overrideColor == Color.white ? parent.DrawColor : overrideColor; var newColor2 = overrideColor == Color.white ? parent.DrawColorTwo : overrideColor; @@ -236,8 +269,7 @@ public virtual Graphic Graphic Props.graphicData.Graphic.GetColoredVersion(parent.Graphic.Shader, newColor1, newColor2); graphicInt = PostGraphicEffects(graphicInt); } - badGraphic = graphicInt; - return badGraphic; + return graphicInt; } } @@ -251,23 +283,7 @@ public override void PostDraw() base.PostDraw(); if (ShowNow) { - //float parentRotation = 0.0f; - - //if (this.parent.Graphic != null) - //{ - // if (this.parent.Graphic.data != null) - // { - // parentRotation = this.parent.Graphic.data.onGroundRandomRotateAngle; - // } - // else Log.ErrorOnce("ProjectJedi.CompActivatableEffect :: this.parent.graphic.data Null Reference", 7887); - //} - - //if (parentRotation > 0.01f) - //{ Graphic = new Graphic_RandomRotated(Graphic, 35f); - //} - - Graphic.Draw(GenThing.TrueCenter(parent.Position, parent.Rotation, parent.def.size, Props.Altitude), parent.Rotation, parent); } @@ -275,4 +291,4 @@ public override void PostDraw() #endregion Graphics } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompActivatableEffect/CompActivatableEffect.csproj b/Source/AllModdingComponents/CompActivatableEffect/CompActivatableEffect.csproj index 84ae7644..84d64e13 100755 --- a/Source/AllModdingComponents/CompActivatableEffect/CompActivatableEffect.csproj +++ b/Source/AllModdingComponents/CompActivatableEffect/CompActivatableEffect.csproj @@ -1,63 +1,12 @@  - - + + - Debug - AnyCPU {EC1AEA45-45FE-4A6A-A835-81B289E03BC9} - Library - Properties CompActivatableEffect CompActivatableEffect - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - - {08e20d0e-4493-4dfe-9212-dec323f26e89} - CompOversizedWeapon - - - - 1.1.2566 - - - 2.0.0.8 - + - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompActivatableEffect/CompProperties_ActivatableEffect.cs b/Source/AllModdingComponents/CompActivatableEffect/CompProperties_ActivatableEffect.cs index e8214f2a..d210163d 100644 --- a/Source/AllModdingComponents/CompActivatableEffect/CompProperties_ActivatableEffect.cs +++ b/Source/AllModdingComponents/CompActivatableEffect/CompProperties_ActivatableEffect.cs @@ -30,4 +30,4 @@ public CompProperties_ActivatableEffect() public float Altitude => Altitudes.AltitudeFor(altitudeLayer); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompActivatableEffect/HarmonyCompActivatableEffect.cs b/Source/AllModdingComponents/CompActivatableEffect/HarmonyCompActivatableEffect.cs index 540c37f3..9ee3df9f 100644 --- a/Source/AllModdingComponents/CompActivatableEffect/HarmonyCompActivatableEffect.cs +++ b/Source/AllModdingComponents/CompActivatableEffect/HarmonyCompActivatableEffect.cs @@ -14,76 +14,29 @@ internal static class HarmonyCompActivatableEffect static HarmonyCompActivatableEffect() { var harmony = new Harmony("jecstools.jecrell.comps.activator"); - - harmony.Patch(typeof(Pawn).GetMethod("GetGizmos"), null, - new HarmonyMethod(typeof(HarmonyCompActivatableEffect).GetMethod("GetGizmosPrefix"))); - - harmony.Patch(typeof(PawnRenderer).GetMethod("DrawEquipmentAiming"), null, - new HarmonyMethod(typeof(HarmonyCompActivatableEffect), nameof(DrawEquipmentAimingPostFix))); - + var type = typeof(HarmonyCompActivatableEffect); - harmony.Patch(AccessTools.Method(typeof(Verb), "TryStartCastOn", new[] { typeof(LocalTargetInfo), typeof(LocalTargetInfo), typeof(bool), typeof(bool)}), - new HarmonyMethod(typeof(HarmonyCompActivatableEffect), nameof(TryStartCastOnPrefix)), null); + harmony.Patch(AccessTools.Method(typeof(Pawn_EquipmentTracker), nameof(Pawn_EquipmentTracker.GetGizmos)), + postfix: new HarmonyMethod(type, nameof(GetGizmosPostfix))); - - harmony.Patch(typeof(Pawn_DraftController).GetMethod("set_Drafted"), null, - new HarmonyMethod(typeof(HarmonyCompActivatableEffect).GetMethod("set_DraftedPostFix"))); + harmony.Patch(AccessTools.Method(typeof(PawnRenderer), nameof(PawnRenderer.DrawEquipmentAiming)), + postfix: new HarmonyMethod(type, nameof(DrawEquipmentAimingPostFix))); -<<<<<<< Updated upstream - - harmony.Patch(typeof(Pawn).GetMethod("ExitMap"), - new HarmonyMethod(typeof(HarmonyCompActivatableEffect).GetMethod("ExitMap_PreFix")), null); -======= harmony.Patch(AccessTools.Method(typeof(Verb), nameof(Verb.TryStartCastOn), new[] { typeof(LocalTargetInfo), typeof(LocalTargetInfo), typeof(bool), typeof(bool), typeof(bool), typeof(bool) }), prefix: new HarmonyMethod(type, nameof(TryStartCastOnPrefix))); ->>>>>>> Stashed changes - - harmony.Patch(typeof(Pawn_EquipmentTracker).GetMethod("TryDropEquipment"), - new HarmonyMethod(typeof(HarmonyCompActivatableEffect).GetMethod("TryDropEquipment_PreFix")), null); + harmony.Patch(AccessTools.PropertySetter(typeof(Pawn_DraftController), nameof(Pawn_DraftController.Drafted)), + postfix: new HarmonyMethod(type, nameof(set_DraftedPostFix))); - - harmony.Patch(typeof(Pawn_DraftController).GetMethod("set_Drafted"), null, - new HarmonyMethod(typeof(HarmonyCompActivatableEffect).GetMethod("set_DraftedPostFix"))); + harmony.Patch(AccessTools.Method(typeof(Pawn), nameof(Pawn.ExitMap)), + prefix: new HarmonyMethod(type, nameof(ExitMap_PreFix))); } -<<<<<<< Updated upstream - //=================================== COMPACTIVATABLE - - // Verse.Pawn_EquipmentTracker - public static void TryDropEquipment_PreFix(Pawn_EquipmentTracker __instance, ThingWithComps eq) - { - if (__instance is Pawn_EquipmentTracker eqq && - eqq.Primary is ThingWithComps t && - t.GetComp() is CompActivatableEffect compActivatableEffect && - compActivatableEffect.CurrentState == CompActivatableEffect.State.Activated) - compActivatableEffect.TryDeactivate(); - } - - public static void ExitMap_PreFix(Pawn __instance, bool allowedToJoinOrCreateCaravan) - { - if (__instance is Pawn p && p.equipment is Pawn_EquipmentTracker eq && - eq.Primary is ThingWithComps t && - t.GetComp() is CompActivatableEffect compActivatableEffect && - compActivatableEffect.CurrentState == CompActivatableEffect.State.Activated) - compActivatableEffect.TryDeactivate(); - } - -#pragma warning disable IDE1006 // Naming Styles - public static void set_DraftedPostFix(Pawn_DraftController __instance, bool value) -#pragma warning restore IDE1006 // Naming Styles - { - if (__instance.pawn is Pawn p && p.equipment is Pawn_EquipmentTracker eq && - eq.Primary is ThingWithComps t && - t.GetComp() is CompActivatableEffect compActivatableEffect) - if (value == false) -======= public static void GetGizmosPostfix(Pawn_EquipmentTracker __instance, ref IEnumerable __result) { if (__instance.Primary?.GetCompActivatableEffect() is CompActivatableEffect compActivatableEffect) if (__instance.pawn.Faction == Faction.OfPlayer) ->>>>>>> Stashed changes { if (compActivatableEffect.GizmosOnEquip) __result = __result.Concat(compActivatableEffect.EquippedGizmos()); @@ -91,192 +44,70 @@ public static void GetGizmosPostfix(Pawn_EquipmentTracker __instance, ref IEnume else { if (compActivatableEffect.CurrentState == CompActivatableEffect.State.Deactivated) -<<<<<<< Updated upstream - compActivatableEffect.TryActivate(); - } - } - - public static bool TryStartCastOnPrefix(ref bool __result, Verb __instance) - { - if (__instance.caster is Pawn pawn) - { - var pawn_EquipmentTracker = pawn?.equipment; - if (pawn_EquipmentTracker == null) return true; - - var thingWithComps = - pawn_EquipmentTracker?.Primary; //(ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); - - var compActivatableEffect = thingWithComps?.GetComp(); - if (compActivatableEffect == null) return true; - - //Equipment source throws errors when checked while casting abilities with a weapon equipped. - // to avoid this error preventing our code from executing, we do a try/catch. - try - { - if (__instance?.EquipmentSource != thingWithComps) - return true; - } - catch (Exception e) - { - } - - if (compActivatableEffect.CurrentState == CompActivatableEffect.State.Activated) - return true; - else if (compActivatableEffect.TryActivate()) - return true; - if (Find.TickManager.TicksGame % 250 == 0) - Messages.Message("DeactivatedWarning".Translate(pawn.Label), - MessageTypeDefOf.RejectInput); - __result = false; - return false; - } - return true; -======= compActivatableEffect.Activate(); } ->>>>>>> Stashed changes } - ///// - ///// Prevents the user from having damage with the verb. - ///// - ///// - ///// - ///// - //public static void GetDamageFactorForPostFix(Verb __instance, ref float __result, Pawn pawn) - //{ - // Pawn_EquipmentTracker pawn_EquipmentTracker = pawn.equipment; - // if (pawn_EquipmentTracker != null) - // { - // //Log.Message("2"); - // ThingWithComps thingWithComps = (ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); - - // if (thingWithComps != null) - // { - // //Log.Message("3"); - // CompActivatableEffect compActivatableEffect = thingWithComps.GetComp(); - // if (compActivatableEffect != null) - // { - // if (compActivatableEffect.CurrentState != CompActivatableEffect.State.Activated) - // { - // //Messages.Message("DeactivatedWarning".Translate(), MessageSound.RejectInput); - // __result = 0f; - // } - // } - // } - // } - //} - - /// /// Adds another "layer" to the equipment aiming if they have a /// weapon with a CompActivatableEffect. /// - /// - /// - /// - /// - public static void DrawEquipmentAimingPostFix(PawnRenderer __instance, Thing eq, Vector3 drawLoc, + public static void DrawEquipmentAimingPostFix(Pawn ___pawn, Thing eq, Vector3 drawLoc, float aimAngle) { - var pawn = (Pawn) AccessTools.Field(typeof(PawnRenderer), "pawn").GetValue(__instance); - - var pawn_EquipmentTracker = pawn.equipment; - var thingWithComps = - pawn_EquipmentTracker?.Primary; //(ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); + var compActivatableEffect = ___pawn.equipment?.Primary?.GetCompActivatableEffect(); + if (compActivatableEffect?.Graphic == null || + compActivatableEffect.CurrentState != CompActivatableEffect.State.Activated) + return; - var compActivatableEffect = thingWithComps?.GetComp(); - if (compActivatableEffect?.Graphic == null) return; - if (compActivatableEffect.CurrentState != CompActivatableEffect.State.Activated) return; - var num = aimAngle - 90f; + // start copied vanilla code (with mesh = flip ? MeshPool.plane10Flip : MeshPool.plane10) var flip = false; - + var angle = aimAngle - 90f; if (aimAngle > 20f && aimAngle < 160f) { - //mesh = MeshPool.GridPlaneFlip(thingWithComps.def.graphicData.drawSize); - num += eq.def.equippedAngleOffset; + angle += eq.def.equippedAngleOffset; } else if (aimAngle > 200f && aimAngle < 340f) { - //mesh = MeshPool.GridPlane(thingWithComps.def.graphicData.drawSize); flip = true; - num -= 180f; - num -= eq.def.equippedAngleOffset; + angle -= 180f; + angle -= eq.def.equippedAngleOffset; } else { - //mesh = MeshPool.GridPlaneFlip(thingWithComps.def.graphicData.drawSize); - num += eq.def.equippedAngleOffset; + angle += eq.def.equippedAngleOffset; } + // end copied vanilla code - Vector3 offset = Vector3.zero; + var offset = Vector3.zero; - if (eq is ThingWithComps eqComps) + var weaponComp = compActivatableEffect.GetOversizedWeapon; + if (weaponComp != null) { - if (eqComps.AllComps.FirstOrDefault(z => z is CompOversizedWeapon.CompOversizedWeapon) is - CompOversizedWeapon.CompOversizedWeapon weaponComp) - { - if (pawn.Rotation == Rot4.East) - offset = weaponComp.Props.eastOffset; - else if (pawn.Rotation == Rot4.West) - offset = weaponComp.Props.westOffset; - else if (pawn.Rotation == Rot4.North) - offset = weaponComp.Props.northOffset; - else if (pawn.Rotation == Rot4.South) - offset = weaponComp.Props.southOffset; - offset += weaponComp.Props.offset; - } - - - var deflector = eqComps.AllComps.FirstOrDefault(y => - y.GetType().ToString().Contains("Deflect")); - if (deflector != null) + offset = OffsetFromRotation(weaponComp.Props, ___pawn.Rotation); + } + + if (compActivatableEffect.CompDeflectorIsAnimatingNow) + { + float animationTicks = compActivatableEffect.CompDeflectorAnimationDeflectionTicks; + if (animationTicks > 0) { - var isActive = (bool) AccessTools - .Property(deflector.GetType(), "IsAnimatingNow").GetValue(deflector, null); - if (isActive) - { - float numMod = (int) AccessTools - .Property(deflector.GetType(), "AnimationDeflectionTicks") - .GetValue(deflector, null); - //float numMod2 = new float(); - //numMod2 = numMod; - if (numMod > 0) - if (!flip) num += (numMod + 1) / 2; - else num -= (numMod + 1) / 2; - } + if (flip) + angle -= (animationTicks + 1) / 2; + else + angle += (animationTicks + 1) / 2; } } - num %= 360f; - //ThingWithComps eqComps = eq as ThingWithComps; - //if (eqComps != null) - //{ - // ThingComp deflector = eqComps.AllComps.FirstOrDefault((ThingComp y) => y.GetType().ToString() == "CompDeflector.CompDeflector"); - // if (deflector != null) - // { - // float numMod = (float)((int)AccessTools.Property(deflector.GetType(), "AnimationDeflectionTicks").GetValue(deflector, null)); - // //Log.ErrorOnce("NumMod " + numMod.ToString(), 1239); - //numMod = (numMod + 1) / 2; - //if (subtract) num -= numMod; - //else num += numMod; - // } - //} + angle %= 360f; // copied vanilla code var matSingle = compActivatableEffect.Graphic.MatSingle; - //if (mesh == null) mesh = MeshPool.GridPlane(thingWithComps.def.graphicData.drawSize); var s = new Vector3(eq.def.graphicData.drawSize.x, 1f, eq.def.graphicData.drawSize.y); - var matrix = default(Matrix4x4); - matrix.SetTRS(drawLoc + offset, Quaternion.AngleAxis(num, Vector3.up), s); - if (!flip) Graphics.DrawMesh(MeshPool.plane10, matrix, matSingle, 0); - else Graphics.DrawMesh(MeshPool.plane10Flip, matrix, matSingle, 0); - //Graphics.DrawMesh(mesh, drawLoc, Quaternion.AngleAxis(num, Vector3.up), matSingle, 0); + var matrix = Matrix4x4.TRS(drawLoc + offset, Quaternion.AngleAxis(angle, Vector3.up), s); + Graphics.DrawMesh(flip ? MeshPool.plane10Flip : MeshPool.plane10, matrix, matSingle, 0); } -<<<<<<< Updated upstream - public static IEnumerable GizmoGetter(CompActivatableEffect compActivatableEffect) -======= public static bool TryStartCastOnPrefix(ref bool __result, Verb __instance) { @@ -337,53 +168,16 @@ public static void set_DraftedPostFix(Pawn_DraftController __instance, bool valu // Workaround for mod lists that contain other mods with an outdated copy of CompOversizedWeapon that's loaded before ours: // avoid calling new code that's in our version. private static Vector3 OffsetFromRotation(CompOversizedWeapon.CompProperties_OversizedWeapon weaponComp, Rot4 rotation) ->>>>>>> Stashed changes { - //Log.Message("5"); - if (compActivatableEffect.GizmosOnEquip) - { - //Log.Message("6"); - //Iterate EquippedGizmos - var enumerator = compActivatableEffect.EquippedGizmos().GetEnumerator(); - while (enumerator.MoveNext()) - { - //Log.Message("7"); - var current = enumerator.Current; - yield return current; - } - } + if (rotation == Rot4.North) + return weaponComp.northOffset; + else if (rotation == Rot4.East) + return weaponComp.eastOffset; + else if (rotation == Rot4.West) + return weaponComp.westOffset; + else + return weaponComp.southOffset; } -<<<<<<< Updated upstream - public static void GetGizmosPrefix(Pawn __instance, ref IEnumerable __result) - { - //Log.Message("1"); - var pawn_EquipmentTracker = __instance.equipment; - if (pawn_EquipmentTracker != null) - { - //Log.Message("2"); - //ThingWithComps thingWithComps = (ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); - var thingWithComps = pawn_EquipmentTracker.Primary; - - if (thingWithComps != null) - { - //Log.Message("3"); - var compActivatableEffect = thingWithComps.GetComp(); - if (compActivatableEffect != null) - if (__instance != null) - if (__instance.Faction == Faction.OfPlayer) - { - __result = __result.Concat(GizmoGetter(compActivatableEffect)); - } - else - { - if (compActivatableEffect.CurrentState == CompActivatableEffect.State.Deactivated) - compActivatableEffect.Activate(); - } - } - } - } -======= ->>>>>>> Stashed changes } } diff --git a/Source/AllModdingComponents/CompAnimated/CompAnimated.cs b/Source/AllModdingComponents/CompAnimated/CompAnimated.cs index 47037668..52a71015 100644 --- a/Source/AllModdingComponents/CompAnimated/CompAnimated.cs +++ b/Source/AllModdingComponents/CompAnimated/CompAnimated.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using UnityEngine; using Verse; using Verse.Sound; @@ -13,22 +12,14 @@ public class CompAnimated : ThingComp public bool dirty; public int ticksToCycle = -1; - public int MaxFrameIndexMoving => Props.movingFrames.Count(); - public int MaxFrameIndexStill => Props.stillFrames.Count(); + public int MaxFrameIndexMoving => Props.movingFrames.Count; + public int MaxFrameIndexStill => Props.stillFrames.Count; - private static bool AsPawn(ThingWithComps pAnimatee, out Pawn pawn) - { - bool asPawn = pAnimatee is Pawn; - pawn = asPawn? (Pawn) pAnimatee : null; - return asPawn; - } - - /** - * render over thing when not a pawn; rather than use as base layer like the PawnGraphicSet does for the pawns graphics managment - */ + // render over thing when not a pawn; rather than use as base layer like the PawnGraphicSet does for the pawns graphics managment public override void PostDraw() { - if (parent is Pawn) return; + if (parent is Pawn) + return; base.PostDraw(); if (curGraphic != null) Render(); @@ -36,11 +27,11 @@ public override void PostDraw() public virtual void Render() { - Vector3 drawPos = this.parent.DrawPos; - curGraphic.Draw(drawPos, Rot4.North, this.parent, 0f); + var drawPos = parent.DrawPos; + curGraphic.Draw(drawPos, Rot4.North, parent, 0f); } - public CompProperties_Animated Props => (CompProperties_Animated) props; + public CompProperties_Animated Props => (CompProperties_Animated)props; public Graphic CurGraphic { @@ -73,10 +64,10 @@ public static Graphic ResolveCurGraphic(ThingWithComps pThingWithComps, CompProp { pTicksToCycle = Find.TickManager.TicksGame + pProps.secondsBetweenFrames.SecondsToTicks(); - bool asPawn = AsPawn(pThingWithComps, out var pAnimatee); - if (asPawn && (pAnimatee?.pather?.MovingNow ?? false)) + var pAnimatee = pThingWithComps as Pawn; + if (pAnimatee?.pather?.MovingNow ?? false) { - pCurIndex = (pCurIndex + 1) % pProps.movingFrames.Count(); + pCurIndex = (pCurIndex + 1) % pProps.movingFrames.Count; pProps.sound?.PlayOneShot(SoundInfo.InMap(pAnimatee)); result = ResolveCycledGraphic(pThingWithComps, pProps, pCurIndex); } @@ -85,12 +76,10 @@ public static Graphic ResolveCurGraphic(ThingWithComps pThingWithComps, CompProp if (!pProps.stillFrames.NullOrEmpty()) { //Log.Message("ticked still"); - pCurIndex = (pCurIndex + 1) % pProps.stillFrames.Count(); + pCurIndex = (pCurIndex + 1) % pProps.stillFrames.Count; result = ResolveCycledGraphic(pThingWithComps, pProps, pCurIndex); - pDirty = false; - return result; } - if (pAnimatee!=null && useBaseGraphic) + else if (pAnimatee != null && useBaseGraphic) result = ResolveBaseGraphic(pAnimatee); else result = ResolveCycledGraphic(pThingWithComps, pProps, pCurIndex); @@ -100,7 +89,7 @@ public static Graphic ResolveCurGraphic(ThingWithComps pThingWithComps, CompProp return result; } - /** Primary call to above */ + // Primary call to above private Graphic DefaultGraphic() { Graphic proxyGraphic = null; @@ -110,7 +99,7 @@ private Graphic DefaultGraphic() curGraphic = proxyGraphic; NotifyGraphicsChange(); } - + return resolveCurGraphic ?? curGraphic; } @@ -123,15 +112,15 @@ public static Graphic ResolveCycledGraphic(Pawn pAnimatee, CompProperties_Animat public static Graphic ResolveCycledGraphic(ThingWithComps pAnimatee, CompProperties_Animated pProps, int pCurIndex) { Graphic result = null; - bool haveMovingFrames = !pProps.movingFrames.NullOrEmpty(); - if (!pProps.movingFrames.NullOrEmpty() && - AsPawn(pAnimatee, out var pPawn) && + var haveMovingFrames = !pProps.movingFrames.NullOrEmpty(); + if (haveMovingFrames && + pAnimatee is Pawn pPawn && pPawn.Drawer?.renderer?.graphics is PawnGraphicSet pawnGraphicSet) { - /*Start Pawn*/ + // Start Pawn pawnGraphicSet.ClearCache(); - - if (haveMovingFrames && AsPawn(pAnimatee, out var p) && (p?.pather?.MovingNow ?? false)) + + if (pPawn.pather?.MovingNow ?? false) { result = pProps.movingFrames[pCurIndex].Graphic; pawnGraphicSet.nakedGraphic = result; @@ -141,15 +130,17 @@ public static Graphic ResolveCycledGraphic(ThingWithComps pAnimatee, CompPropert result = pProps.stillFrames[pCurIndex].Graphic; pawnGraphicSet.nakedGraphic = result; } - else if(haveMovingFrames) + else { result = pProps.movingFrames[pCurIndex].Graphic; } - } /*Start Non Pawn*/ else if (!pProps.stillFrames.NullOrEmpty()) + } + // Start Non Pawn + else if (!pProps.stillFrames.NullOrEmpty()) { result = pProps.stillFrames[pCurIndex].Graphic; } - else if(haveMovingFrames) + else if (haveMovingFrames) { result = pProps.movingFrames[pCurIndex].Graphic; } @@ -177,7 +168,7 @@ public static Graphic ResolveBaseGraphic(Pawn pAnimatee) pawnGraphicSet.nakedGraphic = result; } pawnGraphicSet.rottingGraphic = pawnGraphicSet.nakedGraphic.GetColoredVersion(ShaderDatabase.CutoutSkin, - PawnGraphicSet.RottingColor, PawnGraphicSet.RottingColor); + PawnGraphicSet.RottingColorDefault, PawnGraphicSet.RottingColorDefault); if (pAnimatee.RaceProps.packAnimal) pawnGraphicSet.packGraphic = GraphicDatabase.Get( pawnGraphicSet.nakedGraphic.path + "Pack", ShaderDatabase.Cutout, @@ -197,8 +188,8 @@ public override void CompTick() public override void PostExposeData() { base.PostExposeData(); - Scribe_Values.Look(ref curIndex, "curIndex", 0); - Scribe_Values.Look(ref ticksToCycle, "ticksToCycle", -1); + Scribe_Values.Look(ref curIndex, nameof(curIndex)); + Scribe_Values.Look(ref ticksToCycle, nameof(ticksToCycle), -1); } public virtual void NotifyGraphicsChange() diff --git a/Source/AllModdingComponents/CompAnimated/CompAnimated.csproj b/Source/AllModdingComponents/CompAnimated/CompAnimated.csproj index 254bc0d8..433c730e 100644 --- a/Source/AllModdingComponents/CompAnimated/CompAnimated.csproj +++ b/Source/AllModdingComponents/CompAnimated/CompAnimated.csproj @@ -1,58 +1,7 @@  - - + + - Debug - AnyCPU - {29E2AEA4-3154-42DF-87CF-AEAFF042F2E0} - Library - Properties - CompAnimated CompAnimated - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompAnimated/CompAnimatedOver.cs b/Source/AllModdingComponents/CompAnimated/CompAnimatedOver.cs index 4a2c6e22..fcada93f 100644 --- a/Source/AllModdingComponents/CompAnimated/CompAnimatedOver.cs +++ b/Source/AllModdingComponents/CompAnimated/CompAnimatedOver.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using Verse; namespace CompAnimated @@ -7,27 +7,28 @@ public class CompAnimatedOver : CompAnimated { protected Graphic scaled; /// - /// Additional programatic movement hooks + /// Additional programatic movement hooks /// - public float yOffset = 0f, xOffset = 0f, xScale = 1f, yScale = 1f; - - public CompProperties_AnimatedOver OverProps => (CompProperties_AnimatedOver) props; - + public float yOffset = 0f, xOffset = 0f, layerOffset = 0f, xScale = 1f, yScale = 1f; + + public CompProperties_AnimatedOver OverProps => (CompProperties_AnimatedOver)props; + public override void Render() { - Vector3 drawPos = this.parent.DrawPos; - + var drawPos = parent.DrawPos; + //apply offset drawPos.x += OverProps.xOffset + xOffset; drawPos.z += OverProps.yOffset + yOffset; - - scaled.Draw(drawPos, Rot4.North, this.parent); + drawPos.y += OverProps.layerOffset + layerOffset; + + scaled.Draw(drawPos, Rot4.North, parent); } public override void NotifyGraphicsChange() { - var vector2 = new Vector2(OverProps.xScale*xScale, OverProps.yScale*yScale); - + var vector2 = new Vector2(OverProps.xScale * xScale, OverProps.yScale * yScale); + var sz = curGraphic.drawSize; sz.Scale(vector2); scaled = curGraphic.GetCopy(sz); @@ -37,7 +38,7 @@ public override void NotifyGraphicsChange() public void Invalidate() { curGraphic = null; - this.dirty = true; + dirty = true; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAnimated/CompProperties_Animated.cs b/Source/AllModdingComponents/CompAnimated/CompProperties_Animated.cs index 04bb4d28..cad7d1e2 100644 --- a/Source/AllModdingComponents/CompAnimated/CompProperties_Animated.cs +++ b/Source/AllModdingComponents/CompAnimated/CompProperties_Animated.cs @@ -18,19 +18,11 @@ public CompProperties_Animated() public override IEnumerable ConfigErrors(ThingDef parentDef) { foreach (var error in base.ConfigErrors(parentDef)) - { yield return error; - } - if (stillFrames.NullOrEmpty() && movingFrames.NullOrEmpty()) - { - yield return "Forgot to define stillFrame > li or movingFrame > li"; - } - - if (secondsBetweenFrames<=0f) - { - yield return "Forgot to define secondsBetweenFrames"; - } + yield return $"both {nameof(stillFrames)} and {nameof(movingFrames)} are null or empty"; + if (secondsBetweenFrames <= 0f) + yield return nameof(secondsBetweenFrames) + " must be positive"; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompAnimated/CompProperties_AnimatedOver.cs b/Source/AllModdingComponents/CompAnimated/CompProperties_AnimatedOver.cs index 4659f259..91367fce 100644 --- a/Source/AllModdingComponents/CompAnimated/CompProperties_AnimatedOver.cs +++ b/Source/AllModdingComponents/CompAnimated/CompProperties_AnimatedOver.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Verse; namespace CompAnimated { public class CompProperties_AnimatedOver : CompProperties_Animated { - public float yOffset = 0f, xOffset = 0f, xScale = 1f, yScale = 1f; + public float yOffset = 0f, xOffset = 0f, layerOffset = 0f, xScale = 1f, yScale = 1f; + public CompProperties_AnimatedOver() { compClass = typeof(CompAnimatedOver); @@ -14,21 +15,11 @@ public CompProperties_AnimatedOver() public override IEnumerable ConfigErrors(ThingDef parentDef) { foreach (var error in base.ConfigErrors(parentDef)) - { yield return error; - } - - if (xScale <= 0f) - { - xScale = 0f; - yield return "xScale must be positive"; - } - + if (xScale <= 0f) + yield return nameof(xScale) + " must be positive"; if (yScale <= 0f) - { - yScale = 0f; - yield return "yScale must be positive"; - } + yield return nameof(yScale) + " must be positive"; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompBalloon/CompBalloon.cs b/Source/AllModdingComponents/CompBalloon/CompBalloon.cs index 6417dfec..3ce62b9e 100644 --- a/Source/AllModdingComponents/CompBalloon/CompBalloon.cs +++ b/Source/AllModdingComponents/CompBalloon/CompBalloon.cs @@ -1,32 +1,30 @@ -using System; -using UnityEngine; +using UnityEngine; using Verse; -using Verse.Sound; namespace CompBalloon { public class CompBalloon : ThingComp { - public int curTicks = Int32.MinValue; + public int curTicks = int.MinValue; public bool deflating = true; public Pawn Ballooner => parent as Pawn; - public CompProperties_Balloon Props => (CompProperties_Balloon) props; + public CompProperties_Balloon Props => (CompProperties_Balloon)props; - private float MaxTicks => (Props.secondsBetweenCycles * 60); - - private float Range => Props.balloonRange.max - Props.balloonRange.min; - + private float MaxTicks => Props.secondsBetweenCycles * GenTicks.TicksPerRealSecond; + + //private float Range => Props.balloonRange.max - Props.balloonRange.min; + public void ResolveBaseGraphic() { - var sizeFactor = 1.0f; - var curSizeAdjustment = curTicks * Range; - + // TODO: sizeFactor and curSizeAdjustment end up being unused, and so I commented them out - what are they for? + //var curSizeAdjustment = curTicks * Range; + //Initialize or Deflate - if (curTicks == Int32.MinValue || + if (curTicks == int.MinValue || (!deflating && curTicks >= MaxTicks)) { curTicks = (int)MaxTicks; @@ -40,29 +38,21 @@ public void ResolveBaseGraphic() curTicks = 1; } - if (deflating) - { - sizeFactor = Props.balloonRange.max - curSizeAdjustment; - } - else - { - sizeFactor = Props.balloonRange.min + curSizeAdjustment; - } - + //var sizeFactor = deflating ? Props.balloonRange.max - curSizeAdjustment : Props.balloonRange.min + curSizeAdjustment; + if (Ballooner.Drawer?.renderer?.graphics is PawnGraphicSet pawnGraphicSet) { pawnGraphicSet.ClearCache(); - + var nakedGraphicDrawSize = pawnGraphicSet.nakedGraphic.drawSize; - + //Duplicated code from -> Verse.PawnGrapic -> ResolveAllGraphics var curKindLifeStage = Ballooner.ageTracker.CurKindLifeStage; - if (Ballooner.gender != Gender.Female || curKindLifeStage.femaleGraphicData == null) - pawnGraphicSet.nakedGraphic = curKindLifeStage.bodyGraphicData.Graphic; - else - pawnGraphicSet.nakedGraphic = curKindLifeStage.femaleGraphicData.Graphic; + pawnGraphicSet.nakedGraphic = Ballooner.gender != Gender.Female || curKindLifeStage.femaleGraphicData == null + ? curKindLifeStage.bodyGraphicData.Graphic + : curKindLifeStage.femaleGraphicData.Graphic; pawnGraphicSet.rottingGraphic = pawnGraphicSet.nakedGraphic.GetColoredVersion(ShaderDatabase.CutoutSkin, - PawnGraphicSet.RottingColor, PawnGraphicSet.RottingColor); + PawnGraphicSet.RottingColorDefault, PawnGraphicSet.RottingColorDefault); if (Ballooner.RaceProps.packAnimal) { pawnGraphicSet.packGraphic = GraphicDatabase.Get( @@ -74,20 +64,22 @@ public void ResolveBaseGraphic() curKindLifeStage.dessicatedBodyGraphicData.GraphicColoredFor(Ballooner); } - if (deflating) curTicks--; - else curTicks++; + if (deflating) + curTicks--; + else + curTicks++; } public override void CompTick() { ResolveBaseGraphic(); } - + public override void PostExposeData() { base.PostExposeData(); - Scribe_Values.Look(ref curTicks, "curTicks", Int32.MinValue); + Scribe_Values.Look(ref curTicks, nameof(curTicks), int.MinValue); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompBalloon/CompBalloon.csproj b/Source/AllModdingComponents/CompBalloon/CompBalloon.csproj index 6fe1c6d5..e2c121af 100644 --- a/Source/AllModdingComponents/CompBalloon/CompBalloon.csproj +++ b/Source/AllModdingComponents/CompBalloon/CompBalloon.csproj @@ -1,56 +1,7 @@  - - + + - Debug - AnyCPU - {CE293DBE-D76A-4F24-A086-42051996698D} - Library - Properties - CompBalloon CompBalloon - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompBalloon/CompProperties_Balloon.cs b/Source/AllModdingComponents/CompBalloon/CompProperties_Balloon.cs index 9593ecd1..eb630ccf 100644 --- a/Source/AllModdingComponents/CompBalloon/CompProperties_Balloon.cs +++ b/Source/AllModdingComponents/CompBalloon/CompProperties_Balloon.cs @@ -20,4 +20,4 @@ public override void ResolveReferences(ThingDef parentDef) 132); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompBigBox/BigBoxUtility.cs b/Source/AllModdingComponents/CompBigBox/BigBoxUtility.cs new file mode 100644 index 00000000..34413245 --- /dev/null +++ b/Source/AllModdingComponents/CompBigBox/BigBoxUtility.cs @@ -0,0 +1,23 @@ +using Verse; + +namespace DefModExtension_BigBox +{ + public static class BigBoxUtility + { + // Avoiding Def.GetModExtension and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static DefModExtension_BigBox GetModExtensionBigBox(this Def def) + { + var modExtensions = def.modExtensions; + if (modExtensions == null) + return null; + for (int i = 0, count = modExtensions.Count; i < count; i++) + { + if (modExtensions[i] is DefModExtension_BigBox modExtension) + return modExtension; + } + return null; + } + } +} diff --git a/Source/AllModdingComponents/CompBigBox/DefModExtension_BigBox.csproj b/Source/AllModdingComponents/CompBigBox/DefModExtension_BigBox.csproj index 8929aa4b..e71cc0c7 100644 --- a/Source/AllModdingComponents/CompBigBox/DefModExtension_BigBox.csproj +++ b/Source/AllModdingComponents/CompBigBox/DefModExtension_BigBox.csproj @@ -1,64 +1,10 @@  - - + + - Debug - AnyCPU - {CB5B70DA-38FB-4C54-A816-7112CA045235} - Library - Properties - CompBigBox CompBigBox - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - False - ..\..\..\Assemblies\0JecsTools.dll - False - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - + - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompBigBox/HitBoxHolder.cs b/Source/AllModdingComponents/CompBigBox/HitBoxHolder.cs index 3d341c1f..524a264f 100644 --- a/Source/AllModdingComponents/CompBigBox/HitBoxHolder.cs +++ b/Source/AllModdingComponents/CompBigBox/HitBoxHolder.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using RimWorld; -using Verse; +using Verse; namespace DefModExtension_BigBox { - class ThingWithComps_HitBox : ThingWithComps + internal class ThingWithComps_HitBox : ThingWithComps { public Pawn master = null; @@ -23,21 +18,19 @@ public override void Tick() public void CheckNeedsDestruction() { - if (master != null && this.Spawned) + if (master != null && Spawned) { if (!master.Spawned) { - this.Destroy(0); - return; + Destroy(0); } - } } - + public override void ExposeData() { base.ExposeData(); - Scribe_References.Look(ref this.master, "master", false); + Scribe_References.Look(ref master, nameof(master)); } } } diff --git a/Source/AllModdingComponents/CompBigBox/_HarmonyCompBigBox.cs b/Source/AllModdingComponents/CompBigBox/_HarmonyCompBigBox.cs index 3e860754..f5547aa0 100644 --- a/Source/AllModdingComponents/CompBigBox/_HarmonyCompBigBox.cs +++ b/Source/AllModdingComponents/CompBigBox/_HarmonyCompBigBox.cs @@ -1,11 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using HarmonyLib; using RimWorld; using UnityEngine; using Verse; -using Verse.AI; namespace DefModExtension_BigBox { @@ -15,60 +12,55 @@ internal static class HarmonyDefModExtension_BigBox static HarmonyDefModExtension_BigBox() { var harmony = new Harmony("jecstools.jecrell.defmodextensions.bigbox"); - var type = typeof(HarmonyDefModExtension_BigBox); + harmony.Patch(AccessTools.Method(typeof(SelectionDrawer), "DrawSelectionBracketFor"), - new HarmonyMethod(type, nameof(DrawSelectionBracketFor_PreFix)), null); + prefix: new HarmonyMethod(type, nameof(DrawSelectionBracketFor_PreFix))); } - private static bool DrawSelectionBracketFor_PreFix(object obj) + private static bool DrawSelectionBracketFor_PreFix(object obj, Vector3[] ___bracketLocs, Material ___SelectionBracketMat, + Dictionary ___selectTimes) { - var thing = obj as ThingWithComps; - if (thing != null && thing?.def?.GetModExtension() is DefModExtension_BigBox bigBox) + if (obj is ThingWithComps thing && thing.def?.GetModExtensionBigBox() is DefModExtension_BigBox bigBox) { - - var bracketLocs = Traverse.Create(typeof(SelectionDrawer)).Field("bracketLocs").GetValue(); - var SelectionBracketMat = Traverse.Create(typeof(SelectionDrawer)).Field("SelectionBracketMat").GetValue(); - var selectTimes = Traverse.Create(typeof(SelectionDrawer)).Field("selectTimes").GetValue>(); - //Use public variables from DefModExtension_BigBox - Vector3 drawPos = thing.DrawPos; - Vector2 drawSize = new Vector2(1, 1); + var drawPos = thing.DrawPos; + Vector2 drawSize; if (!bigBox.directionBased) { - drawPos = drawPos + bigBox.offset; + drawPos += bigBox.offset; drawSize = bigBox.size; } else { if (thing.Rotation == Rot4.East) { - drawPos = drawPos + bigBox.eastOffset; + drawPos += bigBox.eastOffset; drawSize = bigBox.eastSize; } else if (thing.Rotation == Rot4.North) { - drawPos = drawPos + bigBox.northOffset; + drawPos += bigBox.northOffset; drawSize = bigBox.northSize; } else if (thing.Rotation == Rot4.West) { - drawPos = drawPos + bigBox.westOffset; + drawPos += bigBox.westOffset; drawSize = bigBox.westSize; } else { - drawPos = drawPos + bigBox.southOffset; + drawPos += bigBox.southOffset; drawSize = bigBox.southSize; } } - SelectionDrawerUtility.CalculateSelectionBracketPositionsWorld(bracketLocs, thing, drawPos, drawSize, selectTimes, Vector2.one); - int num = 0; - for (int i = 0; i < 4; i++) + SelectionDrawerUtility.CalculateSelectionBracketPositionsWorld(___bracketLocs, thing, drawPos, drawSize, ___selectTimes, Vector2.one); + var num = 0; + for (var i = 0; i < 4; i++) { - Quaternion rotation = Quaternion.AngleAxis(num, Vector3.up); - Graphics.DrawMesh(MeshPool.plane10, bracketLocs[i], rotation, SelectionBracketMat, 0); + var rotation = Quaternion.AngleAxis(num, Vector3.up); + Graphics.DrawMesh(MeshPool.plane10, ___bracketLocs[i], rotation, ___SelectionBracketMat, 0); num -= 90; } return false; @@ -77,4 +69,4 @@ private static bool DrawSelectionBracketFor_PreFix(object obj) } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDeflector/CompDeflector.cs b/Source/AllModdingComponents/CompDeflector/CompDeflector.cs index 97ac768f..9c36b872 100644 --- a/Source/AllModdingComponents/CompDeflector/CompDeflector.cs +++ b/Source/AllModdingComponents/CompDeflector/CompDeflector.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using HarmonyLib; using RimWorld; using UnityEngine; @@ -9,6 +7,7 @@ namespace CompDeflector { + public class CompDeflector : ThingComp { public enum AccuracyRoll @@ -19,8 +18,9 @@ public enum AccuracyRoll CriticalSuccess } - private int animationDeflectionTicks; + public CompProperties_Deflector Props => (CompProperties_Deflector)props; + private int animationDeflectionTicks; public Verb_Deflected deflectVerb; public AccuracyRoll lastAccuracyRoll = AccuracyRoll.Failure; @@ -32,123 +32,220 @@ public int AnimationDeflectionTicks get => animationDeflectionTicks; } - public bool IsAnimatingNow - { - get - { - if (animationDeflectionTicks >= 0) return true; - return false; - } - } + public bool IsAnimatingNow => animationDeflectionTicks >= 0; + + private CompEquippable compEquippable; + private ThingComp compActivatableEffect; + private Func compActivatableEffectIsActive; + + private static readonly Type compActivatableEffectType = GenTypes.GetTypeInAnyAssembly("CompActivatableEffect.CompActivatableEffect"); + + public CompEquippable GetEquippable => compEquippable; + + public Pawn GetPawn => GetEquippable?.verbTracker.PrimaryVerb.CasterPawn; + + public ThingComp GetActivatableEffect => compActivatableEffect; - public CompEquippable GetEquippable => parent.GetComp(); + public bool HasCompActivatableEffect => GetActivatableEffect != null; - public Pawn GetPawn => GetEquippable.verbTracker.PrimaryVerb.CasterPawn; + public bool CompActivatableEffectiveIsActive => compActivatableEffectIsActive?.Invoke() ?? false; - public ThingComp GetActivatableEffect => - parent.AllComps.FirstOrDefault(y => y.GetType().ToString().Contains("ActivatableEffect")); + // Caching comps needs to happen after all comps are created. Ideally, this would be done right after + // ThingWithComps.InitializeComps(). This requires overriding two hooks: PostPostMake and PostExposeData. - public bool HasCompActivatableEffect + public override void PostPostMake() { - get + base.PostPostMake(); + CacheComps(); + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref animationDeflectionTicks, nameof(animationDeflectionTicks)); + if (Scribe.mode == LoadSaveMode.LoadingVars) + CacheComps(); + } + + private void CacheComps() + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + // For the optional CompActivatableEffect, we have to use the slower IsAssignableFrom reflection check. + var comps = parent.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) { - if (parent is ThingWithComps x) - if (GetActivatableEffect != null) - return true; - return false; + var comp = comps[i]; + if (comp is CompEquippable compEquippable) + this.compEquippable = compEquippable; + else if (compActivatableEffectType != null) + { + var compType = comp.GetType(); + if (compActivatableEffectType.IsAssignableFrom(compType)) + { + compActivatableEffect = comp; + compActivatableEffectIsActive = + (Func)AccessTools.Method(compType, "IsActive").CreateDelegate(typeof(Func), comp); + } + } } } - public float DeflectionChance + internal class DeflectionChanceCalculator { - get + private readonly CompDeflector compDeflector; + private readonly Pawn pawn; + private readonly CompProperties_Deflector props; + private readonly bool fixedRandSeed; + + public DeflectionChanceCalculator(CompDeflector compDeflector, bool fixedRandSeed) { - var calc = Props.baseDeflectChance; + this.compDeflector = compDeflector; + this.fixedRandSeed = fixedRandSeed; + pawn = compDeflector.GetPawn; + props = compDeflector.Props; + } - if (GetEquippable != null) - if (GetPawn != null) - { - var pawn = GetPawn; + public float BeforeInfixValue { get; private set; } + public float InfixValue { get; private set; } - //This handles if a deflection skill is defined. - //Example, melee skill of 20. - if (Props.useSkillInCalc) + public float Calculate() + { + var calc = props.baseDeflectChance; + if (pawn != null) + { + if (UseSkill(out var deflectSkill)) + calc += deflectSkill.Level * props.deflectRatePerSkillPoint; + BeforeInfixValue = calc; + // Due to possibility of DeflectionChance_InFix implementation using Rand, option to use a fixed Random seed. + if (fixedRandSeed) + { + Rand.PushState(0); + try { - var skillToCheck = Props.deflectSkill; - if (skillToCheck != null) - { - var skillRecord = pawn.skills?.GetSkill(skillToCheck); - if (skillRecord != null) - { - var param = Props.deflectRatePerSkillPoint; - if (param != 0) - calc += skillRecord.Level * param; //Makes the skill into float percent - else - Log.Error( - "CompDeflector :: deflectRatePerSkillPoint is set to 0, but useSkillInCalc is set to true."); - } - } + calc = compDeflector.DeflectionChance_InFix(calc); } + finally + { + Rand.PopState(); + } + } + else + calc = compDeflector.DeflectionChance_InFix(calc); + InfixValue = calc; + if (UseManipulation(out var capable) && capable) + calc *= pawn.health.capacities.GetLevel(PawnCapacityDefOf.Manipulation); + } + return Mathf.Clamp01(calc); + } - calc = DeflectionChance_InFix(calc); + public bool UseSkill(out SkillRecord skill) + { + skill = null; + if (props.useSkillInCalc && props.deflectSkill != null) + skill = pawn.skills?.GetSkill(props.deflectSkill); + return skill != null; + } - //This handles if manipulation needs to be checked. - if (!Props.useManipulationInCalc) return Mathf.Clamp(calc, 0, 1.0f); - if (pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)) - calc *= pawn.health.capacities.GetLevel(PawnCapacityDefOf.Manipulation); - else - calc = 0f; - } - return Mathf.Clamp(calc, 0, 1.0f); + public bool UseManipulation(out bool capable) + { + capable = props.useManipulationInCalc && pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation); + return props.useManipulationInCalc; } } - public string ChanceToString => DeflectionChance.ToStringPercent(); + internal DeflectionChanceCalculator GetDeflectionChanceCalculator(bool fixedRandSeed) => new DeflectionChanceCalculator(this, fixedRandSeed); + public float DeflectionChance => GetDeflectionChanceCalculator(fixedRandSeed: false).Calculate(); - public CompProperties_Deflector Props => (CompProperties_Deflector) props; + public string ChanceToString => DeflectionChance.ToStringPercent(); + // TODO: This is never called (and Props.deflectSkillLearnRate is never used) - should it be called upon deflection success? + // or whenever deflection is rolled ala reflection skill (though this would mean every received hit would result in skill gain)? public void DeflectionSkillGain(SkillRecord skill) { GetPawn.skills?.Learn(Props.deflectSkill, Props.deflectSkillLearnRate, false); } - public void ReflectionSkillGain(SkillRecord skill) { + // TODO: GetPawn should be passed in, though doing so would break binary compatibility GetPawn.skills?.Learn(Props.reflectSkill, Props.reflectSkillLearnRate, false); } - //Accuracy Roll Calculator - public AccuracyRoll ReflectionAccuracy() + // TODO: Use this in a StatWorker_ReflectionAccuracy. + internal class ReflectionAccuracyCalculator { - var d100 = Rand.Range(1, 100); - var modifier = 0; - var difficulty = 80; - var thisPawn = GetPawn; - if (thisPawn?.skills != null) + private readonly CompDeflector compDeflector; + private readonly Pawn pawn; + private readonly CompProperties_Deflector props; + private readonly bool fixedRandSeed; + + public ReflectionAccuracyCalculator(CompDeflector compDeflector, bool fixedRandSeed) { - if (Props?.reflectSkill != null) + this.compDeflector = compDeflector; + this.fixedRandSeed = fixedRandSeed; + pawn = compDeflector.GetPawn; + props = compDeflector.Props; + } + + public void Calculate(out int modifier, out int difficulty, out SkillRecord skill) + { + modifier = 0; + difficulty = 80; + if (UseSkill(out skill)) + { + modifier += (int)(props.reflectRatePerSkillPoint * skill.Level); + //Log.Message("Deflection mod: " + modifier.ToString()); + } + // Due to possibility of ReflectionAccuracy_InFix implementation using Rand, option to use a fixed Random seed. + if (fixedRandSeed) { - var skill = thisPawn.skills.GetSkill(Props.reflectSkill); - if (skill?.Level > 0) + Rand.PushState(0); + try { - modifier += (int) (Props.deflectRatePerSkillPoint * skill.Level); - //Log.Message("Deflection mod: " + modifier.ToString()); - ReflectionSkillGain(skill); + compDeflector.ReflectionAccuracy_InFix(ref modifier, ref difficulty); + } + finally + { + Rand.PopState(); } } + else + compDeflector.ReflectionAccuracy_InFix(ref modifier, ref difficulty); + } + + public bool UseSkill(out SkillRecord skill) + { + skill = null; + if (props.reflectSkill != null) + skill = pawn.skills?.GetSkill(props.reflectSkill); + return skill != null; + } + } + + internal ReflectionAccuracyCalculator GetReflectionAccuracyCalculator(bool fixedRandSeed) => new ReflectionAccuracyCalculator(this, fixedRandSeed); + + public AccuracyRoll ReflectionAccuracy() + { + var d100 = Rand.Range(1, 100); + GetReflectionAccuracyCalculator(fixedRandSeed: false).Calculate(out var modifier, out var difficulty, out var skill); + if (skill != null) + { + // TODO: This means the skill is leveled regardless of reflection success - is this correct? + ReflectionSkillGain(skill); } - ReflectionAccuracy_InFix(ref modifier, ref difficulty); var subtotal = d100 + modifier; if (subtotal >= 90) return AccuracyRoll.CriticalSuccess; - if (subtotal > difficulty) + else if (subtotal > difficulty) return AccuracyRoll.Success; - if (subtotal <= 30) + else if (subtotal <= 30) return AccuracyRoll.CritialFailure; - return AccuracyRoll.Failure; + else + return AccuracyRoll.Failure; } public virtual void ReflectionAccuracy_InFix(ref int modifier, ref int difficulty) @@ -166,22 +263,6 @@ public virtual float DeflectionChance_InFix(float calc) return calc; } - public override IEnumerable SpecialDisplayStats() - { - //yield return new StatDrawEntry(StatCategoryDefOf.Basics, "DeflectChance".Translate(), ChanceToString, 0); - yield return new StatDrawEntry(StatCategoryDefOf.Basics, StatDef.Named("Deflect chance"), float.Parse(ChanceToString), StatRequest.ForEmpty()); - } - - // if (this.ingestible != null) - // { - // IEnumerator enumerator2 = this.ingestible.SpecialDisplayStats(this).GetEnumerator(); - // while (enumerator2.MoveNext()) - // { - // StatDrawEntry current2 = enumerator2.Current; - // yield return current2; - // } - //} - public virtual Verb ReflectionHandler(Verb newVerb) { if (Props.canReflect) @@ -199,13 +280,13 @@ public virtual Verb ReflectionHandler(Verb newVerb) muzzleFlashScale = newVerb.verbProps.muzzleFlashScale, warmupTime = 0, defaultCooldownTime = 0, - soundCast = Props.deflectSound + soundCast = Props.deflectSound, }; switch (lastAccuracyRoll) { case AccuracyRoll.CriticalSuccess: - if (GetPawn != null) - MoteMaker.ThrowText(GetPawn.DrawPos, GetPawn.Map, + if (GetPawn is Pawn pawn) // TODO: GetPawn should be passed in, though doing so would break binary compatibility + MoteMaker.ThrowText(pawn.DrawPos, pawn.Map, "SWSaber_TextMote_CriticalSuccess".Translate(), 6f); newVerbProps.accuracyLong = 999.0f; newVerbProps.accuracyMedium = 999.0f; @@ -213,7 +294,7 @@ public virtual Verb ReflectionHandler(Verb newVerb) lastShotReflected = true; break; case AccuracyRoll.Failure: - newVerbProps.forcedMissRadius = 50.0f; + verbPropertiesForcedMissRadius(newVerbProps) = 50.0f; newVerbProps.accuracyLong = 0.0f; newVerbProps.accuracyMedium = 0.0f; newVerbProps.accuracyShort = 0.0f; @@ -221,8 +302,8 @@ public virtual Verb ReflectionHandler(Verb newVerb) break; case AccuracyRoll.CritialFailure: - if (GetPawn != null) - MoteMaker.ThrowText(GetPawn.DrawPos, GetPawn.Map, + if (GetPawn is Pawn pawn2) + MoteMaker.ThrowText(pawn2.DrawPos, pawn2.Map, "SWSaber_TextMote_CriticalFailure".Translate(), 6f); newVerbProps.accuracyLong = 999.0f; newVerbProps.accuracyMedium = 999.0f; @@ -243,6 +324,10 @@ public virtual Verb ReflectionHandler(Verb newVerb) return newVerb; } + private static readonly AccessTools.FieldRef verbPropertiesForcedMissRadius = + AccessTools.FieldRefAccess("forcedMissRadius"); + + // TODO: This is never called - still needed? public virtual Verb CopyAndReturnNewVerb_PostFix(Verb newVerb) { return newVerb; @@ -252,9 +337,8 @@ public Verb CopyAndReturnNewVerb(Verb newVerb = null) { if (newVerb != null) { - deflectVerb = null; - deflectVerb = (Verb_Deflected) Activator.CreateInstance(typeof(Verb_Deflected)); - deflectVerb.caster = GetPawn; + deflectVerb = (Verb_Deflected)Activator.CreateInstance(typeof(Verb_Deflected)); + deflectVerb.caster = GetPawn; // TODO: GetPawn should be passed in, though doing so would break binary compatibility //Initialize VerbProperties var newVerbProps = new VerbProperties @@ -266,7 +350,7 @@ public Verb CopyAndReturnNewVerb(Verb newVerb = null) muzzleFlashScale = newVerb.verbProps.muzzleFlashScale, warmupTime = 0, defaultCooldownTime = 0, - soundCast = Props.deflectSound + soundCast = Props.deflectSound, }; //Apply values @@ -274,8 +358,9 @@ public Verb CopyAndReturnNewVerb(Verb newVerb = null) } else { - if (deflectVerb != null) return deflectVerb; - deflectVerb = (Verb_Deflected) Activator.CreateInstance(typeof(Verb_Deflected)); + if (deflectVerb != null) + return deflectVerb; + deflectVerb = (Verb_Deflected)Activator.CreateInstance(typeof(Verb_Deflected)); deflectVerb.caster = GetPawn; deflectVerb.verbProps = Props.DeflectVerb; } @@ -289,64 +374,60 @@ public void ResolveDeflectVerb() public virtual Pawn ResolveDeflectionTarget(Pawn defaultTarget = null) { - if (lastAccuracyRoll != AccuracyRoll.CritialFailure) return defaultTarget; - var thisPawn = GetPawn; - if (thisPawn == null || thisPawn.Dead) return defaultTarget; - - bool Validator(Thing t) - { - return t is Pawn pawn3 && pawn3 != thisPawn; - } - - var closestPawn = (Pawn) GenClosest.ClosestThingReachable(thisPawn.Position, thisPawn.Map, + if (lastAccuracyRoll != AccuracyRoll.CritialFailure) + return defaultTarget; + var thisPawn = GetPawn; // TODO: GetPawn should be passed in, though doing so would break binary compatibility + var closestPawn = (Pawn)GenClosest.ClosestThingReachable(thisPawn.Position, thisPawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.InteractionCell, - TraverseParms.For(thisPawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, Validator, null, + TraverseParms.For(thisPawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, t => t is Pawn && t != thisPawn, null, 0, -1, false, RegionType.Set_Passable, false); - if (closestPawn == null) return defaultTarget; - return closestPawn == defaultTarget ? thisPawn : closestPawn; + if (closestPawn == null) + return defaultTarget; + else if (closestPawn == defaultTarget) + return thisPawn; + else + return closestPawn; } public virtual void CriticalFailureHandler(DamageInfo dinfo, Pawn newTarget, out bool shouldContinue) { shouldContinue = true; - if (lastAccuracyRoll != AccuracyRoll.CritialFailure) return; - var thisPawn = GetPawn; - if (thisPawn == null || thisPawn.Dead) return; + if (lastAccuracyRoll != AccuracyRoll.CritialFailure) + return; + var thisPawn = GetPawn; // TODO: GetPawn should be passed in, though doing so would break binary compatibility //If the target isn't the old target, then get out of this if (newTarget != dinfo.Instigator as Pawn) return; shouldContinue = false; - GetPawn.TakeDamage(new DamageInfo(dinfo.Def, dinfo.Amount)); + thisPawn.TakeDamage(new DamageInfo(dinfo.Def, dinfo.Amount)); } public virtual void GiveDeflectJob(DamageInfo dinfo) { - try - { - if (!(dinfo.Instigator is Pawn pawn2)) return; - var job = new Job(CompDeflectorDefOf.CastDeflectVerb) - { - playerForced = true, - locomotionUrgency = LocomotionUrgency.Sprint - }; - var compEquip = pawn2.equipment?.PrimaryEq; - if (compEquip?.PrimaryVerb == null) return; - var verbToUse = (Verb_Deflected) CopyAndReturnNewVerb(compEquip.PrimaryVerb); - verbToUse = (Verb_Deflected) ReflectionHandler(deflectVerb); - verbToUse.lastShotReflected = lastShotReflected; - verbToUse.verbTracker = GetPawn.VerbTracker; - pawn2 = ResolveDeflectionTarget(pawn2); - CriticalFailureHandler(dinfo, pawn2, out var shouldContinue); - if (!shouldContinue) return; - job.targetA = pawn2; - job.verbToUse = verbToUse; - job.killIncappedTarget = pawn2.Downed; - GetPawn.jobs.TryTakeOrderedJob(job); - } - catch (NullReferenceException) - { - } - ////Log.Message("TryToTakeOrderedJob Called"); + if (!(dinfo.Instigator is Pawn pawn)) + return; + var job = JobMaker.MakeJob(CompDeflectorDefOf.CastDeflectVerb); + job.playerForced = true; + job.locomotionUrgency = LocomotionUrgency.Sprint; + var compEquipVerb = pawn.equipment?.PrimaryEq?.PrimaryVerb; + if (compEquipVerb == null) + return; + var thisPawn = GetPawn; + if (thisPawn == null || thisPawn.Dead) + return; + var deflectVerb = (Verb_Deflected)CopyAndReturnNewVerb(compEquipVerb); + var verbToUse = (Verb_Deflected)ReflectionHandler(deflectVerb); + verbToUse.lastShotReflected = lastShotReflected; + verbToUse.verbTracker = thisPawn.VerbTracker; + pawn = ResolveDeflectionTarget(pawn); + CriticalFailureHandler(dinfo, pawn, out var shouldContinue); + if (!shouldContinue) + return; + job.targetA = pawn; + job.verbToUse = verbToUse; + job.killIncappedTarget = pawn.Downed; + thisPawn.jobs.TryTakeOrderedJob(job); + //Log.Message("TryToTakeOrderedJob Called"); } /// @@ -361,17 +442,15 @@ public override void PostPreApplyDamage(DamageInfo dinfo, out bool absorbed) { if (HasCompActivatableEffect) { - bool? isActive = (bool) AccessTools.Method(GetActivatableEffect.GetType(), "IsActive") - .Invoke(GetActivatableEffect, null); - if (isActive == false) + if (CompActivatableEffectiveIsActive == false) { - ////Log.Message("Inactivate Weapon"); + //Log.Message("Inactivate Weapon"); absorbed = false; return; } } var calc = DeflectionChance; - var deflectThreshold = (int) (calc * 100); // 0.3f => 30 + var deflectThreshold = (int)(calc * 100); // 0.3f => 30 if (Rand.Range(1, 100) > deflectThreshold) { absorbed = false; @@ -386,11 +465,5 @@ public override void PostPreApplyDamage(DamageInfo dinfo, out bool absorbed) } absorbed = false; } - - public override void PostExposeData() - { - Scribe_Values.Look(ref animationDeflectionTicks, "animationDeflectionTicks", 0); - base.PostExposeData(); - } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDeflector/CompDeflector.csproj b/Source/AllModdingComponents/CompDeflector/CompDeflector.csproj index 059f159d..b6310e9c 100755 --- a/Source/AllModdingComponents/CompDeflector/CompDeflector.csproj +++ b/Source/AllModdingComponents/CompDeflector/CompDeflector.csproj @@ -1,61 +1,7 @@  - - + + - Debug - AnyCPU - {4A2FA470-0CA5-442B-B04D-2C4A62859CA7} - Library - Properties - CompDeflector CompDeflector - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompDeflector/CompDeflectorDefOf.cs b/Source/AllModdingComponents/CompDeflector/CompDeflectorDefOf.cs index f8b48a97..ec35a67d 100644 --- a/Source/AllModdingComponents/CompDeflector/CompDeflectorDefOf.cs +++ b/Source/AllModdingComponents/CompDeflector/CompDeflectorDefOf.cs @@ -7,5 +7,8 @@ namespace CompDeflector public static class CompDeflectorDefOf { public static JobDef CastDeflectVerb; + public static StatDef MeleeWeapon_DeflectionChance; + + static CompDeflectorDefOf() => DefOfHelper.EnsureInitializedInCtor(typeof(CompDeflectorDefOf)); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDeflector/CompProperties_Deflector.cs b/Source/AllModdingComponents/CompDeflector/CompProperties_Deflector.cs index 4575534d..d399a689 100644 --- a/Source/AllModdingComponents/CompDeflector/CompProperties_Deflector.cs +++ b/Source/AllModdingComponents/CompDeflector/CompProperties_Deflector.cs @@ -24,12 +24,20 @@ public class CompProperties_Deflector : CompProperties public bool useManipulationInCalc = false; public bool useSkillInCalc = false; - + public CompProperties_Deflector() { compClass = typeof(CompDeflector); } + public override IEnumerable ConfigErrors(ThingDef parentDef) + { + foreach (var error in base.ConfigErrors(parentDef)) + yield return error; + if (useSkillInCalc && deflectRatePerSkillPoint == 0f) + yield return $"{nameof(deflectRatePerSkillPoint)} is set to zero, but {nameof(useSkillInCalc)} is set to true"; + } + public virtual IEnumerable PostSpecialDisplayStats() { yield break; @@ -40,44 +48,21 @@ public override IEnumerable SpecialDisplayStats(StatRequest req) { if (!useSkillInCalc) { - yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "Deflect chance", baseDeflectChance.ToStringPercent(), "", 0, "Determines how often this weapon returns projectiles back at the attacker."); + yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "DeflectChance".Translate(), baseDeflectChance.ToStringPercent(), + "DeflectChanceEx".Translate(), 0); } else { - var calc = Mathf.Clamp(baseDeflectChance + deflectRatePerSkillPoint * 20, 0f, 1.0f); - //yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "MaxDeflectChance".Translate(), calc.ToStringPercent(), 0) - //{ - // overrideReportText = "MaxDeflectChanceEx".Translate(new object[] - // { - // deflectSkill.label, - // deflectRatePerSkillPoint.ToStringPercent(), - // calc.ToStringPercent() - // }), - //}; - yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "Max deflect chance", calc.ToStringPercent(), "", 0, "For each point in " + deflectSkill.label + ", the user gains a " + - deflectRatePerSkillPoint.ToStringPercent() + - " chance of deflecting the projectile back the target. " + - calc.ToStringPercent() + " is the maximum possible deflection chance."); - - //yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "DeflectChancePerLevel".Translate(new object[] { deflectSkill.label }), deflectRatePerSkillPoint.ToStringPercent(), 0) - //{ - // overrideReportText = "DeflectChancePerLevelEx".Translate(new object[] { deflectSkill.label }) - //}; - //yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "DeflectChancePerLevel".Translate(new object[] { deflectSkill.label }), deflectRatePerSkillPoint.ToStringPercent(), 0) - //{ - // overrideReportText = "DeflectChancePerLevelEx".Translate(new object[] { deflectSkill.label }) - //}; - yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "Deflect % per " + deflectSkill.label + " skill", deflectRatePerSkillPoint.ToStringPercent(), "For each level in " + deflectSkill.label + - ", the user gains this much % chance to deflect a projectile.", 0); - + var deflectRatePerSkillPointStr = deflectRatePerSkillPoint.ToStringPercent(); + var maxDeflectChanceStr = Mathf.Clamp01(baseDeflectChance + deflectRatePerSkillPoint * 20).ToStringPercent(); + yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "MaxDeflectChance".Translate(), maxDeflectChanceStr, + "MaxDeflectChanceEx".Translate(deflectSkill.label, deflectRatePerSkillPointStr, maxDeflectChanceStr), 0); + yield return new StatDrawEntry(StatCategoryDefOf.Weapon, "DeflectChancePerLevel".Translate(deflectSkill.label), deflectRatePerSkillPointStr, + "DeflectChancePerLevelEx".Translate(deflectSkill.label), 0); } - var enumerator2 = PostSpecialDisplayStats().GetEnumerator(); - while (enumerator2.MoveNext()) - { - var current2 = enumerator2.Current; - yield return current2; - } + foreach (var current in PostSpecialDisplayStats()) + yield return current; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDeflector/DeflectorUtility.cs b/Source/AllModdingComponents/CompDeflector/DeflectorUtility.cs new file mode 100644 index 00000000..3a5bdc7c --- /dev/null +++ b/Source/AllModdingComponents/CompDeflector/DeflectorUtility.cs @@ -0,0 +1,21 @@ +using Verse; + +namespace CompDeflector +{ + public static class DeflectorUtility + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static CompDeflector GetCompDeflector(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompDeflector comp) + return comp; + } + return null; + } + } +} diff --git a/Source/AllModdingComponents/CompDeflector/HarmonyCompDeflector.cs b/Source/AllModdingComponents/CompDeflector/HarmonyCompDeflector.cs index 7a0e5e8d..a6eae558 100644 --- a/Source/AllModdingComponents/CompDeflector/HarmonyCompDeflector.cs +++ b/Source/AllModdingComponents/CompDeflector/HarmonyCompDeflector.cs @@ -1,5 +1,4 @@ -using System; -using HarmonyLib; +using HarmonyLib; using RimWorld; using UnityEngine; using Verse; @@ -12,125 +11,111 @@ internal static class HarmonyCompDeflector static HarmonyCompDeflector() { var harmony = new Harmony("jecstools.jecrell.comps.deflector"); + var type = typeof(HarmonyCompDeflector); + harmony.Patch(AccessTools.Method(typeof(Thing), nameof(Thing.TakeDamage)), - new HarmonyMethod(typeof(HarmonyCompDeflector), nameof(TakeDamage_PreFix)), null); - harmony.Patch(AccessTools.Method(typeof(PawnRenderer), nameof(PawnRenderer.DrawEquipmentAiming)), null, - new HarmonyMethod(typeof(HarmonyCompDeflector), nameof(DrawEquipmentAimingPostFix)), null); + prefix: new HarmonyMethod(type, nameof(TakeDamage_PreFix))); + harmony.Patch(AccessTools.Method(typeof(PawnRenderer), nameof(PawnRenderer.DrawEquipmentAiming)), + postfix: new HarmonyMethod(type, nameof(DrawEquipmentAimingPostFix))); } - public static void DrawEquipmentAimingPostFix(PawnRenderer __instance, Thing eq, Vector3 drawLoc, + public static void DrawEquipmentAimingPostFix(Pawn ___pawn, Thing eq, Vector3 drawLoc, float aimAngle) { - var pawn = (Pawn) AccessTools.Field(typeof(PawnRenderer), "pawn").GetValue(__instance); - if (pawn != null) + var pawn_EquipmentTracker = ___pawn.equipment; + if (pawn_EquipmentTracker != null) { - ////Log.Message("1"); - var pawn_EquipmentTracker = pawn.equipment; - if (pawn_EquipmentTracker != null) - foreach (var thingWithComps in pawn_EquipmentTracker.AllEquipmentListForReading) - ////Log.Message("3"); - if (thingWithComps != null) + foreach (var thingWithComps in pawn_EquipmentTracker.AllEquipmentListForReading) + { + var compDeflector = thingWithComps?.GetCompDeflector(); + if (compDeflector != null) + { + if (compDeflector.IsAnimatingNow) { - ////Log.Message("4"); - ////Log.Message("3"); - var compDeflector = thingWithComps.GetComp(); - if (compDeflector != null) - if (compDeflector.IsAnimatingNow) + if (!Find.TickManager.Paused && compDeflector.IsAnimatingNow) + compDeflector.AnimationDeflectionTicks -= 20; + + // start copied vanilla code (with mesh = flip ? MeshPool.plane10Flip : MeshPool.plane10) + var flip = false; + var angle = aimAngle - 90f; + if (aimAngle > 20f && aimAngle < 160f) + { + angle += eq.def.equippedAngleOffset; + } + else if (aimAngle > 200f && aimAngle < 340f) + { + flip = true; + angle -= 180f; + angle -= eq.def.equippedAngleOffset; + } + else + { + angle += eq.def.equippedAngleOffset; + } + // end copied vanilla code + + if (compDeflector.IsAnimatingNow) + { + float animationTicks = compDeflector.AnimationDeflectionTicks; + if (animationTicks > 0) { - var flip = false; - if (!Find.TickManager.Paused && compDeflector.IsAnimatingNow) - compDeflector.AnimationDeflectionTicks -= 20; - var offset = eq.def.equippedAngleOffset; - var num = aimAngle - 90f; - if (aimAngle > 20f && aimAngle < 160f) - { - //mesh = MeshPool.plane10; - num += offset; - if (compDeflector.IsAnimatingNow) - num += (compDeflector.AnimationDeflectionTicks + 1) / 2; - } - else if (aimAngle > 200f && aimAngle < 340f) - { - //mesh = MeshPool.plane10Flip; - flip = true; - num -= 180f; - num -= offset; - if (compDeflector.IsAnimatingNow) - num -= (compDeflector.AnimationDeflectionTicks + 1) / 2; - } + if (flip) + angle -= (animationTicks + 1) / 2; else - { - //mesh = MeshPool.plane10; - num += offset; - if (compDeflector.IsAnimatingNow) - num += (compDeflector.AnimationDeflectionTicks + 1) / 2; - } - num %= 360f; - var graphic_StackCount = eq.Graphic as Graphic_StackCount; - Material matSingle; - if (graphic_StackCount != null) - matSingle = graphic_StackCount.SubGraphicForStackCount(1, eq.def).MatSingle; - else - matSingle = eq.Graphic.MatSingle; - //mesh = MeshPool.GridPlane(thingWithComps.def.graphicData.drawSize); - //Graphics.DrawMesh(mesh, drawLoc, Quaternion.AngleAxis(num, Vector3.up), matSingle, 0); + angle += (animationTicks + 1) / 2; + } + } - var s = new Vector3(eq.def.graphicData.drawSize.x, 1f, - eq.def.graphicData.drawSize.y); - var matrix = default(Matrix4x4); - matrix.SetTRS(drawLoc, Quaternion.AngleAxis(num, Vector3.up), s); - if (!flip) Graphics.DrawMesh(MeshPool.plane10, matrix, matSingle, 0); - else Graphics.DrawMesh(MeshPool.plane10Flip, matrix, matSingle, 0); + angle %= 360f; // copied vanilla code - ////Log.Message("DeflectDraw"); - } + var matSingle = eq.Graphic is Graphic_StackCount graphic_StackCount + ? graphic_StackCount.SubGraphicForStackCount(1, eq.def).MatSingle + : eq.Graphic.MatSingle; + var s = new Vector3(eq.def.graphicData.drawSize.x, 1f, + eq.def.graphicData.drawSize.y); + var matrix = Matrix4x4.TRS(drawLoc, Quaternion.AngleAxis(angle, Vector3.up), s); + Graphics.DrawMesh(flip ? MeshPool.plane10Flip : MeshPool.plane10, matrix, matSingle, 0); } + } + } } } public static bool TakeDamage_PreFix(Thing __instance, ref DamageInfo dinfo) { - //Pawn pawn = (Pawn)AccessTools.Field(typeof(Pawn_HealthTracker), "pawn").GetValue(__instance); //if (dinfo.Instigator == null) return true; - try + if (__instance is Pawn pawn) { - if (__instance is Pawn pawn) - { - var pawn_EquipmentTracker = pawn.equipment; - if (pawn_EquipmentTracker?.AllEquipmentListForReading.Count > 0) - foreach (var thingWithComps in pawn_EquipmentTracker.AllEquipmentListForReading) + var pawn_EquipmentTracker = pawn.equipment; + if (pawn_EquipmentTracker != null) + foreach (var thingWithComps in pawn_EquipmentTracker.AllEquipmentListForReading) + { + if (dinfo.Def == DamageDefOf.Bomb || dinfo.Def == DamageDefOf.Flame || dinfo.Def.isExplosive) + continue; + var compDeflector = thingWithComps?.GetCompDeflector(); + if (compDeflector == null) + continue; + if (dinfo.Weapon?.IsMeleeWeapon ?? false) { - ////Log.Message("3"); - var compDeflector = thingWithComps?.GetComp(); - if (compDeflector == null) continue; - if (dinfo.Def == DamageDefOf.Bomb) continue; - if (dinfo.Def == DamageDefOf.Flame) continue; - if (dinfo.Def.isExplosive) continue; - if (!dinfo.Weapon.IsMeleeWeapon) + if (compDeflector.TrySpecialMeleeBlock()) { - compDeflector.PostPreApplyDamage(dinfo, out var newAbsorbed); - if (newAbsorbed) - { - compDeflector.AnimationDeflectionTicks = 1200; - dinfo.SetAmount(0); - return true; - } + dinfo.SetAmount(0); + return true; } - else + } + else + { + compDeflector.PostPreApplyDamage(dinfo, out var absorbed); + if (absorbed) { - if (compDeflector.TrySpecialMeleeBlock()) - { - dinfo.SetAmount(0); - return true; - } + compDeflector.AnimationDeflectionTicks = 1200; + dinfo.SetAmount(0); + return true; } } - } - } - catch (NullReferenceException) - { + } } return true; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDeflector/JobDriver_CastDeflectVerb.cs b/Source/AllModdingComponents/CompDeflector/JobDriver_CastDeflectVerb.cs index bfa40dd5..34aea690 100644 --- a/Source/AllModdingComponents/CompDeflector/JobDriver_CastDeflectVerb.cs +++ b/Source/AllModdingComponents/CompDeflector/JobDriver_CastDeflectVerb.cs @@ -1,25 +1,11 @@ using System.Collections.Generic; -using System.Linq; using RimWorld; -using Verse; using Verse.AI; namespace CompDeflector { public class JobDriver_CastDeflectVerb : JobDriver { - private CompDeflector CompDeflector - { - get - { - var check = pawn.equipment.AllEquipmentListForReading.FirstOrDefault(x => - x.TryGetComp() != null); - if (check != null) - return check.GetComp(); - return null; - } - } - public override void ExposeData() { base.ExposeData(); @@ -32,14 +18,12 @@ public override bool TryMakePreToilReservations(bool errorOnFailed) protected override IEnumerable MakeNewToils() { - ////Log.Message("DeflecVErbcalls"); yield return Toils_Misc.ThrowColonistAttackingMote(TargetIndex.A); - //Toil getInRangeToil = Toils_Combat.GotoCastPosition(TargetIndex.A, false); + //Toil getInRangeToil = Toils_Combat.GotoCastPosition(TargetIndex.A, TargetIndex.B); //yield return getInRangeToil; - var verb = pawn.CurJob.verbToUse as Verb_Deflected; - + //var verb = pawn.CurJob.verbToUse as Verb_Deflected; //Find.Targeter.targetingVerb = verb; - yield return Toils_Combat.CastVerb(TargetIndex.A, false); + yield return Toils_Combat.CastVerb(TargetIndex.A, TargetIndex.B, canHitNonTargetPawns: false); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDeflector/StatWorker_DeflectionChance.cs b/Source/AllModdingComponents/CompDeflector/StatWorker_DeflectionChance.cs index f72387db..37cfb421 100644 --- a/Source/AllModdingComponents/CompDeflector/StatWorker_DeflectionChance.cs +++ b/Source/AllModdingComponents/CompDeflector/StatWorker_DeflectionChance.cs @@ -1,118 +1,95 @@ -using System.Text; +using System.Collections.Generic; +using System.Text; using RimWorld; using Verse; namespace CompDeflector { + // TODO: Should also have a StatWorker_ReflectionAccuracy. public class StatWorker_DeflectionChance : StatWorker { public override float GetValueUnfinalized(StatRequest req, bool applyPostProcess = true) { - return GetBaseDeflectionChance(req, applyPostProcess) + GetSkillLevel(req, applyPostProcess) * - GetDeflectPerSkillLevel(req, applyPostProcess) * GetManipulationModifier(req, applyPostProcess); + if (GetDeflector(req) is CompDeflector compDeflector) + return new CompDeflector.DeflectionChanceCalculator(compDeflector, fixedRandSeed: true).Calculate(); + return 0f; } - private Pawn GetPawn(StatRequest req) + private static CompDeflector GetDeflector(StatRequest req) { - return req.Thing as Pawn; + return req.Thing is Pawn pawn ? GetDeflector(pawn) : null; } - private CompDeflector GetDeflector(StatRequest req) + private static CompDeflector GetDeflector(Pawn pawn) { - if (req.Thing is Pawn pawn) + if (pawn.equipment is Pawn_EquipmentTracker equipmentTracker) { - var pawn_EquipmentTracker = pawn.equipment; - if (pawn_EquipmentTracker != null) - foreach (var thingWithComps in pawn_EquipmentTracker.AllEquipmentListForReading) - if (thingWithComps != null) - { - ////Log.Message("3"); - var compDeflector = thingWithComps.GetComp(); - if (compDeflector != null) - return compDeflector; - } + foreach (var equipment in equipmentTracker.AllEquipmentListForReading) + { + if (equipment?.GetCompDeflector() is CompDeflector compDeflector) + return compDeflector; + } } return null; } - private float GetBaseDeflectionChance(StatRequest req, bool applyPostProcess = true) - { - var compDeflector = GetDeflector(req); - if (compDeflector != null) - return compDeflector.Props.baseDeflectChance; - return 0f; - } - - private float GetSkillLevel(StatRequest req, bool applyPostProcess = true) + public override string GetExplanationUnfinalized(StatRequest req, ToStringNumberSense numberSense) { + // Based off StatWorker_MeleeDPS. + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("StatsReport_DeflectionExplanation".Translate()); + stringBuilder.AppendLine(); var compDeflector = GetDeflector(req); - if (compDeflector != null) - if (compDeflector.Props.useSkillInCalc) + if (compDeflector == null) + { + stringBuilder.AppendLine("NoDeflectorEquipped".Translate() + ": " + ValueToString(0f, finalized: false)); + } + else + { + var props = compDeflector.Props; + var calculator = compDeflector.GetDeflectionChanceCalculator(fixedRandSeed: true); + stringBuilder.AppendLine("StatsReport_BaseDeflectChance".Translate() + ": " + ValueToString(props.baseDeflectChance, finalized: false)); + if (calculator.UseSkill(out var skill)) { - var skillDef = compDeflector.Props.deflectSkill; - if (GetPawn(req).skills != null) - if (GetPawn(req).skills.GetSkill(skillDef) != null) - return GetPawn(req).skills.GetSkill(skillDef).Level; + stringBuilder.AppendLine("StatsReport_DeflectPerSkillLevel".Translate() + ": x" + props.deflectRatePerSkillPoint.ToStringPercent()); + stringBuilder.AppendLine("StatsReport_Skills".Translate()); + var skillLevel = skill.Level; + stringBuilder.AppendLine($" {compDeflector.Props.deflectSkill.LabelCap} ({skillLevel}): +" + + ValueToString(skillLevel * props.deflectRatePerSkillPoint, finalized: false)); } - return 0f; - } - - private float GetDeflectPerSkillLevel(StatRequest req, bool applyPostProcess = true) - { - var compDeflector = GetDeflector(req); - if (compDeflector != null) - if (compDeflector.Props.useSkillInCalc) - return compDeflector.Props.deflectRatePerSkillPoint; - return 0f; - } - - private float GetManipulationModifier(StatRequest req, bool applyPostProcess = true) - { - var pawn = GetPawn(req); - if (pawn != null) - if (pawn.health != null) - if (pawn.health.capacities != null) - return pawn.health.capacities.GetLevel(PawnCapacityDefOf.Manipulation); - return 1.0f; + var calc = calculator.Calculate(); + if (calculator.BeforeInfixValue != calculator.InfixValue) + { + var infixDeclaredType = compDeflector.GetType().GetMethod(nameof(CompDeflector.DeflectionChance_InFix)).DeclaringType; + stringBuilder.AppendLine(infixDeclaredType.Name); + stringBuilder.AppendLine(" " + ValueToString(calculator.BeforeInfixValue, finalized: false) + " => " + + ValueToString(calculator.InfixValue, finalized: false)); + } + if (calculator.UseManipulation(out var capable)) + { + var pawn = compDeflector.GetPawn; + stringBuilder.AppendLine("StatsReport_Health".Translate()); + stringBuilder.Append($" {PawnCapacityDefOf.Manipulation.GetLabelFor(pawn).CapitalizeFirst()}: x"); + if (capable) + stringBuilder.AppendLine(pawn.health.capacities.GetLevel(PawnCapacityDefOf.Manipulation).ToStringPercent()); + else + stringBuilder.AppendLine($"{0f.ToStringPercent()} ({"Incapable".Translate()})"); + } + } + return stringBuilder.ToString(); } - public override string GetExplanationUnfinalized(StatRequest req, ToStringNumberSense numberSense) + public override bool IsDisabledFor(Thing thing) { - var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine( - "Stat is displayed in the following format:\nDeflection chance equals ( Base chance + ( Skill Level * % per Skill Level) / Manipulation Efficiency\n\n"); - //stringBuilder.AppendLine("StatsReport_DeflectionExplanation".Translate()); - stringBuilder.AppendLine(); - stringBuilder.AppendLine("Base deflect chance"); - //stringBuilder.AppendLine("StatsReport_BaseDeflectChance".Translate()); - stringBuilder.AppendLine(" " + GetBaseDeflectionChance(req, true).ToStringPercent()); - stringBuilder.AppendLine(); - stringBuilder.AppendLine("Skill level"); - //stringBuilder.AppendLine("StatsReport_SkillLevel".Translate()); - stringBuilder.AppendLine(" " + GetSkillLevel(req, true).ToString("0")); - stringBuilder.AppendLine(); - stringBuilder.AppendLine("Deflect % per skill level"); - //stringBuilder.AppendLine("StatsReport_DeflectPerSkillLevel".Translate()); - stringBuilder.AppendLine(" " + GetDeflectPerSkillLevel(req, true).ToStringPercent("0.##")); - stringBuilder.AppendLine(); - stringBuilder.AppendLine("Manipulation modifier"); - //stringBuilder.AppendLine("StatsReport_ManipulationModifier".Translate()); - stringBuilder.AppendLine(" " + GetManipulationModifier(req, true).ToStringPercent()); - stringBuilder.AppendLine(); - return stringBuilder.ToString(); + return thing is Pawn pawn && GetDeflector(pawn) is CompDeflector compDeflector && + compDeflector.GetDeflectionChanceCalculator(fixedRandSeed: true).UseSkill(out var skill) && skill.TotallyDisabled; } - // Tad changed missing additional final parameter on the end, the "finalized" bool. - public override string GetStatDrawEntryLabel(StatDef stat, float value, ToStringNumberSense numberSense, StatRequest optionalReq, bool finalized = true) + public override IEnumerable GetInfoCardHyperlinks(StatRequest statRequest) { - return string.Format("{0} (({1} + ( {2} * {3} )) / {4} )", - value.ToStringByStyle(stat.toStringStyle, numberSense), - GetBaseDeflectionChance(optionalReq, true).ToStringPercent(), - GetSkillLevel(optionalReq, true).ToString("0"), - GetDeflectPerSkillLevel(optionalReq, true).ToStringPercent("0.##"), - GetManipulationModifier(optionalReq, true).ToStringPercent(), - finalized); + var compDeflector = GetDeflector(statRequest); + if (compDeflector != null) + yield return new Dialog_InfoCard.Hyperlink(compDeflector.parent); } - } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDeflector/Verb_Deflected.cs b/Source/AllModdingComponents/CompDeflector/Verb_Deflected.cs index f8ab5324..1adb572b 100644 --- a/Source/AllModdingComponents/CompDeflector/Verb_Deflected.cs +++ b/Source/AllModdingComponents/CompDeflector/Verb_Deflected.cs @@ -9,7 +9,8 @@ public class Verb_Deflected : Verb_Shoot public override bool CanHitTargetFrom(IntVec3 root, LocalTargetInfo targ) { - if (lastShotReflected) return true; + if (lastShotReflected) + return true; return base.CanHitTargetFrom(root, targ); } @@ -21,15 +22,13 @@ protected override bool TryCastShot() public bool TryCastShot_V1Vanilla_Modified() { - var result = false; - if (currentTarget.HasThing && currentTarget.Thing.Map != caster.Map) return false; var flag = TryFindShootLineFromTo(caster.Position, currentTarget, out var shootLine); if (verbProps.stopBurstWithoutLos && !flag) return false; var drawPos = caster.DrawPos; - var projectile = (Projectile) GenSpawn.Spawn(verbProps.defaultProjectile, shootLine.Source, caster.Map); + var projectile = (Projectile)GenSpawn.Spawn(verbProps.defaultProjectile, shootLine.Source, caster.Map); ///MODIFIED SECTION //////////////////////////////////////////// @@ -37,7 +36,7 @@ public bool TryCastShot_V1Vanilla_Modified() if (lastShotReflected) { ////Log.Message("lastShotReflected Called"); - projectile.Launch(caster, currentTarget, currentTarget, ProjectileHitFlags.IntendedTarget, EquipmentSource); //TODO + projectile.Launch(caster, currentTarget, currentTarget, ProjectileHitFlags.IntendedTarget, preventFriendlyFire, EquipmentSource); return true; } @@ -45,18 +44,19 @@ public bool TryCastShot_V1Vanilla_Modified() // //projectile.FreeIntercept = canFreeInterceptNow && !projectile.def.projectile.flyOverhead; - if (verbProps.forcedMissRadius > 0.5f) + var forcedMissRadius = verbProps.ForcedMissRadius; + if (forcedMissRadius > 0.5f) { - float num = VerbUtility.CalculateAdjustedForcedMiss(this.verbProps.forcedMissRadius, - this.currentTarget.Cell - this.caster.Position); + var num = VerbUtility.CalculateAdjustedForcedMiss(forcedMissRadius, + currentTarget.Cell - caster.Position); if (num > 0.5f) { - int max = GenRadial.NumCellsInRadius(this.verbProps.forcedMissRadius); - int num2 = Rand.Range(0, max); + var max = GenRadial.NumCellsInRadius(forcedMissRadius); + var num2 = Rand.Range(0, max); if (num2 > 0) { if (DebugViewSettings.drawShooting) - MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToForRad", -1f); + MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToForRad"); // TODO: Translate()? var c = currentTarget.Cell + GenRadial.RadialPattern[num2]; ProjectileHitFlags projectileHitFlags; if (Rand.Chance(0.5f)) @@ -67,23 +67,23 @@ public bool TryCastShot_V1Vanilla_Modified() { projectileHitFlags = ProjectileHitFlags.All; } - if (!this.canHitNonTargetPawnsNow) + if (!canHitNonTargetPawnsNow) { projectileHitFlags &= ~ProjectileHitFlags.NonTargetPawns; } - projectile.Launch(caster, currentTarget, c, projectileHitFlags, EquipmentSource); //TODO + projectile.Launch(caster, currentTarget, c, projectileHitFlags, preventFriendlyFire, EquipmentSource); return true; } } } var shotReport = ShotReport.HitReportFor(caster, this, currentTarget); - Thing randomCoverToMissInto = shotReport.GetRandomCoverToMissInto(); - ThingDef targetCoverDef = (randomCoverToMissInto == null) ? null : randomCoverToMissInto.def; + var randomCoverToMissInto = shotReport.GetRandomCoverToMissInto(); + var targetCoverDef = randomCoverToMissInto?.def; if (!Rand.Chance(shotReport.AimOnTargetChance_IgnoringPosture)) { if (DebugViewSettings.drawShooting) { - MoteMaker.ThrowText(this.caster.DrawPos, this.caster.Map, "ToWild", -1f); + MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToWild"); // TODO: Translate()? } shootLine.ChangeDestToMissWild(shotReport.AimOnTargetChance_StandardTarget); ProjectileHitFlags projectileHitFlags2; @@ -94,26 +94,28 @@ public bool TryCastShot_V1Vanilla_Modified() else { projectileHitFlags2 = ProjectileHitFlags.NonTargetWorld; - if (this.canHitNonTargetPawnsNow) + if (canHitNonTargetPawnsNow) { projectileHitFlags2 |= ProjectileHitFlags.NonTargetPawns; } } - projectile.Launch(caster, currentTarget, shootLine.Dest, projectileHitFlags2, EquipmentSource); //TODO + projectile.Launch(caster, currentTarget, shootLine.Dest, projectileHitFlags2, + preventFriendlyFire, EquipmentSource); return true; } - if (this.currentTarget.Thing != null && this.currentTarget.Thing.def.category == ThingCategory.Pawn && !Rand.Chance(shotReport.PassCoverChance)) + if (currentTarget.Thing != null && currentTarget.Thing.def.category == ThingCategory.Pawn && !Rand.Chance(shotReport.PassCoverChance)) { if (DebugViewSettings.drawShooting) - MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToCover", -1f); + MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToCover"); // TODO: Translate()? if (currentTarget.Thing != null && currentTarget.Thing.def.category == ThingCategory.Pawn) { - ProjectileHitFlags projectileHitFlags5 = ProjectileHitFlags.NonTargetWorld; - if (this.canHitNonTargetPawnsNow) + var projectileHitFlags5 = ProjectileHitFlags.NonTargetWorld; + if (canHitNonTargetPawnsNow) { projectileHitFlags5 |= ProjectileHitFlags.NonTargetPawns; } - projectile.Launch(caster, currentTarget, randomCoverToMissInto, projectileHitFlags5, EquipmentSource); + projectile.Launch(caster, currentTarget, randomCoverToMissInto, projectileHitFlags5, + preventFriendlyFire, EquipmentSource); return true; } } @@ -123,47 +125,47 @@ public bool TryCastShot_V1Vanilla_Modified() { if (DebugViewSettings.drawShooting) { - MoteMaker.ThrowText(this.caster.DrawPos, this.caster.Map, "ToCover", -1f); + MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToCover"); // TODO: Translate()? } - if (this.currentTarget.Thing != null && this.currentTarget.Thing.def.category == ThingCategory.Pawn) + if (currentTarget.Thing != null && currentTarget.Thing.def.category == ThingCategory.Pawn) { - ProjectileHitFlags projectileHitFlags3 = ProjectileHitFlags.NonTargetWorld; - if (this.canHitNonTargetPawnsNow) + var projectileHitFlags3 = ProjectileHitFlags.NonTargetWorld; + if (canHitNonTargetPawnsNow) { projectileHitFlags3 |= ProjectileHitFlags.NonTargetPawns; } - projectile.Launch(caster, drawPos, randomCoverToMissInto, this.currentTarget, - projectileHitFlags3, EquipmentSource, targetCoverDef); + projectile.Launch(caster, drawPos, randomCoverToMissInto, currentTarget, + projectileHitFlags3, preventFriendlyFire, EquipmentSource, targetCoverDef); return true; } } if (DebugViewSettings.drawShooting) { - MoteMaker.ThrowText(this.caster.DrawPos, this.caster.Map, "ToHit", -1f); + MoteMaker.ThrowText(caster.DrawPos, caster.Map, "ToHit"); // TODO: Translate()? } - ProjectileHitFlags projectileHitFlags4 = ProjectileHitFlags.IntendedTarget; - if (this.canHitNonTargetPawnsNow) + var projectileHitFlags4 = ProjectileHitFlags.IntendedTarget; + if (canHitNonTargetPawnsNow) { projectileHitFlags4 |= ProjectileHitFlags.NonTargetPawns; } - if (!this.currentTarget.HasThing || this.currentTarget.Thing.def.Fillage == FillCategory.Full) + if (!currentTarget.HasThing || currentTarget.Thing.def.Fillage == FillCategory.Full) { projectileHitFlags4 |= ProjectileHitFlags.NonTargetWorld; } - if (this.currentTarget.Thing != null) + if (currentTarget.Thing != null) { - projectile.Launch(caster, drawPos, this.currentTarget, this.currentTarget, projectileHitFlags4, - EquipmentSource, targetCoverDef); + projectile.Launch(caster, drawPos, currentTarget, currentTarget, projectileHitFlags4, + preventFriendlyFire, EquipmentSource, targetCoverDef); } else { - projectile.Launch(caster, drawPos, shootLine.Dest, this.currentTarget, projectileHitFlags4, - EquipmentSource, targetCoverDef); + projectile.Launch(caster, drawPos, shootLine.Dest, currentTarget, projectileHitFlags4, + preventFriendlyFire, EquipmentSource, targetCoverDef); } - result = true; + return true; } - return result; + return false; } - + } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDelayedSpawner/CompDelayedSpawner.cs b/Source/AllModdingComponents/CompDelayedSpawner/CompDelayedSpawner.cs index 8fa380ac..2de55866 100644 --- a/Source/AllModdingComponents/CompDelayedSpawner/CompDelayedSpawner.cs +++ b/Source/AllModdingComponents/CompDelayedSpawner/CompDelayedSpawner.cs @@ -1,5 +1,5 @@ using System; -using System.Linq; +using System.Collections.Generic; using Verse; namespace CompDelayedSpawner @@ -20,11 +20,8 @@ public class CompDelayedSpawner : ThingComp public override void CompTick() { base.CompTick(); - //Log.Message("Tick"); if (parent.Spawned && !isSpawning && Find.TickManager.TicksGame % Props.tickRate == 0) { - //Log.Message("Tick2"); - if (ticksLeft == -999) ticksLeft = Props.ticksUntilSpawning; @@ -66,10 +63,13 @@ private void SpawnThings(SpawnInfo info) private void SpawnPawns(SpawnInfo info) { - var spawnPosition = Position; - if ((from cell in GenAdj.CellsAdjacent8Way(new TargetInfo(Position, Map)) - where Position.Walkable(Map) - select cell).TryRandomElement(out spawnPosition)) + var walkableAdjCells = new List(); + foreach (var cell in GenAdj.CellsAdjacent8Way(new TargetInfo(Position, Map))) + { + if (Position.Walkable(Map)) + walkableAdjCells.Add(cell); + } + if (walkableAdjCells.TryRandomElement(out var spawnPosition)) { var pawn = PawnGenerator.GeneratePawn(info.pawnKind, Find.FactionManager.FirstFactionOfDef(info.faction) ?? null); @@ -82,15 +82,15 @@ where Position.Walkable(Map) } } - private void GiveMentalState(SpawnInfo info, Pawn pawn) + private static void GiveMentalState(SpawnInfo info, Pawn pawn) { if (info.withMentalState != null) pawn.mindState.mentalStateHandler.TryStartMentalState(info.withMentalState); } - private void GiveHediffs(SpawnInfo info, Pawn pawn) + private static void GiveHediffs(SpawnInfo info, Pawn pawn) { - if (!info.withHediffs.NullOrEmpty()) + if (info.withHediffs != null) foreach (var hediff in info.withHediffs) if (HediffMaker.MakeHediff(hediff, pawn, null) is Hediff tempHediff) pawn.health.AddHediff(tempHediff, null, null); @@ -108,7 +108,7 @@ public void ResolveDestroySettings() { if (Props.destroyAfterSpawn) { - parent.Destroy(DestroyMode.Vanish); + parent.Destroy(); return; } @@ -122,8 +122,8 @@ public void ResolveDestroySettings() public override void PostExposeData() { base.PostExposeData(); - Scribe_Values.Look(ref isSpawning, "isSpawning", false); - Scribe_Values.Look(ref ticksLeft, "ticksLeft", -999); + Scribe_Values.Look(ref isSpawning, nameof(isSpawning)); + Scribe_Values.Look(ref ticksLeft, nameof(ticksLeft), -999); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompDelayedSpawner/CompDelayedSpawner.csproj b/Source/AllModdingComponents/CompDelayedSpawner/CompDelayedSpawner.csproj index 466dd2fb..0be129ac 100644 --- a/Source/AllModdingComponents/CompDelayedSpawner/CompDelayedSpawner.csproj +++ b/Source/AllModdingComponents/CompDelayedSpawner/CompDelayedSpawner.csproj @@ -1,60 +1,7 @@  - - + + - Debug - AnyCPU - {4074F652-2FDA-41D0-A631-F6C83A2351F1} - Library - Properties - CompDelayedSpawner CompDelayedSpawner - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompDelayedSpawner/CompProperties_DelayedSpawner.cs b/Source/AllModdingComponents/CompDelayedSpawner/CompProperties_DelayedSpawner.cs index ba31d2a2..5c5a3e90 100644 --- a/Source/AllModdingComponents/CompDelayedSpawner/CompProperties_DelayedSpawner.cs +++ b/Source/AllModdingComponents/CompDelayedSpawner/CompProperties_DelayedSpawner.cs @@ -19,12 +19,12 @@ public class CompProperties_DelayedSpawner : CompProperties public bool destroyAfterSpawn = true; public List spawnList = new List(); public bool spawnsOnce = true; - public int tickRate = 60; //1 second - public int ticksUntilSpawning = 30; //30 seconds + public int tickRate = GenTicks.TicksPerRealSecond; + public int ticksUntilSpawning = 30; // in seconds public CompProperties_DelayedSpawner() { compClass = typeof(CompDelayedSpawner); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompExtraSounds/CompExtraSounds.cs b/Source/AllModdingComponents/CompExtraSounds/CompExtraSounds.cs index 3c2220d1..736f23fd 100644 --- a/Source/AllModdingComponents/CompExtraSounds/CompExtraSounds.cs +++ b/Source/AllModdingComponents/CompExtraSounds/CompExtraSounds.cs @@ -4,6 +4,6 @@ namespace CompExtraSounds { internal class CompExtraSounds : ThingComp { - public CompProperties_ExtraSounds Props => (CompProperties_ExtraSounds) props; + public CompProperties_ExtraSounds Props => (CompProperties_ExtraSounds)props; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompExtraSounds/CompExtraSounds.csproj b/Source/AllModdingComponents/CompExtraSounds/CompExtraSounds.csproj index ed2495dc..234b16d3 100755 --- a/Source/AllModdingComponents/CompExtraSounds/CompExtraSounds.csproj +++ b/Source/AllModdingComponents/CompExtraSounds/CompExtraSounds.csproj @@ -1,59 +1,7 @@  - - + + - Debug - AnyCPU - {05E24FAB-C6BF-43B5-BF69-B92AA38338CA} - Library - Properties - CompExtraSounds CompExtraSounds - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - - - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompExtraSounds/CompProperties_ExtraSounds.cs b/Source/AllModdingComponents/CompExtraSounds/CompProperties_ExtraSounds.cs index 29b26a45..ebd812a9 100644 --- a/Source/AllModdingComponents/CompExtraSounds/CompProperties_ExtraSounds.cs +++ b/Source/AllModdingComponents/CompExtraSounds/CompProperties_ExtraSounds.cs @@ -15,4 +15,4 @@ public CompProperties_ExtraSounds() compClass = typeof(CompExtraSounds); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompExtraSounds/DefModExtension_ExtraSounds.cs b/Source/AllModdingComponents/CompExtraSounds/DefModExtension_ExtraSounds.cs index 1116f75a..a94851c8 100644 --- a/Source/AllModdingComponents/CompExtraSounds/DefModExtension_ExtraSounds.cs +++ b/Source/AllModdingComponents/CompExtraSounds/DefModExtension_ExtraSounds.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Verse; +using Verse; namespace CompExtraSounds { diff --git a/Source/AllModdingComponents/CompExtraSounds/ExtraSoundsUtility.cs b/Source/AllModdingComponents/CompExtraSounds/ExtraSoundsUtility.cs new file mode 100644 index 00000000..903d9531 --- /dev/null +++ b/Source/AllModdingComponents/CompExtraSounds/ExtraSoundsUtility.cs @@ -0,0 +1,37 @@ +using Verse; + +namespace CompExtraSounds +{ + public static class ExtraSoundsUtility + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + internal static CompExtraSounds GetCompExtraSounds(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompExtraSounds comp) + return comp; + } + return null; + } + + // Avoiding Def.GetModExtension and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static DefModExtension_ExtraSounds GetModExtensionExtraSounds(this Def def) + { + var modExtensions = def.modExtensions; + if (modExtensions == null) + return null; + for (int i = 0, count = modExtensions.Count; i < count; i++) + { + if (modExtensions[i] is DefModExtension_ExtraSounds modExtension) + return modExtension; + } + return null; + } + } +} diff --git a/Source/AllModdingComponents/CompExtraSounds/HarmonyCompExtraSounds.cs b/Source/AllModdingComponents/CompExtraSounds/HarmonyCompExtraSounds.cs index ac2348f3..2e7e3a8b 100644 --- a/Source/AllModdingComponents/CompExtraSounds/HarmonyCompExtraSounds.cs +++ b/Source/AllModdingComponents/CompExtraSounds/HarmonyCompExtraSounds.cs @@ -10,102 +10,44 @@ internal static class HarmonyCompExtraSounds static HarmonyCompExtraSounds() { var harmony = new Harmony("jecstools.jecrell.comps.sounds"); - - - harmony.Patch(AccessTools.Method(typeof(Verb_MeleeAttack), "SoundMiss"), null, - new HarmonyMethod(typeof(HarmonyCompExtraSounds), "SoundMissPrefix")); - harmony.Patch(AccessTools.Method(typeof(Verb_MeleeAttack), "SoundHitPawn"), null, - new HarmonyMethod(typeof(HarmonyCompExtraSounds), "SoundHitPawnPrefix")); - harmony.Patch(AccessTools.Method(typeof(Verb_MeleeAttack), "SoundHitBuilding"), null, - new HarmonyMethod(typeof(HarmonyCompExtraSounds), "SoundHitBuildingPrefix")); + var type = typeof(HarmonyCompExtraSounds); + + harmony.Patch(AccessTools.Method(typeof(Verb_MeleeAttack), "SoundMiss"), + postfix: new HarmonyMethod(type, nameof(SoundMissPostfix))); + harmony.Patch(AccessTools.Method(typeof(Verb_MeleeAttack), "SoundHitPawn"), + postfix: new HarmonyMethod(type, nameof(SoundHitPawnPostfix))); + harmony.Patch(AccessTools.Method(typeof(Verb_MeleeAttack), "SoundHitBuilding"), + postfix: new HarmonyMethod(type, nameof(SoundHitBuildingPostfix))); } - //=================================== COMPEXTRASOUNDS - public static void SoundHitPawnPrefix(ref SoundDef __result, Verb_MeleeAttack __instance) + public static void SoundHitPawnPostfix(ref SoundDef __result, Verb_MeleeAttack __instance) { if (__instance.caster is Pawn pawn) { - var pawn_PawnKindDef = pawn.kindDef; - if (pawn_PawnKindDef != null) - { - var extraSoundsExtension = pawn_PawnKindDef.GetModExtension(); - if (extraSoundsExtension != null) - { - if (extraSoundsExtension != null) - if (extraSoundsExtension.soundHitPawn != null) - __result = extraSoundsExtension.soundHitPawn; - } - } - - var pawn_EquipmentTracker = pawn.equipment; - if (pawn_EquipmentTracker != null) - { - //Log.Message("2"); - var thingWithComps = - pawn_EquipmentTracker - .Primary; // (ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); + if (pawn.kindDef?.GetModExtensionExtraSounds()?.soundHitPawn is SoundDef modExtSoundHitPawn) + __result = modExtSoundHitPawn; - if (thingWithComps != null) - { - //Log.Message("3"); - var CompExtraSounds = thingWithComps.GetComp(); - - if (CompExtraSounds != null) - if (CompExtraSounds.Props.soundHitPawn != null) - __result = CompExtraSounds.Props.soundHitPawn; - } - } + if (pawn.equipment?.Primary?.GetCompExtraSounds()?.Props.soundHitPawn is SoundDef soundHitPawn) + __result = soundHitPawn; } } - public static void SoundMissPrefix(ref SoundDef __result, Verb_MeleeAttack __instance) + public static void SoundMissPostfix(ref SoundDef __result, Verb_MeleeAttack __instance) { if (__instance.caster is Pawn pawn) { - var pawn_EquipmentTracker = pawn.equipment; - if (pawn_EquipmentTracker != null) - { - //Log.Message("2"); - var thingWithComps = - pawn_EquipmentTracker - .Primary; // (ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); - - if (thingWithComps != null) - { - //Log.Message("3"); - var CompExtraSounds = thingWithComps.GetComp(); - if (CompExtraSounds != null) - if (CompExtraSounds.Props.soundMiss != null) - __result = CompExtraSounds.Props.soundMiss; - } - } + if (pawn.equipment?.Primary?.GetCompExtraSounds()?.Props.soundMiss is SoundDef soundMiss) + __result = soundMiss; } } - public static void SoundHitBuildingPrefix(ref SoundDef __result, Verb_MeleeAttack __instance) + public static void SoundHitBuildingPostfix(ref SoundDef __result, Verb_MeleeAttack __instance) { if (__instance.caster is Pawn pawn) { - var pawn_EquipmentTracker = pawn.equipment; - if (pawn_EquipmentTracker != null) - { - //Log.Message("2"); - var thingWithComps = - pawn_EquipmentTracker - .Primary; // (ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); - - if (thingWithComps != null) - { - //Log.Message("3"); - var CompExtraSounds = thingWithComps.GetComp(); - if (CompExtraSounds != null) - if (CompExtraSounds.Props.soundHitBuilding != null) - { - __result = CompExtraSounds.Props.soundHitBuilding; - } - } - } + if (pawn.equipment?.Primary?.GetCompExtraSounds()?.Props.soundHitBuilding is SoundDef soundHitBuilding) + __result = soundHitBuilding; } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompInstalledPart/CompInstalledPart.cs b/Source/AllModdingComponents/CompInstalledPart/CompInstalledPart.cs index 46642fe6..4a393748 100644 --- a/Source/AllModdingComponents/CompInstalledPart/CompInstalledPart.cs +++ b/Source/AllModdingComponents/CompInstalledPart/CompInstalledPart.cs @@ -1,26 +1,60 @@ using RimWorld; using Verse; -using Verse.AI; namespace CompInstalledPart { public class CompInstalledPart : ThingComp { + public CompProperties_InstalledPart Props => (CompProperties_InstalledPart)props; + public bool uninstalled; - public CompProperties_InstalledPart Props => (CompProperties_InstalledPart) props; + private CompEquippable compEquippable; + + public CompEquippable GetEquippable => compEquippable; + + // Caching comps needs to happen after all comps are created. Ideally, this would be done right after + // ThingWithComps.InitializeComps(). This requires overriding two hooks: PostPostMake and PostExposeData. + + public override void PostPostMake() + { + base.PostPostMake(); + CacheComps(); + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref uninstalled, nameof(uninstalled)); + if (Scribe.mode == LoadSaveMode.LoadingVars) + CacheComps(); + } + + private void CacheComps() + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + var comps = parent.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompEquippable compEquippable) + { + this.compEquippable = compEquippable; + break; + } + } + } public void GiveInstallJob(Pawn actor, Thing target) { - var actorFac = actor?.Faction; - var targetFac = target?.Faction; - if (actorFac != null && targetFac != null) + if (actor?.Faction is Faction actorFac && target?.Faction is Faction targetFac) if (actorFac == targetFac) { - var newJob = new Job(DefDatabase.GetNamed("CompInstalledPart_InstallPart"), parent, target, + var newJob = JobMaker.MakeJob(CompInstalledPartDefOf.CompInstalledPart_InstallPart, parent, target, target.Position); newJob.count = 2; - actor?.jobs?.TryTakeOrderedJob(newJob); + actor.jobs?.TryTakeOrderedJob(newJob); } else if (actorFac != targetFac) { @@ -30,15 +64,13 @@ public void GiveInstallJob(Pawn actor, Thing target) public void GiveUninstallJob(Pawn actor, Thing target) { - var actorFac = actor?.Faction; - var targetFac = target?.Faction; - if (actorFac != null && targetFac != null) + if (actor?.Faction is Faction actorFac && target?.Faction is Faction targetFac) if (actorFac == targetFac) { - var newJob = new Job(DefDatabase.GetNamed("CompInstalledPart_UninstallPart"), parent, + var newJob = JobMaker.MakeJob(CompInstalledPartDefOf.CompInstalledPart_UninstallPart, parent, target, target.Position); newJob.count = 1; - actor?.jobs?.TryTakeOrderedJob(newJob); + actor.jobs?.TryTakeOrderedJob(newJob); } else if (actorFac != targetFac) { @@ -57,13 +89,13 @@ public void Notify_Installed(Pawn installer, Thing target) if (parent.def.IsApparel && targetPawn.apparel != null) { parent.DeSpawn(); - targetPawn.apparel.Wear((Apparel) parent); + targetPawn.apparel.Wear((Apparel)parent); } //Add equipment if (parent.def.IsWeapon) { - if (targetPawn?.equipment?.Primary?.GetComp() is CompInstalledPart otherPart) + if (targetPawn.equipment.Primary?.GetCompInstalledPart() is CompInstalledPart otherPart) otherPart.Notify_Uninstalled(installer, targetPawn); parent.DeSpawn(); targetPawn.equipment.MakeRoomFor(parent); @@ -95,13 +127,13 @@ public void Notify_Uninstalled(Pawn uninstaller, Thing partOrigin) { //Remove apparel if (parent.def.IsApparel && targetPawn.apparel is Pawn_ApparelTracker tracker && - tracker.WornApparel.Contains((Apparel) parent) && - tracker.TryDrop((Apparel) parent, out var apparel)) + tracker.WornApparel.Contains((Apparel)parent) && + tracker.TryDrop((Apparel)parent, out _)) { } //Remove equipment if (parent.def.IsWeapon && targetPawn.equipment is Pawn_EquipmentTracker eqTracker && - eqTracker.TryDropEquipment(parent, out var dropped, targetPawn.Position)) + eqTracker.TryDropEquipment(parent, out _, targetPawn.Position)) { } } @@ -120,11 +152,5 @@ public void Notify_Uninstalled(Pawn uninstaller, Thing partOrigin) "CompInstalledPart_Uninstalled".Translate(uninstaller.LabelShort, parent.LabelShort, partOrigin.LabelShort), MessageTypeDefOf.PositiveEvent); } - - public override void PostExposeData() - { - base.PostExposeData(); - Scribe_Values.Look(ref uninstalled, "uninstalled", false); - } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompInstalledPart/CompInstalledPart.csproj b/Source/AllModdingComponents/CompInstalledPart/CompInstalledPart.csproj index 6e19a673..daa88500 100755 --- a/Source/AllModdingComponents/CompInstalledPart/CompInstalledPart.csproj +++ b/Source/AllModdingComponents/CompInstalledPart/CompInstalledPart.csproj @@ -1,75 +1,10 @@  - - + + - Debug - AnyCPU - {6ADE9377-5108-4C79-A3E8-034A7EBCC37F} - Library - Properties - CompInstalledPart CompInstalledPart - v4.7.2 - 512 - - - true - full - false - ..\..\..\Assemblies\ - - - prompt - 4 - false - true - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - False - ..\..\..\Assemblies\0JecsTools.dll - - - - - - - - - - - - - - {106BF102-0379-41CF-9C5D-E21AAC5F051B} - JecsTools - - - - 1.1.2566 - - - 2.0.0.8 - + - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompInstalledPart/CompInstalledPartDefOf.cs b/Source/AllModdingComponents/CompInstalledPart/CompInstalledPartDefOf.cs new file mode 100644 index 00000000..c13ec6d6 --- /dev/null +++ b/Source/AllModdingComponents/CompInstalledPart/CompInstalledPartDefOf.cs @@ -0,0 +1,14 @@ +using RimWorld; +using Verse; + +namespace CompInstalledPart +{ + [DefOf] + public static class CompInstalledPartDefOf + { + public static JobDef CompInstalledPart_InstallPart; + public static JobDef CompInstalledPart_UninstallPart; + + static CompInstalledPartDefOf() => DefOfHelper.EnsureInitializedInCtor(typeof(CompInstalledPartDefOf)); + } +} diff --git a/Source/AllModdingComponents/CompInstalledPart/CompProperties_InstalledPart.cs b/Source/AllModdingComponents/CompInstalledPart/CompProperties_InstalledPart.cs index ec5813dc..f8d528f2 100644 --- a/Source/AllModdingComponents/CompInstalledPart/CompProperties_InstalledPart.cs +++ b/Source/AllModdingComponents/CompInstalledPart/CompProperties_InstalledPart.cs @@ -20,4 +20,4 @@ public CompProperties_InstalledPart() compClass = typeof(CompInstalledPart); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompInstalledPart/HarmonyCompInstalledPart.cs b/Source/AllModdingComponents/CompInstalledPart/HarmonyCompInstalledPart.cs index fd5b55f1..104eca4a 100644 --- a/Source/AllModdingComponents/CompInstalledPart/HarmonyCompInstalledPart.cs +++ b/Source/AllModdingComponents/CompInstalledPart/HarmonyCompInstalledPart.cs @@ -1,10 +1,8 @@ -using System.Collections.Generic; -using System.Linq; +using System; using HarmonyLib; using RimWorld; using UnityEngine; using Verse; -using Verse.Sound; namespace CompInstalledPart { @@ -14,60 +12,52 @@ internal static class HarmonyCompInstalledPart static HarmonyCompInstalledPart() { var harmony = new Harmony("jecstools.jecrell.comps.installedpart"); - //harmony.Patch(AccessTools.Method(typeof(FloatMenuMakerMap), "AddHumanlikeOrders"), null, new HarmonyMethod(typeof(HarmonyCompInstalledPart), "AddHumanlikeOrders_PostFix")); + var type = typeof(HarmonyCompInstalledPart); + harmony.Patch(AccessTools.Method(typeof(ITab_Pawn_Gear), "InterfaceDrop"), - new HarmonyMethod(typeof(HarmonyCompInstalledPart).GetMethod("InterfaceDrop_PreFix")), null); - harmony.Patch(AccessTools.Method(typeof(Pawn_EquipmentTracker), "TryDropEquipment"), - new HarmonyMethod(typeof(HarmonyCompInstalledPart), "TryDropEquipment_PreFix"), null); - harmony.Patch(typeof(PawnRenderer).GetMethod("DrawEquipmentAiming"), - new HarmonyMethod(typeof(HarmonyCompInstalledPart).GetMethod("DrawEquipmentAiming_PreFix")), null); + prefix: new HarmonyMethod(type, nameof(InterfaceDrop_PreFix))); + harmony.Patch(AccessTools.Method(typeof(Pawn_EquipmentTracker), nameof(Pawn_EquipmentTracker.TryDropEquipment)), + prefix: new HarmonyMethod(type, nameof(TryDropEquipment_PreFix))); + harmony.Patch(AccessTools.Method(typeof(PawnRenderer), nameof(PawnRenderer.DrawEquipmentAiming)), + prefix: new HarmonyMethod(type, nameof(DrawEquipmentAiming_PreFix))); } - - public static bool DrawEquipmentAiming_PreFix(PawnRenderer __instance, Thing eq, Vector3 drawLoc, + public static bool DrawEquipmentAiming_PreFix(Pawn ___pawn, Thing eq, Vector3 drawLoc, float aimAngle) { - var pawn = (Pawn) AccessTools.Field(typeof(PawnRenderer), "pawn").GetValue(__instance); - if (pawn != null && eq is ThingWithComps x && - x.GetComp() is CompInstalledPart installedComp) + if (___pawn != null && eq.TryGetCompInstalledPart() is CompInstalledPart installedComp) { + // start copied vanilla code (with mesh = flip ? MeshPool.plane10Flip : MeshPool.plane10) var flip = false; - var num = aimAngle - 90f; - Mesh mesh; + var angle = aimAngle - 90f; if (aimAngle > 20f && aimAngle < 160f) { - mesh = MeshPool.plane10; - num += eq.def.equippedAngleOffset; + angle += eq.def.equippedAngleOffset; } else if (aimAngle > 200f && aimAngle < 340f) { - mesh = MeshPool.plane10Flip; flip = true; - num -= 180f; - num -= eq.def.equippedAngleOffset; + angle -= 180f; + angle -= eq.def.equippedAngleOffset; } else { - mesh = MeshPool.plane10; - num += eq.def.equippedAngleOffset; + angle += eq.def.equippedAngleOffset; } - num %= 360f; - var graphic_StackCount = installedComp?.Props?.installedWeaponGraphic?.Graphic as Graphic_StackCount ?? - eq.Graphic as Graphic_StackCount; - Material matSingle; - if (graphic_StackCount != null) - matSingle = graphic_StackCount.SubGraphicForStackCount(1, eq.def).MatSingle; - else - matSingle = installedComp?.Props?.installedWeaponGraphic?.Graphic?.MatSingle ?? - eq.Graphic.MatSingle; + angle %= 360f; + // end copied vanilla code + var installedWeaponGraphic = installedComp.Props?.installedWeaponGraphic; + var graphic_StackCount = installedWeaponGraphic?.Graphic as Graphic_StackCount ?? + eq.Graphic as Graphic_StackCount; + var matSingle = graphic_StackCount != null + ? graphic_StackCount.SubGraphicForStackCount(1, eq.def).MatSingle + : installedWeaponGraphic?.Graphic?.MatSingle ?? eq.Graphic.MatSingle; var s = new Vector3( - installedComp?.Props?.installedWeaponGraphic?.drawSize.x ?? eq.def.graphicData.drawSize.x, 1f, - installedComp?.Props?.installedWeaponGraphic?.drawSize.y ?? eq.def.graphicData.drawSize.y); - var matrix = default(Matrix4x4); - matrix.SetTRS(drawLoc, Quaternion.AngleAxis(num, Vector3.up), s); - if (!flip) Graphics.DrawMesh(MeshPool.plane10, matrix, matSingle, 0); - else Graphics.DrawMesh(MeshPool.plane10Flip, matrix, matSingle, 0); + installedWeaponGraphic?.drawSize.x ?? eq.def.graphicData.drawSize.x, 1f, + installedWeaponGraphic?.drawSize.y ?? eq.def.graphicData.drawSize.y); + var matrix = Matrix4x4.TRS(drawLoc, Quaternion.AngleAxis(angle, Vector3.up), s); + Graphics.DrawMesh(flip ? MeshPool.plane10Flip : MeshPool.plane10, matrix, matSingle, 0); return false; } return true; @@ -78,122 +68,29 @@ public static bool DrawEquipmentAiming_PreFix(PawnRenderer __instance, Thing eq, public static bool TryDropEquipment_PreFix(ThingWithComps eq, out ThingWithComps resultingEq, ref bool __result) { resultingEq = null; - return __result = !!eq?.TryGetComp()?.uninstalled ?? true; + return __result = eq?.GetCompInstalledPart()?.uninstalled ?? true; } - // RimWorld.FloatMenuMakerMap - public static void AddHumanlikeOrders_PostFix(Vector3 clickPos, Pawn pawn, List opts) + // RimWorld.Pawn_ApparelTracker + public static bool InterfaceDrop_PreFix(ITab_Pawn_Gear __instance, Thing t) { - var c = IntVec3.FromVector3(clickPos); - - //Ground things with installed part components - var groundThing = - c.GetThingList(pawn.Map).FirstOrDefault(x => x.TryGetComp() != null) as - ThingWithComps; - if (groundThing != null && groundThing.GetComp() is CompInstalledPart groundPart) - if (pawn.equipment != null) + if (t is Apparel apparel) + { + var pawn = itabPawnGearSelPawnForGearGetter(__instance); + if (pawn?.apparel?.WornApparel.Contains(apparel) ?? false) { - //Remove "Equip" option from right click. - if (groundThing.GetComp() != null) - { - var optToRemove = opts.FirstOrDefault(x => x.Label.Contains(groundThing.Label)); - if (optToRemove != null) opts.Remove(optToRemove); - } - - var text = "CompInstalledPart_Install".Translate(); - opts.Add(new FloatMenuOption(text, delegate - { - var props = groundPart.Props; - if (props != null) - if (props.allowedToInstallOn != null && props.allowedToInstallOn.Count > 0) - { - SoundDefOf.Tick_Tiny.PlayOneShotOnCamera(null); - Find.Targeter.BeginTargeting(new TargetingParameters - { - canTargetPawns = true, - canTargetBuildings = true, - mapObjectTargetsMustBeAutoAttackable = false, - validator = delegate(TargetInfo targ) - { - if (!targ.HasThing) - return false; - return props.allowedToInstallOn.Contains(targ.Thing.def); - } - }, delegate(LocalTargetInfo target) - { - groundThing.SetForbidden(false); - groundPart.GiveInstallJob(pawn, target.Thing); - }, null, null, null); - } - else - { - Log.ErrorOnce( - "CompInstalledPart :: allowedToInstallOn list needs to be defined in XML.", 3242); - } - }, MenuOptionPriority.Default, null, null, 29f, null, null)); + var installedPart = apparel.GetCompInstalledPart(); + if (installedPart != null) + if (!installedPart.uninstalled) + return false; } - - //Install to a thing - var targetPawn = c.GetThingList(pawn.Map).FirstOrDefault(x => x is Pawn) as Pawn; - if (targetPawn != null) - { - if (targetPawn != null && pawn != null && pawn != targetPawn) - if (targetPawn.equipment != null) - if (targetPawn.equipment.Primary != null) - { - var installedEq = targetPawn.equipment.Primary.GetComp(); - if (installedEq != null) - { - var text = "CompInstalledPart_Uninstall".Translate(targetPawn.equipment.Primary - .LabelShort); - opts.Add(new FloatMenuOption(text, delegate - { - SoundDefOf.Tick_Tiny.PlayOneShotOnCamera(null); - installedEq.GiveUninstallJob(pawn, targetPawn); - }, MenuOptionPriority.Default, null, null, 29f, null, null)); - } - } - - - //Handle installed apparel - if (targetPawn.apparel != null) - if (targetPawn.apparel.WornApparel != null && targetPawn.apparel.WornApparelCount > 0) - { - var installedApparel = - targetPawn.apparel.WornApparel.FindAll(x => x.GetComp() != null); - if (installedApparel != null && installedApparel.Count > 0) - foreach (var ap in installedApparel) - { - var text = "CompInstalledPart_Uninstall".Translate(ap.LabelShort); - opts.Add(new FloatMenuOption(text, delegate - { - SoundDefOf.Tick_Tiny.PlayOneShotOnCamera(null); - ap.GetComp().GiveUninstallJob(pawn, targetPawn); - }, MenuOptionPriority.Default, null, null, 29f, null, null)); - } - } } - } - - // RimWorld.Pawn_ApparelTracker - public static bool InterfaceDrop_PreFix(ITab_Pawn_Gear __instance, Thing t) - { - var thingWithComps = t as ThingWithComps; - var apparel = t as Apparel; - var __pawn = (Pawn) AccessTools.Method(typeof(ITab_Pawn_Gear), "get_SelPawnForGear") - .Invoke(__instance, new object[0]); - if (__pawn != null) - if (apparel != null) - if (__pawn.apparel != null) - if (__pawn.apparel.WornApparel.Contains(apparel)) - if (__pawn.apparel.WornApparel != null) - { - var installedPart = apparel.GetComp(); - if (installedPart != null) - if (!installedPart.uninstalled) - return false; - } return true; } + + // Note: This is an open instance delegate where the first argument is the instance. + private static readonly Func itabPawnGearSelPawnForGearGetter = + (Func)AccessTools.PropertyGetter(typeof(ITab_Pawn_Gear), "SelPawnForGear") + .CreateDelegate(typeof(Func)); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompInstalledPart/InstalledPartFloatMenuPatch.cs b/Source/AllModdingComponents/CompInstalledPart/InstalledPartFloatMenuPatch.cs index cb818c29..59ebbb26 100644 --- a/Source/AllModdingComponents/CompInstalledPart/InstalledPartFloatMenuPatch.cs +++ b/Source/AllModdingComponents/CompInstalledPart/InstalledPartFloatMenuPatch.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using JecsTools; using RimWorld; using UnityEngine; @@ -14,63 +13,56 @@ public class InstalledPartFloatMenuPatch : FloatMenuPatch public override IEnumerable>>> GetFloatMenus() { - var FloatMenus = new List>>>(); - var curCondition = new _Condition(_ConditionType.IsType, typeof(ThingWithComps)); - Func> curFunc = - delegate(Vector3 clickPos, Pawn pawn, Thing curThing) - { - var opts = new List(); - if (curThing is ThingWithComps groundThing && - groundThing.GetComp() is CompInstalledPart groundPart) - if (pawn.equipment != null) + + static List curFunc(Vector3 clickPos, Pawn pawn, Thing curThing) + { + var opts = new List(); + if (curThing.TryGetCompInstalledPart() is CompInstalledPart groundPart) + if (pawn.equipment != null) + { + //Remove "Equip" option from right click. + if (groundPart.GetEquippable != null) { - //Remove "Equip" option from right click. - if (groundThing.GetComp() != null) - { - var optToRemove = opts.FirstOrDefault(x => x.Label.Contains(groundThing.Label)); - if (optToRemove != null) opts.Remove(optToRemove); - } + var optToRemoveIndex = opts.FindIndex(x => x.Label.Contains(curThing.Label)); + if (optToRemoveIndex >= 0) + opts.RemoveAt(optToRemoveIndex); + } - var text = "CompInstalledPart_Install".Translate(); - opts.Add(new FloatMenuOption(text, delegate - { - var props = groundPart.Props; - if (props != null) - if (props.allowedToInstallOn != null && props.allowedToInstallOn.Count > 0) + opts.Add(new FloatMenuOption("CompInstalledPart_Install".Translate(), () => + { + var props = groundPart.Props; + if (props != null) + if (!props.allowedToInstallOn.NullOrEmpty()) + { + SoundDefOf.Tick_Tiny.PlayOneShotOnCamera(null); + Find.Targeter.BeginTargeting(new TargetingParameters { - SoundDefOf.Tick_Tiny.PlayOneShotOnCamera(null); - Find.Targeter.BeginTargeting(new TargetingParameters + canTargetPawns = true, + canTargetBuildings = true, + mapObjectTargetsMustBeAutoAttackable = false, + validator = targ => { - canTargetPawns = true, - canTargetBuildings = true, - mapObjectTargetsMustBeAutoAttackable = false, - validator = delegate(TargetInfo targ) - { - if (!targ.HasThing) - return false; - return props.allowedToInstallOn.Contains(targ.Thing.def); - } - }, delegate(LocalTargetInfo target) - { - groundThing.SetForbidden(false); - groundPart.GiveInstallJob(pawn, target.Thing); - }, null, null, null); - } - else + return targ.HasThing && props.allowedToInstallOn.Contains(targ.Thing.def); + }, + }, target => { - Log.ErrorOnce( - "CompInstalledPart :: allowedToInstallOn list needs to be defined in XML.", - 3242); - } - }, MenuOptionPriority.Default, null, null, 29f, null, null)); - } - return opts; - }; - var curSec = - new KeyValuePair<_Condition, Func>>(curCondition, curFunc); - FloatMenus.Add(curSec); - return FloatMenus; + curThing.SetForbidden(false); + groundPart.GiveInstallJob(pawn, target.Thing); + }, null, null); + } + else + { + Log.ErrorOnce( + "CompInstalledPart :: allowedToInstallOn list needs to be defined in XML.", + 3242); + } + }, extraPartWidth: 29f)); + } + return opts; + }; + + yield return new KeyValuePair<_Condition, Func>>(curCondition, curFunc); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompInstalledPart/InstalledPartUtility.cs b/Source/AllModdingComponents/CompInstalledPart/InstalledPartUtility.cs new file mode 100644 index 00000000..9c17956f --- /dev/null +++ b/Source/AllModdingComponents/CompInstalledPart/InstalledPartUtility.cs @@ -0,0 +1,26 @@ +using Verse; + +namespace CompInstalledPart +{ + public static class InstalledPartUtility + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static CompInstalledPart GetCompInstalledPart(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompInstalledPart comp) + return comp; + } + return null; + } + + public static CompInstalledPart TryGetCompInstalledPart(this Thing thing) + { + return thing is ThingWithComps thingWithComps ? thingWithComps.GetCompInstalledPart() : null; + } + } +} diff --git a/Source/AllModdingComponents/CompInstalledPart/JobDriver_InstallPart.cs b/Source/AllModdingComponents/CompInstalledPart/JobDriver_InstallPart.cs index 302ebe9e..f92dd239 100644 --- a/Source/AllModdingComponents/CompInstalledPart/JobDriver_InstallPart.cs +++ b/Source/AllModdingComponents/CompInstalledPart/JobDriver_InstallPart.cs @@ -22,22 +22,15 @@ public class JobDriver_InstallPart : JobDriver protected float workLeft; - protected CompInstalledPart InstallComp => PartToInstall.GetComp(); + protected CompInstalledPart InstallComp => PartToInstall.GetCompInstalledPart(); - protected ThingWithComps PartToInstall => (ThingWithComps) job.targetA.Thing; + protected ThingWithComps PartToInstall => (ThingWithComps)job.targetA.Thing; protected Thing InstallTarget => job.targetB.Thing; - protected int WorkDone => TotalNeededWork - (int) workLeft; + protected int WorkDone => TotalNeededWork - (int)workLeft; - protected int TotalNeededWork - { - get - { - var value = InstallComp.Props.workToInstall; - return Mathf.Clamp(value, 20, 3000); - } - } + protected int TotalNeededWork => Mathf.Clamp(InstallComp.Props.workToInstall, 20, 3000); public override bool TryMakePreToilReservations(bool errorOnFailed) { @@ -51,19 +44,20 @@ protected override IEnumerable MakeNewToils() yield return Toils_Reserve.Reserve(TargetIndex.A); yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.OnCell) .FailOnDestroyedNullOrForbidden(TargetIndex.A); - yield return Toils_Haul.StartCarryThing(TargetIndex.A, false, false); + yield return Toils_Haul.StartCarryThing(TargetIndex.A); yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch); - yield return Toils_Haul.PlaceHauledThingInCell(TargetIndex.B, null, false); + yield return Toils_Haul.PlaceHauledThingInCell(TargetIndex.B, null, storageMode: false); var repair = new Toil { - initAction = delegate + initAction = () => { - ticksToNextRepair = 80f; + ticksToNextRepair = WarmupTicks; workLeft = TotalNeededWork; }, - tickAction = delegate + tickAction = () => { - if (InstallTarget is Pawn pawnTarget) pawnTarget.pather.StopDead(); + if (InstallTarget is Pawn pawnTarget) + pawnTarget.pather.StopDead(); pawn.rotationTracker.FaceCell(TargetB.Cell); var actor = pawn; actor.skills.Learn(SkillDefOf.Construction, 0.275f, false); @@ -71,7 +65,7 @@ protected override IEnumerable MakeNewToils() ticksToNextRepair -= statValue; if (ticksToNextRepair <= 0f) { - ticksToNextRepair += 20f; + ticksToNextRepair += TicksBetweenRepairs; workLeft -= 20 + actor.GetStatValue(StatDefOf.ConstructionSpeed, true); if (workLeft <= 0) { @@ -80,7 +74,7 @@ protected override IEnumerable MakeNewToils() actor.jobs.EndCurrentJob(JobCondition.Succeeded, true); } } - } + }, }; repair.FailOnCannotTouch(TargetIndex.B, PathEndMode.Touch); repair.WithEffect(InstallComp.Props.workEffect, TargetIndex.B); @@ -92,7 +86,7 @@ protected override IEnumerable MakeNewToils() public override void ExposeData() { base.ExposeData(); - Scribe_Values.Look(ref workLeft, "workLeft", -1); + Scribe_Values.Look(ref workLeft, nameof(workLeft), -1); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompInstalledPart/JobDriver_UninstallPart.cs b/Source/AllModdingComponents/CompInstalledPart/JobDriver_UninstallPart.cs index 675c1451..68a946fc 100644 --- a/Source/AllModdingComponents/CompInstalledPart/JobDriver_UninstallPart.cs +++ b/Source/AllModdingComponents/CompInstalledPart/JobDriver_UninstallPart.cs @@ -21,22 +21,15 @@ public class JobDriver_UninstallPart : JobDriver protected float workLeft; - protected CompInstalledPart UninstallComp => PartToUninstall.GetComp(); + protected CompInstalledPart UninstallComp => PartToUninstall.GetCompInstalledPart(); - protected ThingWithComps PartToUninstall => (ThingWithComps) job.targetA.Thing; + protected ThingWithComps PartToUninstall => (ThingWithComps)job.targetA.Thing; protected Thing UninstallTarget => job.targetB.Thing; - protected int WorkDone => TotalNeededWork - (int) workLeft; + protected int WorkDone => TotalNeededWork - (int)workLeft; - protected int TotalNeededWork - { - get - { - var value = UninstallComp.Props.workToInstall; - return Mathf.Clamp(value, 20, 3000); - } - } + protected int TotalNeededWork => Mathf.Clamp(UninstallComp.Props.workToInstall, 20, 3000); public override bool TryMakePreToilReservations(bool errorOnFailed) { @@ -51,14 +44,15 @@ protected override IEnumerable MakeNewToils() yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch); var repair = new Toil { - initAction = delegate + initAction = () => { - ticksToNextRepair = 80f; + ticksToNextRepair = WarmupTicks; workLeft = TotalNeededWork; }, - tickAction = delegate + tickAction = () => { - if (UninstallTarget is Pawn pawnTarget) pawnTarget.pather.StopDead(); + if (UninstallTarget is Pawn pawnTarget) + pawnTarget.pather.StopDead(); pawn.rotationTracker.FaceCell(TargetB.Cell); var actor = pawn; actor.skills.Learn(SkillDefOf.Construction, 0.275f, false); @@ -66,7 +60,7 @@ protected override IEnumerable MakeNewToils() ticksToNextRepair -= statValue; if (ticksToNextRepair <= 0f) { - ticksToNextRepair += 20f; + ticksToNextRepair += TicksBetweenRepairs; workLeft -= 20 + actor.GetStatValue(StatDefOf.ConstructionSpeed, true); if (workLeft <= 0) { @@ -75,7 +69,7 @@ protected override IEnumerable MakeNewToils() actor.jobs.EndCurrentJob(JobCondition.Succeeded, true); } } - } + }, }; repair.FailOnCannotTouch(TargetIndex.B, PathEndMode.Touch); repair.WithEffect(UninstallComp.Props.workEffect, TargetIndex.B); @@ -87,7 +81,7 @@ protected override IEnumerable MakeNewToils() public override void ExposeData() { base.ExposeData(); - Scribe_Values.Look(ref workLeft, "workLeft", -1); + Scribe_Values.Look(ref workLeft, nameof(workLeft), -1); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompLumbering/CompLumbering.cs b/Source/AllModdingComponents/CompLumbering/CompLumbering.cs index 03d1e7f8..b6748331 100644 --- a/Source/AllModdingComponents/CompLumbering/CompLumbering.cs +++ b/Source/AllModdingComponents/CompLumbering/CompLumbering.cs @@ -11,7 +11,7 @@ public class CompLumbering : ThingComp public Pawn Lumberer => parent as Pawn; - public CompProperties_Lumbering Props => (CompProperties_Lumbering) props; + public CompProperties_Lumbering Props => (CompProperties_Lumbering)props; public void ResolveCycledGraphic() { @@ -32,12 +32,11 @@ public void ResolveBaseGraphic() //Duplicated code from -> Verse.PawnGrapic -> ResolveAllGraphics var curKindLifeStage = Lumberer.ageTracker.CurKindLifeStage; - if (Lumberer.gender != Gender.Female || curKindLifeStage.femaleGraphicData == null) - pawnGraphicSet.nakedGraphic = curKindLifeStage.bodyGraphicData.Graphic; - else - pawnGraphicSet.nakedGraphic = curKindLifeStage.femaleGraphicData.Graphic; + pawnGraphicSet.nakedGraphic = Lumberer.gender != Gender.Female || curKindLifeStage.femaleGraphicData == null + ? curKindLifeStage.bodyGraphicData.Graphic + : curKindLifeStage.femaleGraphicData.Graphic; pawnGraphicSet.rottingGraphic = pawnGraphicSet.nakedGraphic.GetColoredVersion(ShaderDatabase.CutoutSkin, - PawnGraphicSet.RottingColor, PawnGraphicSet.RottingColor); + PawnGraphicSet.RottingColorDefault, PawnGraphicSet.RottingColorDefault); if (Lumberer.RaceProps.packAnimal) pawnGraphicSet.packGraphic = GraphicDatabase.Get( pawnGraphicSet.nakedGraphic.path + "Pack", ShaderDatabase.Cutout, @@ -57,24 +56,25 @@ public override void CompTick() Log.ErrorOnce("CompLumbering :: CompProperties_Lumbering secondsPerStep needs to be more than 0", 133); if (Lumberer != null && Props.secondsPerStep > 0.0f && Find.TickManager.TicksGame > ticksToCycle) - if (Lumberer?.pather?.MovingNow ?? false) + if (Lumberer.pather?.MovingNow ?? false) { cycled = !cycled; ticksToCycle = Find.TickManager.TicksGame + Props.secondsPerStep.SecondsToTicks(); - if (Props.sound != null) Props.sound.PlayOneShot(SoundInfo.InMap(Lumberer)); + Props.sound?.PlayOneShot(SoundInfo.InMap(Lumberer)); if (cycled) ResolveCycledGraphic(); else ResolveBaseGraphic(); - if (Props.staggerEffect) Lumberer.stances.StaggerFor(Props.secondsBetweenSteps.SecondsToTicks()); + if (Props.staggerEffect) + Lumberer.stances.StaggerFor(Props.secondsBetweenSteps.SecondsToTicks()); } } public override void PostExposeData() { base.PostExposeData(); - Scribe_Values.Look(ref cycled, "cycled", false); - Scribe_Values.Look(ref ticksToCycle, "ticksToCycle", -1); + Scribe_Values.Look(ref cycled, nameof(cycled)); + Scribe_Values.Look(ref ticksToCycle, nameof(ticksToCycle), -1); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompLumbering/CompLumbering.csproj b/Source/AllModdingComponents/CompLumbering/CompLumbering.csproj index a57ce800..16bec1a2 100755 --- a/Source/AllModdingComponents/CompLumbering/CompLumbering.csproj +++ b/Source/AllModdingComponents/CompLumbering/CompLumbering.csproj @@ -1,56 +1,7 @@  - - + + - Debug - AnyCPU - {CF56EA3A-AEC6-4817-BF46-A886FBEAA49B} - Library - Properties - CompLumbering CompLumbering - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompLumbering/CompProperties_Lumbering.cs b/Source/AllModdingComponents/CompLumbering/CompProperties_Lumbering.cs index aaa88001..5b732694 100644 --- a/Source/AllModdingComponents/CompLumbering/CompProperties_Lumbering.cs +++ b/Source/AllModdingComponents/CompLumbering/CompProperties_Lumbering.cs @@ -15,4 +15,4 @@ public CompProperties_Lumbering() compClass = typeof(CompLumbering); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompOverlays/CompOverlays.cs b/Source/AllModdingComponents/CompOverlays/CompOverlays.cs index cd982b87..735bba50 100644 --- a/Source/AllModdingComponents/CompOverlays/CompOverlays.cs +++ b/Source/AllModdingComponents/CompOverlays/CompOverlays.cs @@ -7,11 +7,47 @@ public class CompOverlays : ThingComp { public CompProperties_Overlays Props => props as CompProperties_Overlays; + private CompRefuelable compRefuelable; + + public CompRefuelable GetRefuelable => compRefuelable; + + // Caching comps needs to happen after all comps are created. Ideally, this would be done right after + // ThingWithComps.InitializeComps(). This requires overriding two hooks: PostPostMake and PostExposeData. + + public override void PostPostMake() + { + base.PostPostMake(); + CacheComps(); + } + + public override void PostExposeData() + { + base.PostExposeData(); + if (Scribe.mode == LoadSaveMode.LoadingVars) + CacheComps(); + } + + private void CacheComps() + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + var comps = parent.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompRefuelable compRefuelable) + { + this.compRefuelable = compRefuelable; + break; + } + } + } + public override void PostDraw() { base.PostDraw(); - if (Props.fuelRequired && parent.TryGetComp() is CompRefuelable rf && rf.HasFuel || - Props.fuelRequired == false) + if (Props.fuelRequired == false || + GetRefuelable is CompRefuelable rf && rf.HasFuel) { var drawPos = parent.DrawPos; drawPos.y += 0.046875f; @@ -21,7 +57,7 @@ public override void PostDraw() var vec3 = drawPos + o.offset; if (o.usesStuff) { - o.graphicData.GraphicColoredFor(this.parent).Draw(vec3, parent.Rotation, parent, 0f); + o.graphicData.GraphicColoredFor(parent).Draw(vec3, parent.Rotation, parent, 0f); continue; } o.graphicData.Graphic.Draw(vec3, parent.Rotation, parent, 0f); @@ -29,4 +65,4 @@ public override void PostDraw() } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompOverlays/CompOverlays.csproj b/Source/AllModdingComponents/CompOverlays/CompOverlays.csproj index 278d999b..421d789d 100644 --- a/Source/AllModdingComponents/CompOverlays/CompOverlays.csproj +++ b/Source/AllModdingComponents/CompOverlays/CompOverlays.csproj @@ -1,56 +1,7 @@  - - + + - Debug - AnyCPU - {947FF025-5DE9-4475-8779-4E9B02D06FB7} - Library - Properties - CompOverlays CompOverlays - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompOverlays/CompProperties_Overlays.cs b/Source/AllModdingComponents/CompOverlays/CompProperties_Overlays.cs index 0b987b52..12a27b88 100644 --- a/Source/AllModdingComponents/CompOverlays/CompProperties_Overlays.cs +++ b/Source/AllModdingComponents/CompOverlays/CompProperties_Overlays.cs @@ -7,10 +7,10 @@ namespace CompOverlays public class GraphicOverlay { public GraphicData graphicData; - + public bool usesStuff = false; public Vector3 offset = Vector3.zero; - + } public class CompProperties_Overlays : CompProperties @@ -23,4 +23,4 @@ public CompProperties_Overlays() compClass = typeof(CompOverlays); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeapon.cs b/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeapon.cs index 0db14444..dcdf547f 100644 --- a/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeapon.cs +++ b/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeapon.cs @@ -1,4 +1,6 @@ -using Verse; +using System; +using HarmonyLib; +using Verse; namespace CompOversizedWeapon { @@ -6,33 +8,53 @@ public class CompOversizedWeapon : ThingComp { public CompProperties_OversizedWeapon Props => props as CompProperties_OversizedWeapon; - public CompOversizedWeapon() + private Func compDeflectorIsAnimatingNow = AlwaysFalse; + + private static bool AlwaysFalse() => false; + + private static readonly Type compDeflectorType = GenTypes.GetTypeInAnyAssembly("CompDeflector.CompDeflector"); + + public bool CompDeflectorIsAnimatingNow => compDeflectorIsAnimatingNow(); + + public bool IsOnGround => ParentHolder is Map; + + // Caching comps needs to happen after all comps are created. Ideally, this would be done right after + // ThingWithComps.InitializeComps(). This requires overriding two hooks: PostPostMake and PostExposeData. + + public override void PostPostMake() { - if (!(props is CompProperties_OversizedWeapon)) - props = new CompProperties_OversizedWeapon(); + base.PostPostMake(); + CacheComps(); } - - - public CompEquippable GetEquippable => parent?.GetComp(); - - public Pawn GetPawn => GetEquippable?.verbTracker?.PrimaryVerb?.CasterPawn; - - private bool isEquipped = false; - public bool IsEquipped + + public override void PostExposeData() { - get - { - if (Find.TickManager.TicksGame % 60 != 0) return isEquipped; - isEquipped = GetPawn != null; - return isEquipped; - } + base.PostExposeData(); + if (Scribe.mode == LoadSaveMode.LoadingVars) + CacheComps(); } - private bool firstAttack = false; - public bool FirstAttack + private void CacheComps() { - get => firstAttack; - set => firstAttack = value; + if (compDeflectorType != null) + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + // For the optional CompDeflector, we have to use the slower IsAssignableFrom reflection check. + var comps = parent.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + var comp = comps[i]; + var compType = comp.GetType(); + if (compDeflectorType.IsAssignableFrom(compType)) + { + compDeflectorIsAnimatingNow = + (Func)AccessTools.PropertyGetter(compType, "IsAnimatingNow").CreateDelegate(typeof(Func), comp); + break; + } + } + } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeapon.csproj b/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeapon.csproj index bfb99648..68faba85 100755 --- a/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeapon.csproj +++ b/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeapon.csproj @@ -1,57 +1,7 @@  - - + + - Debug - AnyCPU - {08E20D0E-4493-4DFE-9212-DEC323F26E89} - Library - Properties - CompOversizedWeapon CompOversizedWeapon - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeaponUtility.cs b/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeaponUtility.cs new file mode 100644 index 00000000..3b7ddbba --- /dev/null +++ b/Source/AllModdingComponents/CompOversizedWeapon/CompOversizedWeaponUtility.cs @@ -0,0 +1,26 @@ +using Verse; + +namespace CompOversizedWeapon +{ + public static class CompOversizedWeaponUtility + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static CompOversizedWeapon GetCompOversizedWeapon(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompOversizedWeapon comp) + return comp; + } + return null; + } + + public static CompOversizedWeapon TryGetCompOversizedWeapon(this Thing thing) + { + return thing is ThingWithComps thingWithComps ? thingWithComps.GetCompOversizedWeapon() : null; + } + } +} diff --git a/Source/AllModdingComponents/CompOversizedWeapon/CompProperties_OversizedWeapon.cs b/Source/AllModdingComponents/CompOversizedWeapon/CompProperties_OversizedWeapon.cs index 02753bb8..52098358 100644 --- a/Source/AllModdingComponents/CompOversizedWeapon/CompProperties_OversizedWeapon.cs +++ b/Source/AllModdingComponents/CompOversizedWeapon/CompProperties_OversizedWeapon.cs @@ -11,11 +11,10 @@ public class CompProperties_OversizedWeapon : CompProperties //public SoundDef soundExtra; //public SoundDef soundExtraTwo; - public Vector3 offset = new Vector3(0,0,0); //No longer in-use. - public Vector3 northOffset = new Vector3(0,0,0); - public Vector3 eastOffset = new Vector3(0,0,0); - public Vector3 southOffset = new Vector3(0,0,0); - public Vector3 westOffset = new Vector3(0,0,0); + public Vector3 northOffset = new Vector3(0, 0, 0); + public Vector3 eastOffset = new Vector3(0, 0, 0); + public Vector3 southOffset = new Vector3(0, 0, 0); + public Vector3 westOffset = new Vector3(0, 0, 0); public bool verticalFlipOutsideCombat = false; public bool verticalFlipNorth = false; public bool isDualWeapon = false; @@ -30,5 +29,29 @@ public CompProperties_OversizedWeapon() { compClass = typeof(CompOversizedWeapon); } + + public float NonCombatAngleAdjustment(Rot4 rotation) + { + if (rotation == Rot4.North) + return angleAdjustmentNorth; + else if (rotation == Rot4.East) + return angleAdjustmentEast; + else if (rotation == Rot4.West) + return angleAdjustmentWest; + else + return angleAdjustmentSouth; + } + + public Vector3 OffsetFromRotation(Rot4 rotation) + { + if (rotation == Rot4.North) + return northOffset; + else if (rotation == Rot4.East) + return eastOffset; + else if (rotation == Rot4.West) + return westOffset; + else + return southOffset; + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompOversizedWeapon/HarmonyCompOversizedWeapon.cs b/Source/AllModdingComponents/CompOversizedWeapon/HarmonyCompOversizedWeapon.cs index ff79c0b7..a0b91d84 100644 --- a/Source/AllModdingComponents/CompOversizedWeapon/HarmonyCompOversizedWeapon.cs +++ b/Source/AllModdingComponents/CompOversizedWeapon/HarmonyCompOversizedWeapon.cs @@ -1,7 +1,4 @@ -using System; -using System.Linq; -using System.Security.Cryptography; -using HarmonyLib; +using HarmonyLib; using RimWorld; using UnityEngine; using Verse; @@ -9,233 +6,131 @@ namespace CompOversizedWeapon { [StaticConstructorOnStartup] + internal static class HarmonyCompOversizedWeapon { static HarmonyCompOversizedWeapon() { var harmony = new Harmony("jecstools.jecrell.comps.oversized"); - harmony.Patch(typeof(PawnRenderer).GetMethod("DrawEquipmentAiming"), - new HarmonyMethod(typeof(HarmonyCompOversizedWeapon).GetMethod("DrawEquipmentAimingPreFix")), null); - harmony.Patch(AccessTools.Method(typeof(Thing), "get_DefaultGraphic"), null, - new HarmonyMethod(typeof(HarmonyCompOversizedWeapon), nameof(get_Graphic_PostFix))); - } + var type = typeof(HarmonyCompOversizedWeapon); + //var CarnySenpaiEnableOversizedWeaponsModLoaded = ModsConfig.IsActive("CarnySenpai.EnableOversizedWeapons"); + // if (CarnySenpaiEnableOversizedWeaponsModLoaded) + // { + // Log.Message("JecsTools:: Using Carny Senpai's Enable Oversized Weapons instead of CompOversizedWeapon"); + // return; + //} + //Log.Warning("JecsTools CompOversizedWeapon Loaded:: This component is no longer recommended for performance. Please see Carny Senpai's Enable Oversized Weapons mod. Once the Carny Senpai's mod is loaded, it will be used instead of CompOversizedWeapon"); + + harmony.Patch(AccessTools.Method(typeof(PawnRenderer), nameof(PawnRenderer.DrawEquipmentAiming)), + prefix: new HarmonyMethod(type, nameof(DrawEquipmentAimingPreFix))); + harmony.Patch(AccessTools.PropertyGetter(typeof(Thing), nameof(Thing.DefaultGraphic)), + postfix: new HarmonyMethod(type, nameof(get_DefaultGraphic_PostFix))); + } /// /// Adds another "layer" to the equipment aiming if they have a /// weapon with a CompActivatableEffect. /// - /// - /// - /// - /// - public static bool DrawEquipmentAimingPreFix(PawnRenderer __instance, Thing eq, Vector3 drawLoc, float aimAngle) + public static bool DrawEquipmentAimingPreFix(Pawn ___pawn, Thing eq, Vector3 drawLoc, float aimAngle) { - if (eq is ThingWithComps thingWithComps) - { - //If the deflector is active, it's already using this code. - var deflector = thingWithComps.AllComps.FirstOrDefault(y => - y.GetType().ToString() == "CompDeflector.CompDeflector" || - y.GetType().BaseType.ToString() == "CompDeflector.CompDeflector"); - if (deflector != null) - { - var isAnimatingNow = Traverse.Create(deflector).Property("IsAnimatingNow").GetValue(); - if (isAnimatingNow) - return false; - } - - var compOversizedWeapon = thingWithComps.TryGetComp(); - if (compOversizedWeapon != null) - { - var flip = false; - var num = aimAngle - 90f; - var pawn = Traverse.Create(__instance).Field("pawn").GetValue(); - if (pawn == null) return true; - - Mesh mesh; - if (aimAngle > 20f && aimAngle < 160f) - { - mesh = MeshPool.plane10; - num += eq.def.equippedAngleOffset; - } - else if (aimAngle > 200f && aimAngle < 340f) - { - mesh = MeshPool.plane10Flip; - flip = true; - num -= 180f; - num -= eq.def.equippedAngleOffset; - } - else - { - num = AdjustOffsetAtPeace(eq, pawn, compOversizedWeapon, num); - } - - if (compOversizedWeapon.Props != null && (!pawn.IsFighting() && (compOversizedWeapon.Props.verticalFlipNorth && pawn.Rotation == Rot4.North))) - { - num += 180f; - } - if (!pawn.IsFighting()) - { - num = AdjustNonCombatRotation(pawn, num, compOversizedWeapon); - } - num %= 360f; - - - - var graphic_StackCount = eq.Graphic as Graphic_StackCount; - Material matSingle; - if (graphic_StackCount != null) - matSingle = graphic_StackCount.SubGraphicForStackCount(1, eq.def).MatSingle; - else - matSingle = eq.Graphic.MatSingle; + var compOversizedWeapon = eq.TryGetCompOversizedWeapon(); + if (compOversizedWeapon == null) + return true; + //If the deflector is animating now, deflector handles drawing (and already has the drawSize fix). + if (compOversizedWeapon.CompDeflectorIsAnimatingNow) + return false; - - var s = new Vector3(eq.def.graphicData.drawSize.x, 1f, eq.def.graphicData.drawSize.y); - var matrix = default(Matrix4x4); + var aimingSouth = false; - - Vector3 curOffset = AdjustRenderOffsetFromDir(pawn, compOversizedWeapon); - matrix.SetTRS(drawLoc + curOffset, Quaternion.AngleAxis(num, Vector3.up), s); - - Graphics.DrawMesh(!flip ? MeshPool.plane10 : MeshPool.plane10Flip, matrix, matSingle, 0); - if (compOversizedWeapon.Props != null && compOversizedWeapon.Props.isDualWeapon) - { - curOffset = new Vector3(-1f * curOffset.x, curOffset.y, curOffset.z); - Mesh curPool; - if (pawn.Rotation == Rot4.North || pawn.Rotation == Rot4.South) - { - num += 135f; - num %= 360f; - curPool = !flip ? MeshPool.plane10Flip : MeshPool.plane10; - } - else - { - curOffset = new Vector3(curOffset.x, curOffset.y - 0.1f, curOffset.z + 0.15f); - curPool = !flip ? MeshPool.plane10 : MeshPool.plane10Flip; - } - matrix.SetTRS(drawLoc + curOffset, Quaternion.AngleAxis(num, Vector3.up), s); - Graphics.DrawMesh(curPool, matrix, matSingle, 0); - } - return false; - } + // start copied vanilla code (with mesh = flip ? MeshPool.plane10Flip : MeshPool.plane10) + var flip = false; + var angle = aimAngle - 90f; + if (aimAngle > 20f && aimAngle < 160f) + { + angle += eq.def.equippedAngleOffset; } - //} - return true; - } + else if (aimAngle > 200f && aimAngle < 340f) + { + flip = true; + angle -= 180f; + angle -= eq.def.equippedAngleOffset; + } + else + { + angle += eq.def.equippedAngleOffset; + aimingSouth = true; // custom + } + // end copied vanilla code - private static float AdjustOffsetAtPeace(Thing eq, Pawn pawn, CompOversizedWeapon compOversizedWeapon, float num) - { - Mesh mesh; - mesh = MeshPool.plane10; - var offsetAtPeace = eq.def.equippedAngleOffset; - if (compOversizedWeapon.Props != null && (!pawn.IsFighting() && compOversizedWeapon.Props.verticalFlipOutsideCombat)) + var props = compOversizedWeapon.Props; + var rotation = ___pawn.Rotation; + + if (props != null && !___pawn.IsFighting()) // at peace { - offsetAtPeace += 180f; + if (aimingSouth && props.verticalFlipOutsideCombat) + angle += 180f; + if (props.verticalFlipNorth && rotation == Rot4.North) + angle += 180f; + angle += props.NonCombatAngleAdjustment(rotation); } - num += offsetAtPeace; - return num; - } - private static float AdjustNonCombatRotation(Pawn pawn, float num, CompOversizedWeapon compOversizedWeapon) - { - if (compOversizedWeapon.Props != null) + angle %= 360f; // copied vanilla code + + var matSingle = eq.Graphic is Graphic_StackCount graphic_StackCount + ? graphic_StackCount.SubGraphicForStackCount(1, eq.def).MatSingle + : eq.Graphic.MatSingle; + var s = new Vector3(eq.def.graphicData.drawSize.x, 1f, eq.def.graphicData.drawSize.y); + var curOffset = props != null ? props.OffsetFromRotation(rotation) : Vector3.zero; + var matrix = Matrix4x4.TRS(drawLoc + curOffset, Quaternion.AngleAxis(angle, Vector3.up), s); + Graphics.DrawMesh(flip ? MeshPool.plane10Flip : MeshPool.plane10, matrix, matSingle, 0); + + if (props != null && props.isDualWeapon) { - if (pawn.Rotation == Rot4.North) - { - num += compOversizedWeapon.Props.angleAdjustmentNorth; - } - else if (pawn.Rotation == Rot4.East) - { - num += compOversizedWeapon.Props.angleAdjustmentEast; - } - else if (pawn.Rotation == Rot4.West) + curOffset = new Vector3(-1f * curOffset.x, curOffset.y, curOffset.z); + if (rotation == Rot4.North || rotation == Rot4.South) { - num += compOversizedWeapon.Props.angleAdjustmentWest; + angle += 135f; + angle %= 360f; } - else if (pawn.Rotation == Rot4.South) + else { - num += compOversizedWeapon.Props.angleAdjustmentSouth; + curOffset = new Vector3(curOffset.x, curOffset.y - 0.1f, curOffset.z + 0.15f); + flip = !flip; } + matrix.SetTRS(drawLoc + curOffset, Quaternion.AngleAxis(angle, Vector3.up), s); + Graphics.DrawMesh(flip ? MeshPool.plane10 : MeshPool.plane10Flip, matrix, matSingle, 0); } - return num; + return false; } - private static Vector3 AdjustRenderOffsetFromDir(Pawn pawn, CompOversizedWeapon compOversizedWeapon) + public static void get_DefaultGraphic_PostFix(Thing __instance, Graphic ___graphicInt, ref Graphic __result) { - var curDir = pawn.Rotation; - - Vector3 curOffset = Vector3.zero; - - if (compOversizedWeapon.Props != null) + if (___graphicInt == null) + return; + if (__instance.ParentHolder is Pawn) + return; + + var compOversizedWeapon = __instance.TryGetCompOversizedWeapon(); + if (compOversizedWeapon != null) { - - curOffset = compOversizedWeapon.Props.northOffset; - if (curDir == Rot4.East) + var groundGraphic = compOversizedWeapon.Props?.groundGraphic; + if (groundGraphic != null && compOversizedWeapon.IsOnGround && + groundGraphic.GraphicColoredFor(__instance) is Graphic newResult) { - curOffset = compOversizedWeapon.Props.eastOffset; + // See comment below on drawSize. + newResult.drawSize = groundGraphic.drawSize; + __result = newResult; } - else if (curDir == Rot4.South) + else { - curOffset = compOversizedWeapon.Props.southOffset; - } - else if (curDir == Rot4.West) - { - curOffset = compOversizedWeapon.Props.westOffset; + // Note: This is originally a workaround for a bug where the new Graphic returned by + // Graphic_RandomRotated.GetColoredVersion does not inherit the original drawSize, + // instead always using a drawSize of (1,1). This bug has been fixed in RW 1.2.2723+, + // but since older supported RW versions are still afflicted, for now, always apply the workaround. + __result.drawSize = __instance.def.graphicData.drawSize; } } - - return curOffset; - } - - public static void get_Graphic_PostFix(Thing __instance, ref Graphic __result) - { - var tempGraphic = Traverse.Create(__instance).Field("graphicInt").GetValue(); - if (tempGraphic != null) - if (__instance is ThingWithComps thingWithComps) - { - if (thingWithComps.ParentHolder is Pawn) - return; - var activatableEffect = - thingWithComps.AllComps.FirstOrDefault( - y => y.GetType().ToString().Contains("ActivatableEffect")); - if (activatableEffect != null) - { - var getPawn = Traverse.Create(activatableEffect).Property("GetPawn").GetValue(); - if (getPawn != null) - return; - } - var compOversizedWeapon = thingWithComps.TryGetComp(); - if (compOversizedWeapon != null) - { - if (compOversizedWeapon.Props?.groundGraphic == null) - { - tempGraphic.drawSize = __instance.def.graphicData.drawSize; - __result = tempGraphic; - } - else - { - if (compOversizedWeapon.IsEquipped) - { - tempGraphic.drawSize = __instance.def.graphicData.drawSize; - __result = tempGraphic; - } - else - { - if (compOversizedWeapon.Props?.groundGraphic?.GraphicColoredFor(__instance) is Graphic - newResult) - { - newResult.drawSize = compOversizedWeapon.Props.groundGraphic.drawSize; - __result = newResult; - } - else - { - tempGraphic.drawSize = __instance.def.graphicData.drawSize; - __result = tempGraphic; - } - } - } - } - } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/CompProperties_SlotLoadable.cs b/Source/AllModdingComponents/CompSlotLoadable/CompProperties_SlotLoadable.cs index 2e41c390..084064a3 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/CompProperties_SlotLoadable.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/CompProperties_SlotLoadable.cs @@ -14,4 +14,4 @@ public CompProperties_SlotLoadable() compClass = typeof(CompSlotLoadable); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/CompProperties_SlottedBonus.cs b/Source/AllModdingComponents/CompSlotLoadable/CompProperties_SlottedBonus.cs index fa158e79..e4df944e 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/CompProperties_SlottedBonus.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/CompProperties_SlottedBonus.cs @@ -7,9 +7,9 @@ namespace CompSlotLoadable { public class CompProperties_SlottedBonus : CompProperties { - public List additionalProjectiles = new List(); + public List additionalProjectiles = null; // TODO: unused? - public Color color = Color.white; + public Color color = Color.white; // TODO: unused? public DamageDef damageDef = null; @@ -17,20 +17,51 @@ public class CompProperties_SlottedBonus : CompProperties public SlotBonusProps_DefensiveHealChance defensiveHealChance = null; - public float muzzleFlashMod = 0.0f; + public float muzzleFlashMod = 0.0f; // TODO: unused? - public ThingDef projectileReplacer = null; + public ThingDef projectileReplacer = null; // TODO: unused? + + public SoundDef soundCastReplacer = null; // TODO: unused? - public SoundDef soundCastReplacer = null; public List statModifiers = null; public SlotBonusProps_VampiricEffect vampiricHealChance = null; - public float weaponRangeMod = 0.0f; + public float weaponRangeMod = 0.0f; // TODO: unused? public CompProperties_SlottedBonus() { compClass = typeof(CompSlottedBonus); } + + public override void ResolveReferences(ThingDef parentDef) + { + base.ResolveReferences(parentDef); + if (defensiveHealChance != null) + { + if (defensiveHealChance.woundLimit <= 0) + defensiveHealChance.woundLimit = int.MaxValue; + } + if (vampiricHealChance != null) + { + if (vampiricHealChance.woundLimit <= 0) + vampiricHealChance.woundLimit = 2; + vampiricHealChance.damageDef ??= DamageDefOf.Burn; + } + } + + public override IEnumerable ConfigErrors(ThingDef parentDef) + { + foreach (var error in base.ConfigErrors(parentDef)) + yield return error; + if (statModifiers != null) + { + for (var i = 0; i < statModifiers.Count; i++) + { + if (statModifiers[i]?.stat == null) + yield return $"{nameof(statModifiers)}[{i}] is null or has null stat"; + } + } + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadable.cs b/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadable.cs index d2505a38..ea3c34ef 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadable.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadable.cs @@ -1,15 +1,15 @@ using System.Collections.Generic; -using System.Linq; using System.Text; using RimWorld; using UnityEngine; using Verse; -using Verse.AI; namespace CompSlotLoadable { public class CompSlotLoadable : ThingComp { + public CompProperties_SlotLoadable Props => (CompProperties_SlotLoadable)props; + private SlotLoadable colorChangingSlot; public bool GizmosOnEquip = true; @@ -17,94 +17,95 @@ public class CompSlotLoadable : ThingComp private bool isInitialized; + private CompEquippable compEquippable; private SlotLoadable secondColorChangingSlot; private List slots = new List(); public List Slots => slots; - public SlotLoadable ColorChangingSlot + public SlotLoadable ColorChangingSlot => + colorChangingSlot ??= slots.Find(slot => slot.Def?.doesChangeColor ?? false); + + public SlotLoadable SecondColorChangingSlot => + secondColorChangingSlot ??= slots.Find(slot => slot.Def?.doesChangeSecondColor ?? false); + + public List SlotDefs => slots.ConvertAll(slot => slot.Def); + + public Map GetMap => parent.Map ?? GetPawn?.Map; + + public CompEquippable GetEquippable => compEquippable; + + public Pawn GetPawn => compEquippable.PrimaryVerb.CasterPawn; + + // Caching comps needs to happen after all comps are created. Ideally, this would be done right after + // ThingWithComps.InitializeComps(). This requires overriding two hooks: PostPostMake and PostExposeData. + + public override void PostPostMake() { - get - { - if (colorChangingSlot != null) return colorChangingSlot; - if (Slots != null) - if (Slots.Count > 0) - colorChangingSlot = Slots.FirstOrDefault(x => ((SlotLoadableDef) x.def).doesChangeColor); - return colorChangingSlot; - } + base.PostPostMake(); + CacheComps(); } - public SlotLoadable SecondColorChangingSlot + public override void PostExposeData() { - get + base.PostExposeData(); + Scribe_Values.Look(ref isInitialized, nameof(isInitialized)); + Scribe_Values.Look(ref isGathering, nameof(isGathering)); + Scribe_Collections.Look(ref slots, nameof(slots), LookMode.Deep); + slots ??= new List(); + if (Scribe.mode == LoadSaveMode.LoadingVars) { - if (secondColorChangingSlot != null) return secondColorChangingSlot; - if (Slots != null) - if (Slots.Count > 0) - secondColorChangingSlot = - Slots.FirstOrDefault(x => ((SlotLoadableDef) x.def).doesChangeSecondColor); - return colorChangingSlot; + //Scribe.writingForDebug = false; + CacheComps(); } - } - - public List SlotDefs - { - get + if (Scribe.mode == LoadSaveMode.PostLoadInit) { - var result = new List(); - if (slots != null) - if (slots.Count > 0) - foreach (var slot in slots) - result.Add(slot.def as SlotLoadableDef); - return result; + //Scribe.writingForDebug = true; } } - public Map GetMap + private void CacheComps() { - get + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + var comps = parent.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) { - var map = parent.Map; - if (map == null) - if (GetPawn != null) map = GetPawn.Map; - return map; + if (comps[i] is CompEquippable compEquippable) + { + this.compEquippable = compEquippable; + break; + } } } - public CompEquippable GetEquippable => parent.GetComp(); - - public Pawn GetPawn => GetEquippable.verbTracker.PrimaryVerb.CasterPawn; - - - public CompProperties_SlotLoadable Props => (CompProperties_SlotLoadable) props; - + // This is called on the first tick - not rolled into above Initialize since it's still needed in case subclasses implement it. public void Initialize() { - //Log.Message("1"); if (!isInitialized) { - //Log.Message("2"); isInitialized = true; - if (Props != null) - if (Props.slots != null) - if (Props.slots.Count > 0) - foreach (var slot in Props.slots) - { - var newSlot = new SlotLoadable(slot, parent); - //Log.Message("Added Slot"); - slots.Add(newSlot); - } + var slots = Props?.slots; + if (slots != null) + foreach (var slot in slots) + { + var newSlot = new SlotLoadable(slot, parent); + //Log.Message("Added Slot"); + this.slots.Add(newSlot); + } } } public override void CompTick() { base.CompTick(); - if (!isInitialized) Initialize(); + if (!isInitialized) + Initialize(); } - private void TryCancel(string reason = "") + private void TryCancel() { var pawn = GetPawn; if (pawn != null) @@ -112,31 +113,26 @@ private void TryCancel(string reason = "") if (pawn.CurJob.def == CompSlotLoadableDefOf.GatherSlotItem) pawn.jobs.StopAll(); isGathering = false; - //Messages.Message("Cancelling sacrifice. " + reason, MessageSound.Negative); } } private void TryGiveLoadSlotJob(Thing itemToLoad) { - if (GetPawn != null) - if (!GetPawn.Drafted) + var pawn = GetPawn; + if (pawn != null) + if (!pawn.Drafted) { isGathering = true; - var job = new Job(CompSlotLoadableDefOf.GatherSlotItem, itemToLoad) - { - count = 1 - }; - GetPawn.jobs.TryTakeOrderedJob(job); - //GetPawn.jobs.jobQueue.EnqueueFirst(job); - //GetPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); + var job = JobMaker.MakeJob(CompSlotLoadableDefOf.GatherSlotItem, itemToLoad); + job.count = 1; + pawn.jobs.TryTakeOrderedJob(job); + //pawn.jobs.jobQueue.EnqueueFirst(job); + //pawn.jobs.EndCurrentJob(JobCondition.InterruptForced); } else { - Messages.Message(string.Format(StringOf.IsDrafted, new object[] - { - GetPawn.Label - }), MessageTypeDefOf.RejectInput); + Messages.Message(string.Format(StringOf.IsDrafted, pawn.Label), MessageTypeDefOf.RejectInput); } } @@ -144,74 +140,51 @@ public bool TryLoadSlot(Thing thing) { //Log.Message("TryLoadSlot Called"); isGathering = false; - if (slots != null) - if (slots.Count > 0) - { - var loadSlot = slots.FirstOrDefault(x => x.IsEmpty() && x.CanLoad(thing.def)); - if (loadSlot == null) loadSlot = slots.FirstOrDefault(y => y.CanLoad(thing.def)); - if (loadSlot != null) - if (loadSlot.TryLoadSlot(thing, true)) - return true; - } - return false; + var loadSlot = slots.Find(slot => slot.IsEmpty() && slot.CanLoad(thing.def)) ?? + slots.Find(slot => slot.CanLoad(thing.def)); + return loadSlot?.TryLoadSlot(thing, true) ?? false; } public void ProcessInput(SlotLoadable slot) { - var loadTypes = new List(); var floatList = new List(); + var slotOccupant = slot.SlotOccupant; if (!isGathering) { var map = GetMap; - loadTypes = slot.SlottableTypes; - if (slot.SlotOccupant == null) - if (loadTypes != null) - if (loadTypes.Count != 0) - foreach (var current in loadTypes) + if (slotOccupant == null) + { + var loadTypes = slot.SlottableTypes; + if (loadTypes.Count > 0) + { + var pawn = GetPawn; + foreach (var current in loadTypes) + { + var thingToLoad = map.listerThings.ThingsOfDef(current) + .Find(x => map.reservationManager.CanReserve(pawn, x)); + if (thingToLoad != null) { - var thingsWithDef = - new List(map.listerThings.AllThings.FindAll(x => x.def == current)); - if (thingsWithDef != null) - if (thingsWithDef.Count > 0) - { - var thingToLoad = thingsWithDef.FirstOrDefault(x => - map.reservationManager.CanReserve(GetPawn, x)); - if (thingToLoad != null) - { - var text = "Load".Translate() + " " + thingToLoad.def.label; - //Func extraPartOnGUI = (Rect rect) => Widgets.InfoCardButton(rect.x + 5f, rect.y + (rect.height - 24f) / 2f, current); - floatList.Add(new FloatMenuOption(text, - delegate { TryGiveLoadSlotJob(thingToLoad); }, - MenuOptionPriority.Default, null, null, 29f, null, null)); - } - else - { - floatList.Add(new FloatMenuOption( - string.Format(StringOf.Unavailable, new object[] {current.label}), - delegate { }, MenuOptionPriority.Default)); - } - } - else - { - floatList.Add(new FloatMenuOption( - string.Format(StringOf.Unavailable, new object[] {current.label}), - delegate { }, MenuOptionPriority.Default)); - } - else - floatList.Add(new FloatMenuOption( - string.Format(StringOf.Unavailable, new object[] {current.label}), delegate { }, - MenuOptionPriority.Default)); + //bool extraPartOnGUI(Rect rect) => Widgets.InfoCardButton(rect.x + 5f, rect.y + (rect.height - 24f) / 2f, current); + floatList.Add(new FloatMenuOption("Load".Translate() + " " + thingToLoad.def.label, + () => TryGiveLoadSlotJob(thingToLoad), extraPartWidth: 29f)); } - else - floatList.Add(new FloatMenuOption(StringOf.NoLoadOptions, delegate { }, - MenuOptionPriority.Default)); + // Commenting following out since all the unavailable options can clutter the menu. + //else + //{ + // floatList.Add(new FloatMenuOption(string.Format(StringOf.Unavailable, current.label), + // () => { })); + //} + } + } + if (floatList.Count == 0) + floatList.Add(new FloatMenuOption(StringOf.NoLoadOptions, () => { })); + } } - if (!slot.IsEmpty()) + if (slotOccupant != null) { - var text = string.Format(StringOf.Unload, new object[] {slot.SlotOccupant.Label}); - //Func extraPartOnGUI = (Rect rect) => Widgets.InfoCardButton(rect.x + 5f, rect.y + (rect.height - 24f) / 2f, current); - floatList.Add(new FloatMenuOption(text, delegate { TryEmptySlot(slot); }, MenuOptionPriority.Default, - null, null, 29f, null, null)); + //bool extraPartOnGUI(Rect rect) => Widgets.InfoCardButton(rect.x + 5f, rect.y + (rect.height - 24f) / 2f, current); + floatList.Add(new FloatMenuOption(string.Format(StringOf.Unload, slotOccupant.Label), + () => TryEmptySlot(slot), extraPartWidth: 29f)); } Find.WindowStack.Add(new FloatMenu(floatList)); } @@ -223,139 +196,85 @@ public virtual void TryEmptySlot(SlotLoadable slot) public virtual IEnumerable EquippedGizmos() { - if (slots != null) - if (slots.Count > 0) - { - if (isGathering) + if (slots.Count > 0) + { + if (isGathering) + yield return new Command_Action + { + defaultLabel = "Designator_Cancel".Translate(), + defaultDesc = "Designator_CancelDesc".Translate(), + icon = ContentFinder.Get("UI/Designators/Cancel"), + action = TryCancel, + }; + foreach (var slot in slots) + if (slot.IsEmpty()) yield return new Command_Action { - defaultLabel = "Designator_Cancel".Translate(), - defaultDesc = "Designator_CancelDesc".Translate(), - icon = ContentFinder.Get("UI/Designators/Cancel", true), - action = delegate { TryCancel(); } + defaultLabel = slot.Label, + icon = Command.BGTex, + defaultDesc = SlotDesc(slot), + action = () => ProcessInput(slot), }; - foreach (var slot in slots) - if (slot.IsEmpty()) - yield return new Command_Action - { - defaultLabel = slot.Label, - icon = Command.BGTex, - defaultDesc = SlotDesc(slot), - action = delegate { ProcessInput(slot); } - }; - else - yield return new Command_Action - { - defaultLabel = slot.Label, - icon = slot.SlotIcon(), - defaultDesc = SlotDesc(slot), - defaultIconColor = slot.SlotColor(), - action = delegate { ProcessInput(slot); } - }; - } + else + yield return new Command_Action + { + defaultLabel = slot.Label, + icon = slot.SlotIcon(), + defaultDesc = SlotDesc(slot), + defaultIconColor = slot.SlotColor(), + action = () => ProcessInput(slot), + }; + } } + public override IEnumerable CompGetGizmosExtra() + { + if (!GizmosOnEquip) + { + foreach (var current in base.CompGetGizmosExtra()) + yield return current; + + foreach (var current in EquippedGizmos()) + yield return current; + } + } + + // TODO: Define SpecialDisplayStats to show stat entries in stats window? including hyperlinks to the slottables? public virtual string SlotDesc(SlotLoadable slot) { var s = new StringBuilder(); - s.AppendLine(slot.def.description); //TODO - if (!slot.IsEmpty()) + s.AppendLine(slot.DescriptionFlavor); + var slotOccupant = slot.SlotOccupant; + if (slotOccupant != null) { s.AppendLine(); - s.AppendLine(string.Format(StringOf.CurrentlyLoaded, new object[] {slot.SlotOccupant.LabelCap})); - if (((SlotLoadableDef) slot.def).doesChangeColor) + s.AppendLine(string.Format(StringOf.CurrentlyLoaded, slotOccupant.LabelCap)); + if (slot.Def?.doesChangeColor ?? false) { s.AppendLine(); s.AppendLine(StringOf.Effects); s.AppendLine(" " + StringOf.ChangesPrimaryColor); } - if (((SlotLoadableDef) slot.def).doesChangeStats) + if (slot.Def?.doesChangeStats ?? false) { - var slotBonus = slot.SlotOccupant.TryGetComp(); + var slotBonus = slotOccupant.TryGetCompSlottedBonus(); if (slotBonus != null) - if (slotBonus.Props != null) + { + var first = true; + foreach (var statEntry in slotBonus.SpecialDisplayStats()) { - if (slotBonus.Props.statModifiers != null && slotBonus.Props.statModifiers.Count > 0) + if (first) { s.AppendLine(); s.AppendLine(StringOf.StatModifiers); - - foreach (var mod in slotBonus.Props.statModifiers) - { - var v = SlotLoadableUtility.DetermineSlottableStatAugment(slot.SlotOccupant, mod.stat); - var modstring = mod.stat.ValueToString(v, ToStringNumberSense.Offset); - //Log.Message("Determined slot stat augment "+v+" and made string "+modstring); - s.AppendLine(" " + mod.stat.LabelCap + " " + modstring); - //s.AppendLine("\t" + mod.stat.LabelCap + " " + mod.ToStringAsOffset); - } - /* - //Log.Message("fix this to display statModifiers"); - List statMods = slot.SlotOccupant.def.statBases.FindAll( - (StatModifier z) => z.stat.category == StatCategoryDefOf.Weapon || - z.stat.category == StatCategoryDefOf.EquippedStatOffsets); - if (statMods != null && statMods.Count > 0) - { - s.AppendLine(); - s.AppendLine("StatModifiers".Translate() + ":"); - foreach (StatModifier mod in statMods) - { - s.AppendLine("\t" + mod.stat.LabelCap + " " + mod.ToStringAsOffset); - } - } - */ - } - var damageDef = slotBonus.Props.damageDef; - if (damageDef != null) - { - s.AppendLine(); - s.AppendLine(string.Format(StringOf.DamageType, new object[] {damageDef.LabelCap})); - } - var defHealChance = slotBonus.Props.defensiveHealChance; - if (defHealChance != null) - { - var healText = StringOf.all; - if (defHealChance.woundLimit != 0) healText = defHealChance.woundLimit.ToString(); - s.AppendLine(" " + string.Format(StringOf.DefensiveHealChance, new object[] - { - healText, - defHealChance.chance.ToStringPercent() - })); - } - var vampChance = slotBonus.Props.vampiricHealChance; - if (vampChance != null) - { - var vampText = StringOf.all; - if (vampChance.woundLimit != 0) vampText = defHealChance.woundLimit.ToString(); - s.AppendLine(" " + string.Format(StringOf.VampiricChance, new object[] - { - vampText, - vampChance.chance.ToStringPercent() - })); + first = false; } + s.AppendLine(" " + statEntry.LabelCap + " " + statEntry.ValueString); } + } } } return s.ToString(); } - - public override void PostExposeData() - { - Scribe_Values.Look(ref isInitialized, "isInitialized", false); - Scribe_Values.Look(ref isGathering, "isGathering", false); - Scribe_Collections.Look(ref slots, "slots", LookMode.Deep); - base.PostExposeData(); - if (slots == null) - slots = new List(); - if (Scribe.mode == LoadSaveMode.LoadingVars) - { - //Scribe.writingForDebug = false; - } - if (Scribe.mode == LoadSaveMode.PostLoadInit) - { - //Scribe.writingForDebug = true; - } - } - - } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadable.csproj b/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadable.csproj index bd15ccf1..c332f390 100755 --- a/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadable.csproj +++ b/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadable.csproj @@ -1,81 +1,10 @@  - - + + - Debug - AnyCPU - {6EC26D07-B5A0-4075-8919-3B05AF74CE87} - Library - Properties - CompSlotLoadable CompSlotLoadable - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - False - ..\..\..\Assemblies\0JecsTools.dll - False - - - - - - - - - - - - - - - - - - - - - - {106BF102-0379-41CF-9C5D-E21AAC5F051B} - JecsTools - - - - 1.1.2566 - - - 2.0.0.8 - + - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadableDefOf.cs b/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadableDefOf.cs index c080f2a4..525dc1c2 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadableDefOf.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/CompSlotLoadableDefOf.cs @@ -7,5 +7,9 @@ namespace CompSlotLoadable public static class CompSlotLoadableDefOf { public static JobDef GatherSlotItem; + + public static StatCategoryDef SlotLoadable; + + static CompSlotLoadableDefOf() => DefOfHelper.EnsureInitializedInCtor(typeof(CompSlotLoadableDefOf)); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/CompSlottedBonus.cs b/Source/AllModdingComponents/CompSlotLoadable/CompSlottedBonus.cs index ab4e4a97..8ac44262 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/CompSlottedBonus.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/CompSlottedBonus.cs @@ -1,9 +1,83 @@ -using Verse; +using System.Collections.Generic; +using RimWorld; +using Verse; namespace CompSlotLoadable { public class CompSlottedBonus : ThingComp { - public CompProperties_SlottedBonus Props => (CompProperties_SlottedBonus) props; + public CompProperties_SlottedBonus Props => (CompProperties_SlottedBonus)props; + + public virtual float GetStatOffset(StatDef stat) + { + var statModifiers = Props?.statModifiers; + if (statModifiers != null) + { + var statOffset = statModifiers.GetStatOffsetFromList(stat); + //Log.Message("adding in stat " + stat + " offset: " + statOffset); + if (!stat.parts.NullOrEmpty()) + { + var statReq = StatRequest.For(parent); + for (var i = 0; i < stat.parts.Count; i++) + { + //Log.Message("adding in parts " + stat.parts[i]); + stat.parts[i].TransformValue(statReq, ref statOffset); + } + //Log.Message("added in parts of a stat for result " + statOffset); + } + return statOffset; + } + return 0f; + } + + public override IEnumerable SpecialDisplayStats() + { + var props = Props; + if (props != null) + { + if (props.damageDef != null) + { + var damageTypeStr = props.damageDef.LabelCap; + yield return new StatDrawEntry(CompSlotLoadableDefOf.SlotLoadable, StringOf.OverrideDamageType, damageTypeStr, + string.Format(StringOf.OverrideDamageTypeExplanation, damageTypeStr), 99); + // TODO: armorPenStr should somehow be calculated via equivalent logic in ThingDef.SpecialDisplayStats. + var armorPenStr = props.armorPenetration.ToStringPercent(); + yield return new StatDrawEntry(CompSlotLoadableDefOf.SlotLoadable, StringOf.OverrideArmorPenetration, armorPenStr, + string.Format("ArmorPenetrationExplanation".Translate(), armorPenStr), 98); + } + var statModifiers = props.statModifiers; + if (statModifiers != null) + { + var statReq = StatRequest.For(parent); + foreach (var mod in statModifiers) + { + var stat = mod.stat; + yield return new StatDrawEntry(CompSlotLoadableDefOf.SlotLoadable, stat, + stat.Worker.GetValue(statReq), statReq, ToStringNumberSense.Offset); + } + } + var defHealChance = props.defensiveHealChance; + if (defHealChance != null) + { + var chanceStr = defHealChance.chance.ToStringPercent(); + var woundLimitStr = defHealChance.woundLimit == int.MaxValue ? StringOf.all : defHealChance.woundLimit.ToString(); + yield return new StatDrawEntry(CompSlotLoadableDefOf.SlotLoadable, StringOf.DefensiveHeal, + string.Format(StringOf.DefensiveHealShort, chanceStr, woundLimitStr, defHealChance.amountRange), + string.Format(StringOf.DefensiveHealExplanation, chanceStr, woundLimitStr, defHealChance.amountRange), + 90); + } + var vampHealChance = props.vampiricHealChance; + if (vampHealChance != null) + { + var chanceStr = vampHealChance.chance.ToStringPercent(); + var woundLimitStr = vampHealChance.woundLimit == int.MaxValue ? StringOf.all : vampHealChance.woundLimit.ToString(); + var armorPenStr = vampHealChance.armorPenetration.ToStringPercent(); + yield return new StatDrawEntry(CompSlotLoadableDefOf.SlotLoadable, StringOf.VampiricHeal, + string.Format(StringOf.VampiricHealShort, chanceStr, woundLimitStr, vampHealChance.amountRange, vampHealChance.damageDef, armorPenStr), + string.Format(StringOf.VampiricHealExplanation, chanceStr, woundLimitStr, vampHealChance.amountRange, vampHealChance.damageDef, armorPenStr), + 89); + } + } + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/JobDriver_GatherSlotItem.cs b/Source/AllModdingComponents/CompSlotLoadable/JobDriver_GatherSlotItem.cs index f92260cb..1283e929 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/JobDriver_GatherSlotItem.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/JobDriver_GatherSlotItem.cs @@ -6,16 +6,10 @@ namespace CompSlotLoadable { - /** - * Modified JobDriver_Equip - * Repurposed for loading a slot item. - */ + // Based off JobDriver_Equip. public class JobDriver_GatherSlotItem : JobDriver { - public override bool TryMakePreToilReservations(bool errorOnFailed) - { - return true; - } + public override bool TryMakePreToilReservations(bool errorOnFailed) => true; [DebuggerHidden] protected override IEnumerable MakeNewToils() @@ -23,52 +17,32 @@ protected override IEnumerable MakeNewToils() yield return Toils_Reserve.Reserve(TargetIndex.A, 1); var toil = new Toil { - initAction = delegate { pawn.pather.StartPath(TargetThingA, PathEndMode.ClosestTouch); }, - defaultCompleteMode = ToilCompleteMode.PatherArrival + initAction = () => pawn.pather.StartPath(TargetThingA, PathEndMode.ClosestTouch), + defaultCompleteMode = ToilCompleteMode.PatherArrival, }; toil.FailOnDespawnedNullOrForbidden(TargetIndex.A); yield return toil; yield return new Toil { - initAction = delegate + initAction = () => { var itemToGather = job.targetA.Thing; //bool flag = false; - Thing itemToGatherSplit; - if (itemToGather.def.stackLimit > 1 && itemToGather.stackCount > 1) - itemToGatherSplit = itemToGather.SplitOff(1); - else - itemToGatherSplit = itemToGather; + var itemToGatherSplit = itemToGather.def.stackLimit > 1 && itemToGather.stackCount > 1 + ? itemToGather.SplitOff(1) + : itemToGather; //Find the compslotloadable - var pawn_EquipmentTracker = pawn.equipment; - if (pawn_EquipmentTracker != null) + if (pawn.equipment.Primary is ThingWithComps primary && primary.GetCompSlotLoadable() is CompSlotLoadable compSlotLoadable) { - //Log.Message("2"); - var thingWithComps = - pawn_EquipmentTracker - .Primary; //(ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); - - if (thingWithComps != null) - { - //Log.Message("3"); - var CompSlotLoadable = thingWithComps.GetComp(); - if (CompSlotLoadable != null) - { - CompSlotLoadable.TryLoadSlot(itemToGather); - if (thingWithComps.def.soundInteract != null) - thingWithComps.def.soundInteract.PlayOneShot(new TargetInfo(pawn.Position, pawn.Map, - false)); - //if (flag) - //{ - // thingWithComps.DeSpawn(); - //} - } - } + compSlotLoadable.TryLoadSlot(itemToGather); + primary.def.soundInteract?.PlayOneShot(new TargetInfo(pawn.Position, pawn.Map)); + //if (flag) + // thingWithComps.DeSpawn(); } }, - defaultCompleteMode = ToilCompleteMode.Instant + defaultCompleteMode = ToilCompleteMode.Instant, }; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/SlotBonusProps_DefensiveHealChance.cs b/Source/AllModdingComponents/CompSlotLoadable/SlotBonusProps_DefensiveHealChance.cs index 225d6d93..b4e8f82c 100755 --- a/Source/AllModdingComponents/CompSlotLoadable/SlotBonusProps_DefensiveHealChance.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/SlotBonusProps_DefensiveHealChance.cs @@ -1,8 +1,12 @@ -namespace CompSlotLoadable +using Verse; + +namespace CompSlotLoadable { public class SlotBonusProps_DefensiveHealChance { public float chance = 0.05f; public int woundLimit = 0; + // Default value matches the previously hard-coded behavior of always fully healing the hediff. + public FloatRange amountRange = new FloatRange(float.PositiveInfinity, float.PositiveInfinity); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/SlotBonusProps_VampiricEffect.cs b/Source/AllModdingComponents/CompSlotLoadable/SlotBonusProps_VampiricEffect.cs index c626b656..93733267 100755 --- a/Source/AllModdingComponents/CompSlotLoadable/SlotBonusProps_VampiricEffect.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/SlotBonusProps_VampiricEffect.cs @@ -1,8 +1,13 @@ -namespace CompSlotLoadable +using Verse; + +namespace CompSlotLoadable { public class SlotBonusProps_VampiricEffect { public float chance = 0.05f; public int woundLimit = 0; + public FloatRange amountRange = new FloatRange(5f, 10f); + public DamageDef damageDef; + public float armorPenetration = 1f; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/SlotLoadable.cs b/Source/AllModdingComponents/CompSlotLoadable/SlotLoadable.cs index 4b2818e9..3c4671ab 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/SlotLoadable.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/SlotLoadable.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; +using System.Linq; using RimWorld; using UnityEngine; using Verse; namespace CompSlotLoadable { + // Based off ActiveDropPodInfo. public class SlotLoadable : Thing, IThingHolder { //Spawn methods @@ -15,8 +17,6 @@ public SlotLoadable() public SlotLoadable(Thing newOwner) { //Log.Message("Slot started"); - var def = this.def as SlotLoadableDef; - slottableThingDefs = def.slottableThingDefs; owner = newOwner; ThingIDMaker.GiveIDTo(this); slot = new ThingOwner(this, false, LookMode.Deep); @@ -31,37 +31,16 @@ public SlotLoadable(SlotLoadableDef xmlDef, Thing newOwner) ThingIDMaker.GiveIDTo(this); slot = new ThingOwner(this, false, LookMode.Deep); } - - public Texture2D SlotIcon() - { - if (SlotOccupant != null) - if (SlotOccupant.def != null) - return SlotOccupant.def.uiIcon; - return null; - } - public Color SlotColor() - { - if (SlotOccupant != null) - if (SlotOccupant.def != null) - return SlotOccupant.def.graphic.Color; - return Color.white; - } + public SlotLoadableDef Def => def as SlotLoadableDef; - public bool IsEmpty() - { - if (SlotOccupant != null) return false; - return true; - } + public Texture2D SlotIcon() => SlotOccupant?.def?.uiIcon; - public bool CanLoad(ThingDef defType) - { - if (slottableThingDefs != null) - if (slottableThingDefs.Count > 0) - if (slottableThingDefs.Contains(defType)) - return true; - return false; - } + public Color SlotColor() => SlotOccupant?.def?.graphic.Color ?? Color.white; + + public bool IsEmpty() => SlotOccupant == null; + + public bool CanLoad(ThingDef defType) => SlottableTypes.Contains(defType); public override void ExposeData() { @@ -69,53 +48,46 @@ public override void ExposeData() if (Scribe.mode == LoadSaveMode.Saving) if (thingIDNumber == -1) ThingIDMaker.GiveIDTo(this); - Scribe_Deep.Look(ref slot, "slot", this); - Scribe_Collections.Look(ref slottableThingDefs, "slottableThingDefs", LookMode.Undefined); - Scribe_References.Look(ref owner, "owner"); - //Scribe_References.Look(ref this.slotOccupant, "slotOccupant"); + Scribe_Deep.Look(ref slot, nameof(slot), this); + Scribe_References.Look(ref owner, nameof(owner)); + + // Only save slottableThingDefs if it isn't Def.slottableThingDefs (otherwise, save null) to save space. + var defSlottableThingDefs = Def?.slottableThingDefs; + var savedSlottableThingDefs = slottableThingDefs; + if (defSlottableThingDefs != null && slottableThingDefs != null && + defSlottableThingDefs.SequenceEqual(slottableThingDefs)) + savedSlottableThingDefs = null; + Scribe_Collections.Look(ref savedSlottableThingDefs, nameof(slottableThingDefs), LookMode.Def); + if (slottableThingDefs != null) + slottableThingDefs = savedSlottableThingDefs; } #region Variables //Exposable Variables - //private Thing slotOccupant; private ThingOwner slot; + private List slottableThingDefs; - //Settable variables - public List slottableThingDefs; - - // //Spawn variables public Thing owner; + private CompSlotLoadable parentComp; #endregion Variables #region IThingOwnerOwner - public Map GetMap() - { - return ParentMap; - } + public Map GetMap() => ParentMap; - public ThingOwner GetInnerContainer() - { - return slot; - } + public ThingOwner GetInnerContainer() => slot; - public IntVec3 GetPosition() - { - return ParentLoc; - } + public IntVec3 GetPosition() => ParentLoc; public void GetChildHolders(List outChildren) { ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings()); } - public ThingOwner GetDirectlyHeldThings() - { - return slot; - } + public ThingOwner GetDirectlyHeldThings() => slot; #endregion IThingOwnerOwner @@ -123,6 +95,9 @@ public ThingOwner GetDirectlyHeldThings() //Get methods + // XXX: Not sure of all the ways SlotLoadable is initialized (like whether client code does it itself), + // but they should all have parent CompSlotLoadable, which is lazily initialized here from owner. + public CompSlotLoadable ParentComp => parentComp ??= owner?.TryGetCompSlotLoadable(); public Thing SlotOccupant { @@ -131,7 +106,7 @@ public Thing SlotOccupant if (slot.Count == 0) return null; if (slot.Count > 1) - Log.Error("ContainedThing used on a DropPodInfo holding > 1 thing."); + Log.Error("ContainedThing used on a SlotLoadable holding > 1 thing."); return slot[0]; } set @@ -141,22 +116,13 @@ public Thing SlotOccupant { var takenThing = value.holdingOwner.Take(value, 1); value.DeSpawn(); - slot.TryAdd(takenThing, true); + slot.TryAdd(takenThing); } else { - slot.TryAdd(value, true); + slot.TryAdd(value); } } - - //get - //{ - // return slotOccupant; - //} - //set - //{ - // slotOccupant = value; - //} } public ThingOwner Slot @@ -165,41 +131,21 @@ public ThingOwner Slot set => slot = value; } - public Pawn Holder - { - get - { - Pawn result = null; - if (owner != null) - { - var eq = owner.TryGetComp(); - if (eq != null) - if (eq.PrimaryVerb != null) - { - var pawn = eq.PrimaryVerb.CasterPawn; - if (pawn != null) - if (pawn.Spawned) - result = pawn; - } - } - return result; - } - } + public Pawn Holder => ParentComp?.GetPawn is Pawn pawn && pawn.Spawned ? pawn : null; public Map ParentMap { get { - Map result = null; //Does our parent have an equippable class? //Use that to find a pawn location if it's equipped. if (owner != null) { - if (Holder != null) - return Holder.Map; + if (Holder is Pawn holder) + return holder.Map; return owner.Map; } - return result; + return null; } } @@ -207,20 +153,24 @@ public IntVec3 ParentLoc { get { - var result = IntVec3.Invalid; //Does our parent have an equippable class? //Use that to find a pawn location if it's equipped. if (owner != null) { - if (Holder != null) - return Holder.Position; + if (Holder is Pawn holder) + return holder.Position; return owner.Position; } - return result; + return IntVec3.Invalid; } } - public List SlottableTypes => slottableThingDefs; + public List SlottableTypes + { + // def isn't available during constructor, so slottableThingDefs is lazily initialized here. + get => slottableThingDefs ??= Def?.slottableThingDefs ?? new List(); + set => slottableThingDefs = value; + } #endregion Properties @@ -229,34 +179,28 @@ public IntVec3 ParentLoc public virtual bool TryLoadSlot(Thing thingToLoad, bool emptyIfFilled = false) { //Log.Message("TryLoadSlot Called"); - if (SlotOccupant != null && emptyIfFilled || SlotOccupant == null) + if (SlotOccupant == null || emptyIfFilled) { TryEmptySlot(); - if (thingToLoad != null) - if (slottableThingDefs != null) - if (slottableThingDefs.Contains(thingToLoad.def)) - { - SlotOccupant = thingToLoad; - //slot.TryAdd(thingToLoad, false); - if (((SlotLoadableDef) def).doesChangeColor) - owner.Notify_ColorChanged(); - return true; - } + if (thingToLoad != null && CanLoad(thingToLoad.def)) + { + SlotOccupant = thingToLoad; + //slot.TryAdd(thingToLoad, false); + if (Def?.doesChangeColor ?? false) + owner.Notify_ColorChanged(); + return true; + } } else { - Messages.Message(string.Format(StringOf.ExceptionSlotAlreadyFilled, new object[] - { - owner.Label - }), MessageTypeDefOf.RejectInput); + Messages.Message(string.Format(StringOf.ExceptionSlotAlreadyFilled, owner.Label), MessageTypeDefOf.RejectInput); } return false; } public virtual bool TryEmptySlot() { - if (!CanEmptySlot()) return false; - return slot.TryDropAll(ParentLoc, ParentMap, ThingPlaceMode.Near); + return CanEmptySlot() && slot.TryDropAll(ParentLoc, ParentMap, ThingPlaceMode.Near); } public virtual bool CanEmptySlot() @@ -266,4 +210,4 @@ public virtual bool CanEmptySlot() #endregion Methods } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableDef.cs b/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableDef.cs index 83fe99a3..0438b4de 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableDef.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableDef.cs @@ -21,4 +21,4 @@ public class SlotLoadableDef : ThingDef //These can be loaded into the slot. public List slottableThingDefs; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableFloatMenuPatch.cs b/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableFloatMenuPatch.cs index 3bc82093..347c2037 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableFloatMenuPatch.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableFloatMenuPatch.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using JecsTools; using RimWorld; using UnityEngine; @@ -14,82 +13,67 @@ public class SloatLoadbleFloatMenuPatch : FloatMenuPatch public override IEnumerable>>> GetFloatMenus() { - var FloatMenus = new List>>>(); - var curCondition = new _Condition(_ConditionType.ThingHasComp, typeof(CompSlottedBonus)); - List CurFunc(Vector3 clickPos, Pawn pawn, Thing curThing) + static List CurFunc(Vector3 clickPos, Pawn pawn, Thing curThing) { //Log.Message("Patch is loaded"); var opts = new List(); - List holders = new List(); + var holders = new List(); pawn.GetChildHolders(holders); - var allThings = new List(); - holders.ForEach(x => allThings.AddRange(x.GetDirectlyHeldThings().ToList())); - foreach (var item in allThings) + foreach (var holder in holders) { - if (item is ThingWithComps slotLoadable && - slotLoadable.AllComps.FirstOrDefault(x => x is CompSlotLoadable) is CompSlotLoadable - compSlotLoadable) + foreach (var item in holder.GetDirectlyHeldThings()) { - var c = clickPos.ToIntVec3(); - //var thingList = c.GetThingList(pawn.Map); - - foreach (var slot in compSlotLoadable.Slots) + var slots = item.GetSlots(); + if (slots != null) { - var loadableThing = (slot.CanLoad(curThing.def)) ? curThing : null ; - if (loadableThing != null) + foreach (var slot in slots) { - FloatMenuOption itemSlotLoadable; - var labelShort = loadableThing.Label; - if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)) - { - itemSlotLoadable = new FloatMenuOption( - "CannotEquip".Translate(labelShort) + " (" + "Incapable".Translate() + ")", - null, - MenuOptionPriority.Default, null, null, 0f, null, null); - } - else if (!pawn.CanReach(loadableThing, PathEndMode.ClosestTouch, Danger.Deadly)) - { - itemSlotLoadable = new FloatMenuOption( - "CannotEquip".Translate(labelShort) + " (" + "NoPath".Translate() + ")", null, - MenuOptionPriority.Default, null, null, 0f, null, null); - } - else if (!pawn.CanReserve(loadableThing, 1)) + var loadableThing = slot.CanLoad(curThing.def) ? curThing : null; + if (loadableThing != null) { - itemSlotLoadable = new FloatMenuOption( - "CannotEquip".Translate(labelShort) + " (" + - "ReservedBy".Translate(pawn.Map.physicalInteractionReservationManager - .FirstReserverOf(loadableThing).LabelShort) + ")", null, - MenuOptionPriority.Default, null, null, 0f, null, null); - } - else - { - var text2 = "Equip".Translate(labelShort); - itemSlotLoadable = new FloatMenuOption(text2, delegate + FloatMenuOption itemSlotLoadable; + var labelShort = loadableThing.Label; + if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)) + { + itemSlotLoadable = new FloatMenuOption( + "CannotEquip".Translate(labelShort) + " (" + "Incapable".Translate() + ")", null); + } + else if (!pawn.CanReach(loadableThing, PathEndMode.ClosestTouch, Danger.Deadly)) + { + itemSlotLoadable = new FloatMenuOption( + "CannotEquip".Translate(labelShort) + " (" + "NoPath".Translate() + ")", null); + } + else if (!pawn.CanReserve(loadableThing, 1)) + { + itemSlotLoadable = new FloatMenuOption( + "CannotEquip".Translate(labelShort) + " (" + + "ReservedBy".Translate(pawn.Map.physicalInteractionReservationManager + .FirstReserverOf(loadableThing).LabelShort) + ")", null); + } + else { - loadableThing.SetForbidden(false, true); - pawn.jobs.TryTakeOrderedJob(new Job( - DefDatabase.GetNamed("GatherSlotItem"), - loadableThing)); - MoteMaker.MakeStaticMote(loadableThing.DrawPos, loadableThing.Map, - ThingDefOf.Mote_FeedbackEquip, 1f); - //PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.EquippingWeapons, KnowledgeAmount.Total); - }, MenuOptionPriority.High, null, null, 0f, null, null); + itemSlotLoadable = new FloatMenuOption( + "Equip".Translate(labelShort), () => + { + loadableThing.SetForbidden(false, true); + pawn.jobs.TryTakeOrderedJob(JobMaker.MakeJob(CompSlotLoadableDefOf.GatherSlotItem, loadableThing)); + FleckMaker.Static(loadableThing.DrawPos, loadableThing.Map, FleckDefOf.FeedbackEquip); + //PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.EquippingWeapons, KnowledgeAmount.Total); + }, MenuOptionPriority.High); + } + opts.Add(itemSlotLoadable); } - opts.Add(itemSlotLoadable); } + return opts; } - return opts; } } return opts; } - KeyValuePair<_Condition, Func>> curSec = - new KeyValuePair<_Condition, Func>>(curCondition, CurFunc); - FloatMenus.Add(curSec); - return FloatMenus; + yield return new KeyValuePair<_Condition, Func>>(curCondition, CurFunc); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableUtility.cs b/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableUtility.cs index 4ac6eed3..5378f80a 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableUtility.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/SlotLoadableUtility.cs @@ -1,77 +1,77 @@ using System.Collections.Generic; -using System.Linq; using RimWorld; using Verse; namespace CompSlotLoadable { - [StaticConstructorOnStartup] public static class SlotLoadableUtility { - // Grab slots of the thing if they exists. Returns null if none - public static List GetSlots(Thing someThing) + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static CompSlotLoadable GetCompSlotLoadable(this ThingWithComps thing) { - List retval = null; - - if (someThing is ThingWithComps thingWithComps) + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) { - var comp = thingWithComps.AllComps.FirstOrDefault(x => x is CompSlotLoadable); - if (comp != null) - { - var compSlotLoadable = comp as CompSlotLoadable; + if (comps[i] is CompSlotLoadable comp) + return comp; + } + return null; + } - if (compSlotLoadable.Slots != null && compSlotLoadable.Slots.Count > 0) - retval = compSlotLoadable.Slots; - } + public static CompSlotLoadable TryGetCompSlotLoadable(this Thing thing) + { + return thing is ThingWithComps thingWithComps ? thingWithComps.GetCompSlotLoadable() : null; + } + + public static CompSlottedBonus GetCompSlottedBonus(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompSlottedBonus comp) + return comp; } + return null; + } - return retval; + public static CompSlottedBonus TryGetCompSlottedBonus(this Thing thing) + { + return thing is ThingWithComps thingWithComps ? thingWithComps.GetCompSlottedBonus() : null; } + // Grab slots of the thing if they exists. Returns null if none. + public static List GetSlots(this Thing thing) + { + var slots = thing.TryGetCompSlotLoadable()?.Slots; + return !slots.NullOrEmpty() ? slots : null; + } - // Get the thing's modificaiton to stat from it's slots - public static float CheckThingSlotsForStatAugment(Thing slottedThing, StatDef stat) + public static List GetSlots(this ThingWithComps thing) { - var retval = 0.0f; - var slots = GetSlots(slottedThing); + var slots = thing.GetCompSlotLoadable()?.Slots; + return !slots.NullOrEmpty() ? slots : null; + } + // Get the thing's modification to stat from its slots. + public static float CheckThingSlotsForStatAugment(Thing slottedThing, StatDef stat) + { + var statOffset = 0.0f; + var slots = slottedThing.GetSlots(); if (slots != null) + { foreach (var slot in slots) - if (!slot.IsEmpty()) + { + if (slot.Def?.doesChangeStats ?? false) { - var slottable = slot.SlotOccupant; - retval += DetermineSlottableStatAugment(slottable, stat); + var slotBonus = slot.SlotOccupant?.TryGetCompSlottedBonus(); + if (slotBonus != null) + statOffset += slotBonus.GetStatOffset(stat); } - return retval; - } - - - public static float DetermineSlottableStatAugment(Thing slottable, StatDef stat) - { - var retval = 0.0f; - var slotBonus = slottable.TryGetComp(); - if (slotBonus != null) - if (slotBonus.Props != null) - if (slotBonus.Props.statModifiers != null && slotBonus.Props.statModifiers.Count > 0) - foreach (var thisStat in slotBonus.Props.statModifiers) - //Log.Message("Check for modding "+stat+" against "+thisStat.stat); - if (thisStat.stat == stat) - { - //Log.Message("adding in stat "+thisStat.stat+":"+thisStat.value+" to result "+retval); - retval += thisStat.value; - - // apply stats parts from Slottable - if (stat.parts != null && stat.parts.Count > 0) - { - var req = StatRequest.For(slottable); - for (var i = 0; i < stat.parts.Count; i++) - //Log.Message("adding in parts "+stat.parts[i]); - stat.parts[i].TransformValue(req, ref retval); - //Log.Message("added in parts of a stat for result "+retval); - } - } - - return retval; + } + } + return statOffset; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/StringOf.cs b/Source/AllModdingComponents/CompSlotLoadable/StringOf.cs index 2200d9d4..8bd4147d 100755 --- a/Source/AllModdingComponents/CompSlotLoadable/StringOf.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/StringOf.cs @@ -1,5 +1,6 @@ namespace CompSlotLoadable { + // TODO: These should be translation keys public static class StringOf { public static string all = "all"; @@ -11,9 +12,16 @@ public static class StringOf public static string Effects = "Effects:"; public static string ChangesPrimaryColor = "Changes Primary Color"; public static string StatModifiers = "Stat Modifiers"; - public static string DamageType = "Damage Type: {0}"; + public static string OverrideDamageType = "Override damage type"; + public static string OverrideDamageTypeExplanation = "Overrides attack's damage type with {0}"; + public static string OverrideArmorPenetration = "Override armor penetration"; public static string NoLoadOptions = "No load options available."; - public static string DefensiveHealChance = "When attacked, {1} chance to heal {0} wounds"; - public static string VampiricChance = "When attacking, {1} chance to vampiricly heal {0} wounds"; + public static string DefensiveHeal = "Defensive heal"; + public static string DefensiveHealShort = "{0} for {1} wounds, max {2} amount"; + public static string DefensiveHealExplanation = "When attacked, {0} chance to heal {1} wounds up to {2} total amount"; + public static string VampiricHeal = "Vampiric heal"; + public static string VampiricHealShort = "{0} for {1} wounds, max {2} amount\n({3} damage, {4} armor penetration)"; + public static string VampiricHealExplanation = "When attacking, {0} chance to vampiricly heal {1} wounds up to {2} total amount, " + + "dealing additional {2} {3} damage with {4} armor penetration"; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompSlotLoadable/_HarmonyCompSlotLoadable.cs b/Source/AllModdingComponents/CompSlotLoadable/_HarmonyCompSlotLoadable.cs index 230eb4f8..4f58a50d 100644 --- a/Source/AllModdingComponents/CompSlotLoadable/_HarmonyCompSlotLoadable.cs +++ b/Source/AllModdingComponents/CompSlotLoadable/_HarmonyCompSlotLoadable.cs @@ -5,7 +5,6 @@ using RimWorld; using UnityEngine; using Verse; -using Verse.AI; namespace CompSlotLoadable { @@ -19,167 +18,7 @@ internal static class HarmonyCompSlotLoadable static HarmonyCompSlotLoadable() { var harmony = new Harmony("jecstools.jecrell.comps.slotloadable"); - var type = typeof(HarmonyCompSlotLoadable); -<<<<<<< Updated upstream - harmony.Patch(AccessTools.Method(typeof(Pawn), nameof(Pawn.GetGizmos)), null, - new HarmonyMethod(type, nameof(GetGizmos_PostFix))); - harmony.Patch(AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValue)), null, - new HarmonyMethod(type, nameof(GetStatValue_PostFix))); - harmony.Patch(AccessTools.Method(typeof(Verb_MeleeAttackDamage), "DamageInfosToApply"), null, - new HarmonyMethod(type, nameof(DamageInfosToApply_PostFix)), null); - harmony.Patch(AccessTools.Method(typeof(ITab_Pawn_Gear), "DrawThingRow"), null, - new HarmonyMethod(type, nameof(DrawThingRow_PostFix)), null); - harmony.Patch(AccessTools.Method(typeof(Pawn), nameof(Pawn.PostApplyDamage)), null, - new HarmonyMethod(type, nameof(PostApplyDamage_PostFix)), null); - harmony.Patch(AccessTools.Method(typeof(StatWorker), "StatOffsetFromGear"), null, - new HarmonyMethod(type, nameof(StatOffsetFromGear_PostFix))); - } - - // debugging - /* - public static void TicksPerMove_PostFix(Pawn __instance, ref float __result, bool diagonal) { - if ( __instance.IsColonist ) { - float num = __instance.GetStatValue(StatDefOf.MoveSpeed, true); - Log.Message("move speed : "+__instance.Name+ " : (GetStatValue of MoveSpeed:" +num+") (TicksPerMove:"+__result+")"); - } - } */ - - //try to extend this - public static void StatOffsetFromGear_PostFix(ref float __result, Thing gear, StatDef stat) - { - var retValue = 0.0f; - try - { - retValue = SlotLoadableUtility.CheckThingSlotsForStatAugment(gear, stat); - } - catch (Exception e) - { - Log.Warning("Failed to add stats for " + gear.Label + "\n" + e.ToString()); - } - __result += retValue; - } - - - /// - /// Applies the special properties to the slot loadable. - /// - /// - /// - /// - public static void PostApplyDamage_PostFix(Pawn __instance, DamageInfo dinfo, float totalDamageDealt) - { - if (__instance == null) return; - if (__instance.Dead || __instance.equipment == null) return; - var thingWithComps = __instance.equipment.Primary; - if (thingWithComps != null) - { - var comp = thingWithComps.AllComps.FirstOrDefault(x => x is CompSlotLoadable); - if (comp != null) - { - var compSlotLoadable = comp as CompSlotLoadable; - if (compSlotLoadable.Slots != null && compSlotLoadable.Slots.Count > 0) - foreach (var slot in compSlotLoadable.Slots) - if (!slot.IsEmpty()) - { - var slotBonus = slot.SlotOccupant.TryGetComp(); - if (slotBonus != null) - if (slotBonus.Props != null) - { - var defensiveHealChance = slotBonus.Props.defensiveHealChance; - if (defensiveHealChance != null) - { - //Log.Message("defensiveHealingCalled"); - var randValue = Rand.Value; - //Log.Message("randValue = " + randValue.ToString()); - if (randValue <= defensiveHealChance.chance) - { - MoteMaker.ThrowText(__instance.DrawPos, __instance.Map, - "Heal Chance: Success", 6f); - ApplyHealing(__instance, defensiveHealChance.woundLimit); - } - } - } - } - } - } - } - - public static void ApplyHealing(Thing thing, int woundLimit = 0, Thing vampiricTarget = null) - { - if (thing is Pawn pawn) - { - var maxInjuries = woundLimit; - - foreach (var rec in pawn.health.hediffSet.GetInjuredParts()) - if (maxInjuries > 0 || woundLimit == 0) - foreach (var current in from injury in pawn.health.hediffSet.GetHediffs() - where injury.Part == rec - select injury) - //if (maxInjuriesPerBodypart > 0) - //{ - if (current.CanHealNaturally() && !current.IsPermanent()) // isOld // basically check for scars and old wounds - { - current.Heal((int) current.Severity + 1); - maxInjuries--; - //maxInjuriesPerBodypart--; - } - //} - - // - if (vampiricTarget != null) - { - var maxInjuriesToMake = woundLimit; - if (woundLimit == 0) maxInjuriesToMake = 2; - - var vampiricPawn = vampiricTarget as Pawn; - foreach (var rec in vampiricPawn.health.hediffSet.GetNotMissingParts().InRandomOrder()) - if (maxInjuriesToMake > 0) - { - vampiricPawn.TakeDamage(new DamageInfo(DamageDefOf.Burn, new IntRange(5, 10).RandomInRange, - 1f, 1, vampiricPawn, rec)); - - maxInjuriesToMake--; - } - } - } - } - //=================================== COMPSLOTLOADABLE - - public static void DrawThingRow_PostFix(ITab_Pawn_Gear __instance, ref float y, float width, Thing thing, - bool inventory = false) - { - //Log.Message("1"); - if (thing is ThingWithComps thingWithComps) - { - var comp = thingWithComps.AllComps.FirstOrDefault(x => x is CompSlotLoadable); - if (comp != null) - { - var compSlotLoadable = comp as CompSlotLoadable; - if (compSlotLoadable.Slots != null && compSlotLoadable.Slots.Count > 0) - foreach (var slot in compSlotLoadable.Slots) - if (!slot.IsEmpty()) - { - var rect = new Rect(0f, y, width, 28f); - Widgets.InfoCardButton(rect.width - 24f, y, slot.SlotOccupant); - rect.width -= 24f; - //bool CanControl = (bool)AccessTools.Method(typeof(ITab_Pawn_Gear), "get_CanControl").Invoke(__instance, null); - if (Mouse.IsOver(rect)) - { - GUI.color = HighlightColor; - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - if (slot.SlotOccupant.def.DrawMatSingle != null && - slot.SlotOccupant.def.DrawMatSingle.mainTexture != null) - Widgets.ThingIcon(new Rect(4f, y, 28f, 28f), slot.SlotOccupant, 1f); - Text.Anchor = TextAnchor.MiddleLeft; - GUI.color = ThingLabelColor; - var rect4 = new Rect(36f, y, width - 36f, 28f); - var text = slot.SlotOccupant.LabelCap; - Widgets.Label(rect4, text); - y += 28f; - } -======= harmony.Patch(AccessTools.Method(typeof(Pawn_EquipmentTracker), nameof(Pawn_EquipmentTracker.GetGizmos)), postfix: new HarmonyMethod(type, nameof(GetGizmos_PostFix))); @@ -205,115 +44,10 @@ public static void GetGizmos_PostFix(Pawn_EquipmentTracker __instance, ref IEnum if (compSlotLoadable != null && compSlotLoadable.GizmosOnEquip) { __result = __result.Concat(compSlotLoadable.EquippedGizmos()); ->>>>>>> Stashed changes } } } -<<<<<<< Updated upstream - // RimWorld.Verb_MeleeAttack - public static void DamageInfosToApply_PostFix(Verb_MeleeAttack __instance, ref IEnumerable __result, - LocalTargetInfo target) - { - var newList = new List(); - //__result = null; - var EquipmentSource = __instance.EquipmentSource; - if (EquipmentSource != null) - { - //Log.Message("1"); - var comp = EquipmentSource.AllComps.FirstOrDefault(x => x is CompSlotLoadable); - if (comp != null) - { - //Log.Message("2"); - var compSlotLoadable = comp as CompSlotLoadable; - if (compSlotLoadable.Slots != null && compSlotLoadable.Slots.Count > 0) - { - //Log.Message("3"); - var statSlots = compSlotLoadable.Slots.FindAll(z => - !z.IsEmpty() && ((SlotLoadableDef) z.def).doesChangeStats); - if (statSlots != null && statSlots.Count > 0) - foreach (var slot in statSlots) - { - //Log.Message("5"); - var slotBonus = slot.SlotOccupant.TryGetComp(); - if (slotBonus != null) - { - //Log.Message("6"); - var superClass = __instance.GetType().BaseType; - if (slotBonus.Props.damageDef != null) - { - //Log.Message("7"); - var num = __instance.verbProps.AdjustedMeleeDamageAmount(__instance, - __instance.CasterPawn); - var def = __instance.verbProps.meleeDamageDef; - BodyPartGroupDef weaponBodyPartGroup = null; - HediffDef weaponHediff = null; - if (__instance.CasterIsPawn) - if (num >= 1f) - { - weaponBodyPartGroup = __instance.verbProps.linkedBodyPartsGroup; - if (__instance.HediffCompSource != null) - weaponHediff = __instance.HediffCompSource.Def; - } - else - { - num = 1f; - def = DamageDefOf.Blunt; - } - - //Log.Message("9"); - ThingDef def2; - if (__instance.EquipmentSource != null) - def2 = __instance.EquipmentSource.def; - else - def2 = __instance.CasterPawn.def; - - //Log.Message("10"); - var angle = (target.Thing.Position - __instance.CasterPawn.Position) - .ToVector3(); - - //Log.Message("11"); - var caster = __instance.caster; - - //Log.Message("12"); - var newdamage = GenMath.RoundRandom(num); -// Log.Message("applying damage "+newdamage+" out of "+num); - var damageInfo = new DamageInfo(slotBonus.Props.damageDef, newdamage, slotBonus.Props.armorPenetration, -1f, - caster, null, def2); - damageInfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside); - damageInfo.SetWeaponBodyPartGroup(weaponBodyPartGroup); - damageInfo.SetWeaponHediff(weaponHediff); - damageInfo.SetAngle(angle); - - //Log.Message("13"); - newList.Add(damageInfo); - - __result = newList.AsEnumerable(); - } - var vampiricEffect = slotBonus.Props.vampiricHealChance; - if (vampiricEffect != null) - { - //Log.Message("vampiricHealingCalled"); - var randValue = Rand.Value; - //Log.Message("randValue = " + randValue.ToString()); - - if (randValue <= vampiricEffect.chance) - { - MoteMaker.ThrowText(__instance.CasterPawn.DrawPos, - __instance.CasterPawn.Map, "Vampiric Effect: Success", 6f); - //MoteMaker.ThrowText(__instance.CasterPawn.DrawPos, __instance.CasterPawn.Map, "Success".Translate(), 6f); - ApplyHealing(__instance.caster, vampiricEffect.woundLimit, target.Thing); - } - } - } - } - } - } - } - } - - public static void AddHumanlikeOrders_PostFix(Vector3 clickPos, Pawn pawn, List opts) -======= // XXX: If any slot has a CompSlottedBonus with damageDef, all existing melee attacks are replaced with a custom melee attack // that uses that damageDef & custom armorPenetration & damage = orig damage * 0.8~1.2. The logic is based off Verb_MeleeAttackDamage's, // but is missing extra damages, surprise attack, and potentially other logic. @@ -325,200 +59,86 @@ public static void AddHumanlikeOrders_PostFix(Vector3 clickPos, Pawn pawn, List< private const float MeleeDamageRandomFactorMax = 1.2f; public static void DamageInfosToApply_PostFix(Verb_MeleeAttack __instance, ref IEnumerable __result, LocalTargetInfo target) ->>>>>>> Stashed changes { - var c = IntVec3.FromVector3(clickPos); + var equipmentSource = __instance.EquipmentSource; + if (equipmentSource == null) + return; + var casterPawn = __instance.CasterPawn; + if (casterPawn == null) + return; - var slotLoadable = - pawn.equipment.AllEquipmentListForReading.FirstOrDefault(x => x.TryGetComp() != null); - if (slotLoadable != null) + var slots = equipmentSource.GetSlots(); + if (slots != null) { - var compSlotLoadable = slotLoadable.GetComp(); - if (compSlotLoadable != null) - { - var thingList = c.GetThingList(pawn.Map); + Vector3? damageAngle = null; + var hediffCompSource = __instance.HediffCompSource; + var verbProps = __instance.verbProps; - foreach (var slot in compSlotLoadable.Slots) + List newList = null; + foreach (var slot in slots) + { + // Skip slot if doesChangeStats (defaults to false) is false. + if (!(slot.Def?.doesChangeStats ?? false)) + continue; + var slotBonus = slot.SlotOccupant?.TryGetCompSlottedBonus(); + if (slotBonus != null) { - var loadableThing = thingList.FirstOrDefault(y => slot.CanLoad(y.def)); - if (loadableThing != null) + var slotBonusProps = slotBonus.Props; + var damageDef = slotBonusProps.damageDef; + if (damageDef != null) { - FloatMenuOption itemSlotLoadable; - var labelShort = loadableThing.Label; - if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)) - { - itemSlotLoadable = new FloatMenuOption( - "CannotEquip".Translate(labelShort) + " (" + "Incapable".Translate() + ")", null, - MenuOptionPriority.Default, null, null, 0f, null, null); - } - else if (!pawn.CanReach(loadableThing, PathEndMode.ClosestTouch, Danger.Deadly)) + // This logic should be same as the first Verb_MeleeAttackDamage.DamageInfosToApply DamageInfo, + // except using damageDef (and CasterPawn always being non-null as established above). + var damageAmount = verbProps.AdjustedMeleeDamageAmount(__instance, casterPawn); + var weaponBodyPartGroup = verbProps.AdjustedLinkedBodyPartsGroup(__instance.tool); + HediffDef weaponHediff = null; + damageAmount = Rand.Range(damageAmount * MeleeDamageRandomFactorMin, + damageAmount * MeleeDamageRandomFactorMax); + if (damageAmount >= 1f) { - itemSlotLoadable = new FloatMenuOption( - "CannotEquip".Translate(labelShort) + " (" + "NoPath".Translate() + ")", null, - MenuOptionPriority.Default, null, null, 0f, null, null); - } - else if (!pawn.CanReserve(loadableThing, 1)) - { - itemSlotLoadable = new FloatMenuOption( - "CannotEquip".Translate(labelShort) + " (" + - "ReservedBy".Translate(pawn.Map.physicalInteractionReservationManager - .FirstReserverOf(loadableThing).LabelShort) + ")", null, - MenuOptionPriority.Default, null, null, 0f, null, null); + if (hediffCompSource != null) + weaponHediff = hediffCompSource.Def; } else { - var text2 = "Equip".Translate(labelShort); - itemSlotLoadable = new FloatMenuOption(text2, delegate - { - loadableThing.SetForbidden(false, true); - pawn.jobs.TryTakeOrderedJob(new Job(DefDatabase.GetNamed("GatherSlotItem"), - loadableThing)); - MoteMaker.MakeStaticMote(loadableThing.DrawPos, loadableThing.Map, - ThingDefOf.Mote_FeedbackEquip, 1f); - //PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.EquippingWeapons, KnowledgeAmount.Total); - }, MenuOptionPriority.High, null, null, 0f, null, null); + damageAmount = 1f; + damageDef = DamageDefOf.Blunt; } - opts.Add(itemSlotLoadable); - } - } - } - } - } - public static void GetStatValue_PostFix(ref float __result, Thing thing, StatDef stat, bool applyPostProcess) - { - var retValue = 0.0f; - try - { - retValue = SlotLoadableUtility.CheckThingSlotsForStatAugment(thing, stat); - } - catch (Exception e) - { - Log.Warning("Failed to add stats for " + thing.Label + "\n" + e.ToString()); - } - __result += retValue; - } + damageAngle ??= (target.Thing.Position - casterPawn.Position).ToVector3(); + // TODO: armorPenetration should somehow be calculated via VerbProperties.AdjustedArmorPenetration. + var damageInfo = new DamageInfo(damageDef, damageAmount, slotBonusProps.armorPenetration, + -1f, casterPawn, weapon: equipmentSource.def); + damageInfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside); + damageInfo.SetWeaponBodyPartGroup(weaponBodyPartGroup); + damageInfo.SetWeaponHediff(weaponHediff); + damageInfo.SetAngle(damageAngle.Value); - public static void Get_Graphic_PostFix(Thing __instance, ref Graphic __result) - { - if (__instance is ThingWithComps thingWithComps) - { - //Log.Message("3"); - var CompSlotLoadable = thingWithComps.GetComp(); - if (CompSlotLoadable != null) - { - //ThingComp activatableEffect = thingWithComps.AllComps.FirstOrDefault((ThingComp y) => y.GetType().ToString() == "CompActivatableEffect.CompActivatableEffect"); - - var slot = CompSlotLoadable.ColorChangingSlot; - if (slot != null) - if (!slot.IsEmpty()) - { - var slotBonus = slot.SlotOccupant.TryGetComp(); - if (slotBonus != null) + if (newList == null) { - //if (activatableEffect != null) - //{ - // AccessTools.Field(activatableEffect.GetType(), "overrideColor").SetValue(activatableEffect, slot.SlotOccupant.DrawColor); - // Log.ErrorOnce("GraphicPostFix_Called_Activatable", 1866); - //} - //else - //{ - var tempGraphic = (Graphic) AccessTools.Field(typeof(Thing), "graphicInt") - .GetValue(__instance); - if (tempGraphic != null) - if (tempGraphic.Shader != null) - { - tempGraphic = tempGraphic.GetColoredVersion(tempGraphic.Shader, - slotBonus.Props.color, - slotBonus.Props.color); //slot.SlotOccupant.DrawColor; - __result = tempGraphic; - //Log.Message("SlotLoadableDraw"); - } + newList = new List(); + __result = newList; } - //Log.ErrorOnce("GraphicPostFix_Called_5", 1866); - //} + newList.Add(damageInfo); } - } - } - } - - public static void DrawColorPostFix(ThingWithComps __instance, ref Color __result) - { - if (__instance is ThingWithComps thingWithComps) - { - //Log.Message("3"); - var CompSlotLoadable = thingWithComps.GetComp(); - if (CompSlotLoadable != null) - { - var slot = CompSlotLoadable.ColorChangingSlot; - if (slot != null) - if (!slot.IsEmpty()) - { - __result = slot.SlotOccupant.DrawColor; - __instance.Graphic.color = slot.SlotOccupant.DrawColor; - } - } - } - } - -<<<<<<< Updated upstream - public static void DrawColorTwoPostFix(Thing __instance, ref Color __result) - { - if (__instance is ThingWithComps thingWithComps) - { - //Log.Message("3"); - var CompSlotLoadable = thingWithComps.GetComp(); - if (CompSlotLoadable != null) - { - var slot = CompSlotLoadable.SecondColorChangingSlot; - if (slot != null) - if (!slot.IsEmpty()) + var vampiricEffect = slotBonusProps.vampiricHealChance; + if (vampiricEffect != null) { - __result = slot.SlotOccupant.DrawColor; - __instance.Graphic.colorTwo = slot.SlotOccupant.DrawColor; + var randValue = Rand.Value; + //Log.Message("vampiricHealingCalled: randValue = " + randValue); + if (randValue <= vampiricEffect.chance) + { + MoteMaker.ThrowText(casterPawn.DrawPos, casterPawn.Map, "Vampiric Effect: Success", 6f); // TODO: Translate()? + damageAngle ??= (target.Thing.Position - casterPawn.Position).ToVector3(); + ApplyHealing(casterPawn, vampiricEffect.woundLimit, vampiricEffect.amountRange, target.Pawn, + vampiricEffect.damageDef, vampiricEffect.armorPenetration, damageAngle); + } } + } } } } - public static IEnumerable GizmoGetter(CompSlotLoadable CompSlotLoadable) - { - //Log.Message("5"); - if (CompSlotLoadable.GizmosOnEquip) - { - //Log.Message("6"); - //Iterate EquippedGizmos - var enumerator = CompSlotLoadable.EquippedGizmos().GetEnumerator(); - while (enumerator.MoveNext()) - { - //Log.Message("7"); - var current = enumerator.Current; - yield return current; - } - } - } - - public static void GetGizmos_PostFix(Pawn __instance, ref IEnumerable __result) - { - //Log.Message("1"); - var pawn_EquipmentTracker = __instance.equipment; - if (pawn_EquipmentTracker != null) - { - //Log.Message("2"); - var thingWithComps = - pawn_EquipmentTracker - .Primary; //(ThingWithComps)AccessTools.Field(typeof(Pawn_EquipmentTracker), "primaryInt").GetValue(pawn_EquipmentTracker); - - if (thingWithComps != null) - { - //Log.Message("3"); - var CompSlotLoadable = thingWithComps.GetComp(); - if (CompSlotLoadable != null) - if (GizmoGetter(CompSlotLoadable).Count() > 0) - if (__instance != null) - if (__instance.Faction == Faction.OfPlayer) - __result = __result.Concat(GizmoGetter(CompSlotLoadable)); -======= //ITab_Pawn_Gear.DrawThingRow public static void DrawThingRow_PostFix(ref float y, float width, Thing thing, bool inventory) { @@ -649,7 +269,6 @@ public static void ApplyHealing(Pawn pawn, int woundLimit, FloatRange amountRang // $"remaining max injuries to make {maxInjuriesToMake - 1}"); vampiricTarget.TakeDamage(dinfo); maxInjuriesToMake--; ->>>>>>> Stashed changes } } } @@ -660,4 +279,4 @@ public static void ApplyHealing(Pawn pawn, int woundLimit, FloatRange amountRang } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompToggleDef/CompProperties_ToggleDef.cs b/Source/AllModdingComponents/CompToggleDef/CompProperties_ToggleDef.cs index 79311387..67506660 100644 --- a/Source/AllModdingComponents/CompToggleDef/CompProperties_ToggleDef.cs +++ b/Source/AllModdingComponents/CompToggleDef/CompProperties_ToggleDef.cs @@ -1,14 +1,55 @@ +using System; +using System.Collections.Generic; using Verse; namespace CompToggleDef { public class CompProperties_ToggleDef : CompProperties { - public string labelKey; + public string toggleDefTag = "_TOGGLEDEF_"; + + private const string DefaultLabelKey = "TOGGLEDEF"; + + public string labelKey = DefaultLabelKey; // needs a default value to avoid NRE + + // Can change into these + [Unsaved] + public List toggleDefs; public CompProperties_ToggleDef() { compClass = typeof(CompToggleDef); } + + public override void ResolveReferences(ThingDef parentDef) + { + var parsed = parentDef.defName.Split(new[] { toggleDefTag }, StringSplitOptions.None); + if (parsed.Length == 2) + toggleDefs = FillToggleDefs(parsed[0], parsed[1]); + } + + public override IEnumerable ConfigErrors(ThingDef parentDef) + { + foreach (var error in base.ConfigErrors(parentDef)) + yield return error; + if (toggleDefs == null) + yield return $"unable to parse defName '{parentDef.defName}' - must have format '{toggleDefTag}'"; + if (labelKey == DefaultLabelKey && !Translator.CanTranslate(labelKey)) + yield return $"{nameof(labelKey)} has default value '{DefaultLabelKey}' which lacks a translation entry"; + } + + private List FillToggleDefs(string baseName, string toggleKey) + { + // go through all and find the ones that match + var toggleDefs = new List(); + var toggleBase = baseName + toggleDefTag; + foreach (var def in DefDatabase.AllDefsListForReading) + { + if (def.defName.StartsWith(toggleBase)) + toggleDefs.Add(def); + } + //Log.Message($"FillToggleDefs('{baseName}', '{toggleKey}') => " + toggleDefs.ToStringSafeEnumerable()); + return toggleDefs; + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompToggleDef/CompToggleDef.cs b/Source/AllModdingComponents/CompToggleDef/CompToggleDef.cs index 05b2319d..2b2084a2 100644 --- a/Source/AllModdingComponents/CompToggleDef/CompToggleDef.cs +++ b/Source/AllModdingComponents/CompToggleDef/CompToggleDef.cs @@ -1,82 +1,9 @@ -using System; -using System.Collections.Generic; -using Verse; +using Verse; namespace CompToggleDef { public class CompToggleDef : ThingComp { - protected string TDTag = "_TOGGLEDEF_"; - - // Can change into these - public List toggleDefs; - - public string LabelKey => ((CompProperties_ToggleDef) props).labelKey; - - public override void Initialize(CompProperties props) - { - base.Initialize(props); - string tdbase; - string tdkey; - - //Log.Message("CompToggleDef Initialize entered"); - if (toggleDefs == null) - if (parseToggleDef(out tdbase, out tdkey)) - fillToggleDefs(tdbase, tdkey); - else - Log.Warning("Failed to create toggleDefs"); - } - - public void fillToggleDefs(string tdbase, string tdkey) - { - // go through all and find the ones that match - //Log.Message("CompToggleDef.fillToggleDefs" + tdbase +" " + tdkey); - toggleDefs = new List(); - var allDefsListForReading = DefDatabase.AllDefsListForReading; - var tdbasematch = tdbase + TDTag; - for (var i = 0; i < allDefsListForReading.Count; i++) - { - var adef = allDefsListForReading[i]; - if (adef.defName.StartsWith(tdbasematch)) - toggleDefs.Add(adef); - } - } - - - // return true on success - public bool parseToggleDef(out string tdbase, out string tdkey) - { - string[] thematch = null; - var retval = false; - if (parent != null) - if (parent.def != null) - if (parent.def.defName != null) - { - thematch = parent.def.defName.Split(new[] {TDTag}, StringSplitOptions.None); - if (thematch.Length == 2) - retval = true; - else - Log.Warning("parsed defname of '" + parent.def.defName + "' failed to split on tag '" + - TDTag + "'."); - } - else - { - Log.Warning("Unable to parse defName because no this.parent.def.defName"); - } - else Log.Warning("Unable to parse defName because no this.parent.def"); - else Log.Warning("Unable to parse defName because no this.parent"); - - if (retval) - { - tdbase = thematch[0]; - tdkey = thematch[1]; - } - else - { - tdbase = null; - tdkey = null; - } - return retval; - } + public CompProperties_ToggleDef Props => (CompProperties_ToggleDef)props; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompToggleDef/CompToggleDef.csproj b/Source/AllModdingComponents/CompToggleDef/CompToggleDef.csproj index 2a361902..36fc720a 100755 --- a/Source/AllModdingComponents/CompToggleDef/CompToggleDef.csproj +++ b/Source/AllModdingComponents/CompToggleDef/CompToggleDef.csproj @@ -1,51 +1,7 @@  - - + + - Debug - AnyCPU - {9BECA870-0C2F-4F40-BEA1-6E99D68F9EDF} - Library - Properties - CompToggleDef CompToggleDef - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - \ No newline at end of file + diff --git a/Source/AllModdingComponents/CompToggleDef/ITab_ToggleDef.cs b/Source/AllModdingComponents/CompToggleDef/ITab_ToggleDef.cs index 6d3e419d..3fad1b68 100644 --- a/Source/AllModdingComponents/CompToggleDef/ITab_ToggleDef.cs +++ b/Source/AllModdingComponents/CompToggleDef/ITab_ToggleDef.cs @@ -1,46 +1,68 @@ +using System.Collections.Generic; using RimWorld; -using UnityEngine; using Verse; namespace CompToggleDef { public class ITab_ToggleDef : ITab { - public ITab_ToggleDef() + // Seperate class since ITab_ToggleDef is loaded (and thus static constructor runs) too early. + [StaticConstructorOnStartup] + private static class AddITabOnStartup { - size = ToggleDefCardUtility.CardSize + new Vector2(17f, 17f) * 2f; + static AddITabOnStartup() + { + foreach (var def in DefDatabase.AllDefsListForReading) + { + if (def.category == ThingCategory.Pawn && def.inspectorTabsResolved is List tabs) + { + var toggleDefTab = InspectTabManager.GetSharedInstance(typeof(ITab_ToggleDef)); + var gearTabIndex = tabs.FindIndex(tab => tab is ITab_Pawn_Gear); + if (gearTabIndex < 0) + tabs.Add(toggleDefTab); + else + tabs.Insert(gearTabIndex + 1, toggleDefTab); + } + } + } } public override bool IsVisible { get { -#pragma warning disable IDE0019 // Use pattern matching - var selected = SelThing as ThingWithComps; -#pragma warning restore IDE0019 // Use pattern matching - if (selected != null) - { - var td = selected.GetComp(); - if (td != null) - { - //Log.Message("ITab_isvisible"); - labelKey = td.LabelKey; // defined by the Comp - return true; - } - } - return false; + var compToggleDef = ToggleDefCardUtility.GetCompToggleDef(SelThing); + if (compToggleDef == null) + return false; + // InspectPaneUtility calls IsVisible before drawing the tab text (labelKey.Translate()), + // so this is a convenient hook to set labelKey. + labelKey = compToggleDef.Props.labelKey; + return true; + } + } + + protected override void UpdateSize() + { + base.UpdateSize(); + var compToggleDef = ToggleDefCardUtility.GetCompToggleDef(SelThing); + if (compToggleDef == null) + { + Log.Warning("selected thing has no CompToggleDef for ITab_ToggleDef"); + return; } + size = ToggleDefCardUtility.CardSize(compToggleDef); } protected override void FillTab() { - var selected = Find.Selector.SingleSelectedThing as ThingWithComps; - var td = selected.GetComp(); - if (td == null) Log.Warning("selected thing has no CompToggleDef for ITab_ToggleDef"); - labelKey = ((CompProperties_ToggleDef) td.props).labelKey; //"UM_TabToggleDef";//.Translate(); - if (labelKey == null) labelKey = "TOGGLEDEF"; - var rect = new Rect(17f, 17f, ToggleDefCardUtility.CardSize.x, ToggleDefCardUtility.CardSize.y); - ToggleDefCardUtility.DrawCard(rect, selected); + var compToggleDef = ToggleDefCardUtility.GetCompToggleDef(SelThing); + if (compToggleDef == null) + { + Log.Warning("selected thing has no CompToggleDef for ITab_ToggleDef"); + return; + } + labelKey = compToggleDef.Props.labelKey; + ToggleDefCardUtility.DrawCard(size, compToggleDef); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompToggleDef/ToggleDefCardUtility.cs b/Source/AllModdingComponents/CompToggleDef/ToggleDefCardUtility.cs index 9781e65a..78626149 100644 --- a/Source/AllModdingComponents/CompToggleDef/ToggleDefCardUtility.cs +++ b/Source/AllModdingComponents/CompToggleDef/ToggleDefCardUtility.cs @@ -1,89 +1,155 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; +using RimWorld; using UnityEngine; using Verse; namespace CompToggleDef { - public class ToggleDefCardUtility + public static class ToggleDefCardUtility { - // RimWorld.CharacterCardUtility - public static Vector2 CardSize = new Vector2(395f, 536f); - - public static float ButtonSize = 40f; - - public static float ForceButtonSize = 46f; - - public static float ForceButtonPointSize = 24f; - - public static float HeaderSize = 32f; - - public static float TextSize = 22f; - - public static float Padding = 3f; - - public static float SpacingOffset = 15f; - - public static float SectionOffset = 8f; + private const int MaxRows = 10; + private const float CardPadding = GenUI.GapSmall; + private const float ExtraTopPadding = 20f; + private const float RowHeight = Widgets.RadioButtonSize; + private const float RowGap = GenUI.GapSmall; + private const float DefIconMargin = 2f; + private const float DefIconSize = RowHeight - DefIconMargin * 2; + private const float DefLabelOffsetX = 6f; + + public static CompToggleDef GetCompToggleDef(Thing thing) + { + // TODO: Support all the equipment/apparel/carried things on a Pawn somehow? + // Would require showing multiple CompToggleDefs and some way to switch between them in the GUI. + if (thing is Pawn pawn && pawn.IsColonistPlayerControlled) + thing = pawn.equipment?.Primary; + var compToggleDef = thing.TryGetCompToggleDef(); + if (compToggleDef == null) + return null; + var toggleDefs = compToggleDef.Props.toggleDefs; + if (toggleDefs == null || toggleDefs.Count <= 1) + return null; + return compToggleDef; + } - public static float ColumnSize = 245f; + public static Vector2 CardSize(CompToggleDef compToggleDef) + { + var width = InspectPaneUtility.PaneWidthFor((MainTabWindow_Inspect)MainButtonDefOf.Inspect.TabWindow); + var rowCount = Math.Min(compToggleDef.Props.toggleDefs.Count, MaxRows); + return new Vector2(width, TotalRowHeight(rowCount) + CardPadding * 2 + ExtraTopPadding); + } - public static float SkillsColumnHeight = 113f; + private static float TotalRowHeight(int rowCount) => rowCount * (RowHeight + RowGap) - RowGap; - public static float SkillsColumnDivider = 114f; + private static ThingWithComps lastSelectedThing; + private static Vector2 scrollPosition = Vector2.zero; - public static float SkillsTextWidth = 138f; + public static void DrawCard(Vector2 size, CompToggleDef compToggleDef) + { + var selectedThing = compToggleDef.parent; + var toggleDefs = compToggleDef.Props.toggleDefs; - public static float SkillsBoxSize = 18f; + var rect = new Rect(0f, ExtraTopPadding, size.x, size.y - ExtraTopPadding).ContractedBy(CardPadding); - public static float PowersColumnHeight = 195f; + var rowCount = toggleDefs.Count; + var yMin = -RowHeight; + var yMax = rect.height; + if (rowCount > MaxRows) + { + if (lastSelectedThing != selectedThing) + { + lastSelectedThing = selectedThing; + scrollPosition.y = toggleDefs.IndexOf(selectedThing.def) * (RowHeight + RowGap); + } + var viewRect = new Rect(0f, 0f, rect.width - GenUI.ScrollBarWidth - CardPadding, TotalRowHeight(rowCount)); + Widgets.BeginScrollView(rect, ref scrollPosition, viewRect); + rect.width = viewRect.width; + yMin += scrollPosition.y; + yMax += scrollPosition.y; + } + else + { + GUI.BeginGroup(rect); + } - public static float PowersColumnWidth = 123f; + // Add the rows for each toggle def. + var y = 0f; + foreach (var toggleDef in toggleDefs) + { + if (y > yMax) + break; + if (y >= yMin) + { + var rowRect = new Rect(0f, y, rect.width, RowHeight); + var iconAndLabelRect = rowRect.LeftPartPixels(rowRect.width - (Widgets.RadioButtonSize + DefLabelOffsetX)); + Widgets.DefLabelWithIcon(iconAndLabelRect, toggleDef, DefIconMargin, DefLabelOffsetX); + var iconRect = new Rect(DefIconMargin, y + DefIconMargin, DefIconSize, DefIconSize); + if (Widgets.ButtonInvisible(iconRect)) + Find.WindowStack.Add(new Dialog_InfoCard(toggleDef)); + var isSelected = selectedThing.def == toggleDef; + RadioButtonDraw(rowRect.width - Widgets.RadioButtonSize, y, isSelected); + if (!isSelected && Widgets.ButtonInvisible(rowRect.RightPartPixels(rowRect.width - iconRect.xMax - DefLabelOffsetX))) + { + SwapThing(selectedThing, toggleDef); + break; + } + } + y += RowHeight + RowGap; + } - public static bool isfirst = true; + if (rowCount > MaxRows) + Widgets.EndScrollView(); + else + GUI.EndGroup(); + } - // RimWorld.CharacterCardUtility - public static void DrawCard(Rect rect, ThingWithComps selectedThing) + private static void SwapThing(ThingWithComps thing, ThingDef newDef) { - GUI.BeginGroup(rect); + var map = thing.Map; + var loc = thing.Position; + var rot = thing.Rotation; - var compToggleDef = selectedThing.GetComp(); + var eqTracker = thing.ParentHolder as Pawn_EquipmentTracker; + if (eqTracker != null) + eqTracker.Remove(thing); + else + thing.DeSpawn(); - if (compToggleDef != null) + thing.def = newDef; + + // Refresh verbs. + foreach (var comp in thing.AllComps) { - var ts = Text.CalcSize(selectedThing.LabelCap).x; - var y = rect.y; - var rect2 = new Rect(rect.width / 2 - ts + SpacingOffset, y, rect.width, HeaderSize); - y += rect2.height; - Text.Font = GameFont.Medium; - Widgets.Label(rect2, selectedThing.LabelCap); - Text.Font = GameFont.Small; - Widgets.ListSeparator(ref y, rect2.width, "Select one of the following:"); - - // add all the buttons for the toggle defs - foreach (var td in compToggleDef.toggleDefs) + if (comp is IVerbOwner verbOwner && verbOwner.VerbTracker is VerbTracker verbTracker) { - var rect3 = new Rect(0f, y, rect.width, 20f); - var isactive = false; - if (selectedThing.def == td) isactive = true; - if (Widgets.RadioButtonLabeled(rect3, td.LabelCap, isactive)) - { - //Log.Message(".. change location to "+td.LabelCap); - - // CHange def then give it a new id. Hopefully nothing index on the id - var map = selectedThing.Map; - var loc = selectedThing.Position; - var rot = selectedThing.Rotation; - selectedThing.DeSpawn(); - selectedThing.def = td; - selectedThing.thingIDNumber = -1; - ThingIDMaker.GiveIDTo(selectedThing); // necessary - GenSpawn.Spawn(selectedThing, loc, map, rot); - break; - } - y += 25f; + VerbsNeedReinitOnLoad(verbTracker); + _ = verbTracker.AllVerbs; } } - GUI.EndGroup(); + // Refresh graphics. + thing.Notify_ColorChanged(); + + if (eqTracker != null) + eqTracker.AddEquipment(thing); + else if (GenSpawn.Spawn(thing, loc, map, rot) != null) + Find.Selector.Select(thing, playSound: false); + } + + private static readonly Action RadioButtonDraw = + (Action)AccessTools.Method(typeof(Widgets), "RadioButtonDraw") + .CreateDelegate(typeof(Action)); + private static readonly Action VerbsNeedReinitOnLoad = InitVerbsNeedReinitOnLoad(); + + private static Action InitVerbsNeedReinitOnLoad() + { + // VerbTracker.VerbsNeedReinitOnLoad is only available in RW 1.2+ + var method = AccessTools.Method(typeof(VerbTracker), "VerbsNeedReinitOnLoad"); + if (method != null) + return (Action)method.CreateDelegate(typeof(Action)); + var verbsRef = AccessTools.FieldRefAccess>("verbs"); + return verbTracker => verbsRef(verbTracker) = null; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/CompToggleDef/ToggleDefUtility.cs b/Source/AllModdingComponents/CompToggleDef/ToggleDefUtility.cs new file mode 100644 index 00000000..037d7b13 --- /dev/null +++ b/Source/AllModdingComponents/CompToggleDef/ToggleDefUtility.cs @@ -0,0 +1,26 @@ +using Verse; + +namespace CompToggleDef +{ + public static class ToggleDefUtility + { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static CompToggleDef GetCompToggleDef(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompToggleDef comp) + return comp; + } + return null; + } + + public static CompToggleDef TryGetCompToggleDef(this Thing thing) + { + return thing is ThingWithComps thingWithComps ? thingWithComps.GetCompToggleDef() : null; + } + } +} diff --git a/Source/AllModdingComponents/JecsTools/ApparelExtension.cs b/Source/AllModdingComponents/JecsTools/ApparelExtension.cs index 13fe1087..7762ecd4 100644 --- a/Source/AllModdingComponents/JecsTools/ApparelExtension.cs +++ b/Source/AllModdingComponents/JecsTools/ApparelExtension.cs @@ -1,17 +1,47 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Verse; -using Verse.AI; namespace JecsTools { + [Obsolete("Use vanilla apparel.gender field in RimWorld 1.1+")] public class SwapCondition { public Gender swapWhenGender = Gender.None; public ThingDef swapTo = null; } + + [Obsolete("Use vanilla apparel.gender and apparel.layers fields and custom ApparelLayerDef")] public class ApparelExtension : DefModExtension { - public List coverage = new List(); + [Obsolete("Use vanilla apparel.layers field and custom ApparelLayerDef in RimWorld b19+")] + private List coverage; // set via reflection + + [Unsaved] + private HashSet coverageSet; + + public HashSet Coverage + { + get + { + // DefModExtension lacks a ResolveReferences hook, so must use lazy initialization in property instead. + if (coverageSet == null && coverage != null) + { + coverageSet = new HashSet(coverage.Count); + foreach (var item in coverage) + coverageSet.Add(item.ToLowerInvariant()); + } + return coverageSet; + } + } + + [Obsolete("Use vanilla apparel.gender field in RimWorld 1.1+")] public SwapCondition swapCondition = new SwapCondition(); + + public override IEnumerable ConfigErrors() + { + if (coverage != null && Coverage.Count != coverage.Count) + yield return nameof(coverage) + " has duplicate items: " + coverage.ToStringSafeEnumerable(); + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/Backstories/BackstoryDef.cs b/Source/AllModdingComponents/JecsTools/Backstories/BackstoryDef.cs index aea78b13..af749a1d 100644 --- a/Source/AllModdingComponents/JecsTools/Backstories/BackstoryDef.cs +++ b/Source/AllModdingComponents/JecsTools/Backstories/BackstoryDef.cs @@ -1,14 +1,12 @@ -using RimWorld; -using System; +using System; using System.Collections.Generic; using System.Linq; -using Verse; using HarmonyLib; +using RimWorld; +using Verse; namespace JecsTools { - - //Pulled from erdelf's Alien Races 2.0 //Original credit and work belong to erdelf (https://github.com/erdelf) //Link -> https://github.com/RimWorld-CCL-Reborn/AlienRaces/blob/94bf6b6d7a91e9587bdc40e8a231b18515cb6bb7/Source/AlienRace/AlienRace/BackstoryDef.cs @@ -28,87 +26,6 @@ public class BackstoryDef : RimWorld.BackstoryDef public IntRange bioAgeRange; public IntRange chronoAgeRange; public List forcedItems = new List(); -<<<<<<< Updated upstream - public Backstory backstory; - - public class ChancedTraitEntry - { - public string defName; - public int degree = 0; - public float chance = 100; - public float commonalityMale = -1f; - public float commonalityFemale = -1f; - } - - public bool CommonalityApproved(Gender g) => Rand.Range(min: 0, max: 100) < (g == Gender.Female ? this.femaleCommonality : this.maleCommonality); - - public bool Approved(Pawn p) => this.CommonalityApproved(g: p.gender) && - (this.bioAgeRange == default(IntRange) || (this.bioAgeRange.min < p.ageTracker.AgeBiologicalYears && p.ageTracker.AgeBiologicalYears < this.bioAgeRange.max)) && - (this.chronoAgeRange == default(IntRange) || (this.chronoAgeRange.min < p.ageTracker.AgeChronologicalYears && p.ageTracker.AgeChronologicalYears < this.chronoAgeRange.max)); - - public override void ResolveReferences() - { - - base.ResolveReferences(); - - - if (!this.addToDatabase || BackstoryDatabase.allBackstories.ContainsKey(key: this.defName) || this.title.NullOrEmpty() || this.spawnCategories.NullOrEmpty()) return; - - this.backstory = new Backstory - { - slot = this.slot, - shuffleable = this.shuffleable, - spawnCategories = this.spawnCategories, - forcedTraits = this.forcedTraits.NullOrEmpty() ? null : this.forcedTraits.Where(predicate: trait => Rand.Range(min: 0, max: 100) < trait.chance).ToList().ConvertAll(converter: trait => new TraitEntry(def: TraitDef.Named(defName: trait.defName), degree: trait.degree)), - disallowedTraits = this.disallowedTraits.NullOrEmpty() ? null : this.disallowedTraits.Where(predicate: trait => Rand.Range(min: 0, max: 100) < trait.chance).ToList().ConvertAll(converter: trait => new TraitEntry(def: TraitDef.Named(defName: trait.defName), degree: trait.degree)), - workDisables = this.workAllows.NullOrEmpty() ? this.workDisables.NullOrEmpty() ? WorkTags.None : ((Func)delegate - { - WorkTags wt = WorkTags.None; - this.workDisables.ForEach(action: tag => wt |= tag); - return wt; - })() : ((Func)delegate - { - WorkTags wt = WorkTags.None; - Enum.GetValues(enumType: typeof(WorkTags)).Cast().Where(predicate: tag => !this.workAllows.Contains(item: tag)).ToList().ForEach(action: tag => wt |= tag); - return wt; - })(), - identifier = this.defName, - requiredWorkTags = ((Func)delegate - { - WorkTags wt = WorkTags.None; - this.requiredWorkTags.ForEach(action: tag => wt |= tag); - return wt; - })() - }; - - Traverse.Create(root: this.backstory).Field(name: "bodyTypeGlobalResolved").SetValue(value: this.bodyTypeGlobal); - Traverse.Create(root: this.backstory).Field(name: "bodyTypeFemaleResolved").SetValue(value: this.bodyTypeFemale); - Traverse.Create(root: this.backstory).Field(name: "bodyTypeMaleResolved").SetValue(value: this.bodyTypeMale); - Traverse.Create(root: this.backstory).Field(name: nameof(this.skillGains)).SetValue(value: this.skillGains.ToDictionary(keySelector: i => i.defName, elementSelector: i => i.amount)); - - UpdateTranslateableFields(bs: this); - - this.backstory.ResolveReferences(); - this.backstory.PostLoad(); - - this.backstory.identifier = this.defName; - - IEnumerable errors; - if (!(errors = this.backstory.ConfigErrors(ignoreNoSpawnCategories: false)).Any()) - BackstoryDatabase.AddBackstory(bs: this.backstory); - else - Log.Error(text: this.defName + " has errors:\n" + string.Join(separator: "\n", value: errors.ToArray())); - } - - internal static void UpdateTranslateableFields(BackstoryDef bs) - { - if (bs.backstory == null) return; - - bs.backstory.baseDesc = bs.baseDescription.NullOrEmpty() ? "Empty." : bs.baseDescription; - bs.backstory.SetTitle(newTitle: bs.title, newTitleFemale: bs.titleFemale); - bs.backstory.SetTitleShort(newTitleShort: bs.titleShort.NullOrEmpty() ? bs.backstory.title : bs.titleShort, - newTitleShortFemale: bs.titleShortFemale.NullOrEmpty() ? bs.backstory.titleFemale : bs.titleShortFemale); -======= public bool CommonalityApproved(Gender g) => Rand.Range(min: 0, max: 100) < (g == Gender.Female ? this.femaleCommonality : this.maleCommonality); @@ -142,11 +59,8 @@ public class ChancedTraitEntry public float chance = 100; public float commonalityMale = -1f; public float commonalityFemale = -1f; ->>>>>>> Stashed changes } - - public struct BackstoryDefSkillListItem { #pragma warning disable CS0649 @@ -184,4 +98,4 @@ public struct BackstoryDefSkillListItem //public List forcedItems = new List(); //public Backstory backstory; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/BuildingExtension.cs b/Source/AllModdingComponents/JecsTools/BuildingExtension.cs index d2120dcf..671d36b2 100644 --- a/Source/AllModdingComponents/JecsTools/BuildingExtension.cs +++ b/Source/AllModdingComponents/JecsTools/BuildingExtension.cs @@ -1,12 +1,34 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Verse; -using Verse.AI; namespace JecsTools { - public class BuildingExtension : DefModExtension { - public List wipeCategories = new List(); + private List wipeCategories; // set via reflection + + [Unsaved] + private HashSet wipeCategorySet; + + public HashSet WipeCategories + { + get + { + // DefModExtension lacks a ResolveReferences hook, so must use lazy initialization in property instead. + if (wipeCategorySet == null && wipeCategories != null) + { + wipeCategorySet = new HashSet(wipeCategories.Count); + foreach (var category in wipeCategories) + wipeCategorySet.Add(category.ToLowerInvariant()); + } + return wipeCategorySet; + } + } + + public override IEnumerable ConfigErrors() + { + if (wipeCategories != null && WipeCategories.Count != wipeCategories.Count) + yield return nameof(wipeCategories) + " has duplicate categories: " + wipeCategories.ToStringSafeEnumerable(); + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJob.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJob.cs index fa79eaf3..34099c4e 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJob.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJob.cs @@ -8,6 +8,7 @@ namespace JecsTools { + // Based off Job. public class CaravanJob : IExposable { public bool attackDoorIfTargetLost; @@ -53,13 +54,13 @@ public class CaravanJob : IExposable public Lord lord; - public int maxNumMeleeAttacks = 2147483647; + public int maxNumMeleeAttacks = int.MaxValue; - public int maxNumStaticAttacks = 2147483647; + public int maxNumStaticAttacks = int.MaxValue; public bool overeat; - public List placedThings; + public List placedThings; public ThingDef plantDefToSow; @@ -87,11 +88,11 @@ public CaravanJob() { } - public CaravanJob(CaravanJobDef def) : this(def, default(GlobalTargetInfo)) + public CaravanJob(CaravanJobDef def) : this(def, default) { } - public CaravanJob(CaravanJobDef def, GlobalTargetInfo targetA) : this(def, targetA, default(GlobalTargetInfo)) + public CaravanJob(CaravanJobDef def, GlobalTargetInfo targetA) : this(def, targetA, default) { } @@ -131,73 +132,67 @@ public CaravanJob(CaravanJobDef def, int expiryInterval, bool checkOverrideOnExp public void ExposeData() { - var loadReferenceable = (ILoadReferenceable) commTarget; - Scribe_References.Look(ref loadReferenceable, "commTarget", false); - commTarget = (ICommunicable) loadReferenceable; - Scribe_References.Look(ref verbToUse, "verbToUse", false); - Scribe_References.Look(ref bill, "bill", false); - Scribe_References.Look(ref lord, "lord", false); - Scribe_Defs.Look(ref def, "def"); - Scribe_TargetInfo.Look(ref targetA, "targetA"); - Scribe_TargetInfo.Look(ref targetB, "targetB"); - Scribe_TargetInfo.Look(ref targetC, "targetC"); - Scribe_Collections.Look(ref targetQueueA, "targetQueueA", LookMode.Undefined); - Scribe_Collections.Look(ref targetQueueB, "targetQueueB", LookMode.Undefined); - Scribe_Values.Look(ref count, "count", -1, false); - Scribe_Collections.Look(ref countQueue, "countQueue", LookMode.Undefined); - Scribe_Values.Look(ref startTick, "startTick", -1, false); - Scribe_Values.Look(ref expiryInterval, "expiryInterval", -1, false); - Scribe_Values.Look(ref checkOverrideOnExpire, "checkOverrideOnExpire", false, false); - Scribe_Values.Look(ref playerForced, "playerForced", false, false); - Scribe_Collections.Look(ref placedThings, "placedThings", LookMode.Undefined); - Scribe_Values.Look(ref maxNumMeleeAttacks, "maxNumMeleeAttacks", 2147483647, false); - Scribe_Values.Look(ref maxNumStaticAttacks, "maxNumStaticAttacks", 2147483647, false); - Scribe_Values.Look(ref exitMapOnArrival, "exitMapOnArrival", false, false); - Scribe_Values.Look(ref failIfCantJoinOrCreateCaravan, "failIfCantJoinOrCreateCaravan", false, false); - Scribe_Values.Look(ref killIncappedTarget, "killIncappedTarget", false, false); - Scribe_Values.Look(ref haulOpportunisticDuplicates, "haulOpportunisticDuplicates", false, false); - Scribe_Values.Look(ref haulMode, "haulMode", HaulMode.Undefined, false); - Scribe_Defs.Look(ref plantDefToSow, "plantDefToSow"); - Scribe_Values.Look(ref locomotionUrgency, "locomotionUrgency", LocomotionUrgency.Jog, false); - Scribe_Values.Look(ref ignoreDesignations, "ignoreDesignations", false, false); - Scribe_Values.Look(ref canBash, "canBash", false, false); - Scribe_Values.Look(ref haulDroppedApparel, "haulDroppedApparel", false, false); - Scribe_Values.Look(ref restUntilHealed, "restUntilHealed", false, false); - Scribe_Values.Look(ref ignoreJoyTimeAssignment, "ignoreJoyTimeAssignment", false, false); - Scribe_Values.Look(ref overeat, "overeat", false, false); - Scribe_Values.Look(ref attackDoorIfTargetLost, "attackDoorIfTargetLost", false, false); - Scribe_Values.Look(ref takeExtraIngestibles, "takeExtraIngestibles", 0, false); - Scribe_Values.Look(ref expireRequiresEnemiesNearby, "expireRequiresEnemiesNearby", false, false); - Scribe_Values.Look(ref collideWithCaravans, "collideWithCaravans", false, false); + var loadReferenceable = (ILoadReferenceable)commTarget; + Scribe_References.Look(ref loadReferenceable, nameof(commTarget)); + commTarget = (ICommunicable)loadReferenceable; + Scribe_References.Look(ref verbToUse, nameof(verbToUse)); + Scribe_References.Look(ref bill, nameof(bill)); + Scribe_References.Look(ref lord, nameof(lord)); + Scribe_Defs.Look(ref def, nameof(def)); + Scribe_TargetInfo.Look(ref targetA, nameof(targetA)); + Scribe_TargetInfo.Look(ref targetB, nameof(targetB)); + Scribe_TargetInfo.Look(ref targetC, nameof(targetC)); + Scribe_Collections.Look(ref targetQueueA, nameof(targetQueueA), LookMode.GlobalTargetInfo); + Scribe_Collections.Look(ref targetQueueB, nameof(targetQueueB), LookMode.GlobalTargetInfo); + Scribe_Values.Look(ref count, nameof(count), -1); + Scribe_Collections.Look(ref countQueue, nameof(countQueue), LookMode.Value); + Scribe_Values.Look(ref startTick, nameof(startTick), -1); + Scribe_Values.Look(ref expiryInterval, nameof(expiryInterval), -1); + Scribe_Values.Look(ref checkOverrideOnExpire, nameof(checkOverrideOnExpire)); + Scribe_Values.Look(ref playerForced, nameof(playerForced)); + Scribe_Collections.Look(ref placedThings, nameof(placedThings), LookMode.Deep); + Scribe_Values.Look(ref maxNumMeleeAttacks, nameof(maxNumMeleeAttacks), int.MaxValue); + Scribe_Values.Look(ref maxNumStaticAttacks, nameof(maxNumStaticAttacks), int.MaxValue); + Scribe_Values.Look(ref exitMapOnArrival, nameof(exitMapOnArrival)); + Scribe_Values.Look(ref failIfCantJoinOrCreateCaravan, nameof(failIfCantJoinOrCreateCaravan)); + Scribe_Values.Look(ref killIncappedTarget, nameof(killIncappedTarget)); + Scribe_Values.Look(ref haulOpportunisticDuplicates, nameof(haulOpportunisticDuplicates)); + Scribe_Values.Look(ref haulMode, nameof(haulMode)); + Scribe_Defs.Look(ref plantDefToSow, nameof(plantDefToSow)); + Scribe_Values.Look(ref locomotionUrgency, nameof(locomotionUrgency), LocomotionUrgency.Jog); + Scribe_Values.Look(ref ignoreDesignations, nameof(ignoreDesignations)); + Scribe_Values.Look(ref canBash, nameof(canBash)); + Scribe_Values.Look(ref haulDroppedApparel, nameof(haulDroppedApparel)); + Scribe_Values.Look(ref restUntilHealed, nameof(restUntilHealed)); + Scribe_Values.Look(ref ignoreJoyTimeAssignment, nameof(ignoreJoyTimeAssignment)); + Scribe_Values.Look(ref overeat, nameof(overeat)); + Scribe_Values.Look(ref attackDoorIfTargetLost, nameof(attackDoorIfTargetLost)); + Scribe_Values.Look(ref takeExtraIngestibles, nameof(takeExtraIngestibles)); + Scribe_Values.Look(ref expireRequiresEnemiesNearby, nameof(expireRequiresEnemiesNearby)); + Scribe_Values.Look(ref collideWithCaravans, nameof(collideWithCaravans)); } public GlobalTargetInfo GetTarget(TargetIndex ind) { - switch (ind) + return ind switch { - case TargetIndex.A: - return targetA; - case TargetIndex.B: - return targetB; - case TargetIndex.C: - return targetC; - default: - throw new ArgumentException(); - } + TargetIndex.A => targetA, + TargetIndex.B => targetB, + TargetIndex.C => targetC, + _ => throw new ArgumentException(), + }; } public List GetTargetQueue(TargetIndex ind) { if (ind == TargetIndex.A) { - if (targetQueueA == null) - targetQueueA = new List(); + targetQueueA ??= new List(); return targetQueueA; } if (ind != TargetIndex.B) throw new ArgumentException(); - if (targetQueueB == null) - targetQueueB = new List(); + targetQueueB ??= new List(); return targetQueueB; } @@ -226,9 +221,9 @@ public void AddQueuedTarget(TargetIndex ind, GlobalTargetInfo target) public CaravanJobDriver MakeDriver(Caravan driverCaravan) { - var jobDriver = (CaravanJobDriver) Activator.CreateInstance(def.driverClass); + var jobDriver = (CaravanJobDriver)Activator.CreateInstance(def.driverClass); jobDriver.caravan = driverCaravan; - Log.Message("JecsTools :: MakeDriver Called :: " + def.driverClass); + //Log.Message("JecsTools :: MakeDriver Called :: " + def.driverClass); return jobDriver; } @@ -255,12 +250,12 @@ public override string ToString() { var text = def.ToString(); if (targetA.IsValid) - text = text + " A=" + targetA; + text += " A=" + targetA; if (targetB.IsValid) - text = text + " B=" + targetB; + text += " B=" + targetB; if (targetC.IsValid) - text = text + " C=" + targetC; + text += " C=" + targetC; return text; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobDef.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobDef.cs index 7daf5d32..d28ec54e 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobDef.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobDef.cs @@ -31,8 +31,8 @@ public class CaravanJobDef : Def public bool playerInterruptible = true; - [MustTranslate] public string reportString = "Doing something."; - + [MustTranslate] + public string reportString = "Doing something."; //public bool alwaysShowWeapon; @@ -50,10 +50,10 @@ public static CaravanJobDef Named(string defName) [DebuggerHidden] public override IEnumerable ConfigErrors() { - foreach (var e in base.ConfigErrors()) - yield return e; + foreach (var error in base.ConfigErrors()) + yield return error; if (joySkill != null && joyXpPerTick == 0f) - yield return "funSkill is not null but funXpPerTick is zero"; + yield return $"{nameof(joySkill)} is not null, but {nameof(joyXpPerTick)} is zero"; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobDriver.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobDriver.cs index 25ee6b5a..8efc65f6 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobDriver.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobDriver.cs @@ -14,7 +14,8 @@ public enum LayingDownState LayingSurface, LayingInBed } - + + // Based off JobDriver. public abstract class CaravanJobDriver : ICaravanJobEndable, IExposable { public bool asleep; @@ -54,8 +55,7 @@ public CaravanToil CurToil return null; if (curToilIndex >= toils.Count) { - Log.Error(string.Concat(caravan, " with job ", CurJob, " tried to get CurToil with curToilIndex=", - curToilIndex, " but only has ", toils.Count, " toils.")); + Log.Error($"{caravan} with job {CurJob} tried to get CurToil with curToilIndex={curToilIndex} but only has {toils.Count} toils."); return null; } return toils[curToilIndex]; @@ -64,14 +64,14 @@ public CaravanToil CurToil public bool HaveCurToil => curToilIndex >= 0 && curToilIndex < toils.Count; - private bool CanStartNextToilInBusyStance - { - get - { - var num = curToilIndex + 1; - return num < toils.Count && toils[num].atomicWithPrevious; - } - } + //private bool CanStartNextToilInBusyStance + //{ + // get + // { + // var num = curToilIndex + 1; + // return num < toils.Count && toils[num].atomicWithPrevious; + // } + //} public virtual PawnPosture Posture => layingDown == LayingDownState.NotLaying ? PawnPosture.Standing : PawnPosture.LayingOnGroundNormal; @@ -80,7 +80,7 @@ private bool CanStartNextToilInBusyStance public bool HandlingFacing => CurToil != null && CurToil.handlingFacing; - public CaravanJob CurJob => Find.World.GetComponent().CurJob(caravan); + public CaravanJob CurJob => CaravanJobsUtility.GetCaravanJobGiver().CurJob(caravan); public GlobalTargetInfo TargetA => CurJob.targetA; @@ -122,28 +122,22 @@ public void AddEndCondition(Func newEndCondition) public virtual void ExposeData() { - Scribe_References.Look(ref caravan, "caravan"); - Scribe_Values.Look(ref ended, "ended", false, false); - Scribe_Values.Look(ref curToilIndex, "curToilIndex", 0, true); - Scribe_Values.Look(ref ticksLeftThisToil, "ticksLeftThisToil", 0, false); - Scribe_Values.Look(ref wantBeginNextToil, "wantBeginNextToil", false, false); - Scribe_Values.Look(ref curToilCompleteMode, "curToilCompleteMode", ToilCompleteMode.Undefined, false); - Scribe_Values.Look(ref startTick, "startTick", 0, false); - Scribe_Values.Look(ref rotateToFace, "rotateToFace", TargetIndex.A, false); - Scribe_Values.Look(ref layingDown, "layingDown", LayingDownState.NotLaying, false); - Scribe_Values.Look(ref asleep, "asleep", false, false); - Scribe_Values.Look(ref uninstallWorkLeft, "uninstallWorkLeft", 0f, false); + Scribe_References.Look(ref caravan, nameof(caravan)); + Scribe_Values.Look(ref ended, nameof(ended)); + Scribe_Values.Look(ref curToilIndex, nameof(curToilIndex), forceSave: true); + Scribe_Values.Look(ref ticksLeftThisToil, nameof(ticksLeftThisToil)); + Scribe_Values.Look(ref wantBeginNextToil, nameof(wantBeginNextToil)); + Scribe_Values.Look(ref curToilCompleteMode, nameof(curToilCompleteMode)); + Scribe_Values.Look(ref startTick, nameof(startTick)); + Scribe_Values.Look(ref rotateToFace, nameof(rotateToFace), TargetIndex.A); + Scribe_Values.Look(ref layingDown, nameof(layingDown)); + Scribe_Values.Look(ref asleep, nameof(asleep)); + Scribe_Values.Look(ref uninstallWorkLeft, nameof(uninstallWorkLeft)); if (Scribe.mode == LoadSaveMode.PostLoadInit) SetupToils(); } - //public Map Map - //{ - // get - // { - // return this.caravan.Map; - // } - //} + //public Map Map => caravan.Map; public virtual string GetReport() { @@ -153,18 +147,9 @@ public virtual string GetReport() public string ReportStringProcessed(string str) { var curJob = CurJob; - if (curJob.targetA.HasThing) - str = str.Replace("TargetA", curJob.targetA.Thing.LabelShort); - else - str = str.Replace("TargetA", "AreaLower".Translate()); - if (curJob.targetB.HasThing) - str = str.Replace("TargetB", curJob.targetB.Thing.LabelShort); - else - str = str.Replace("TargetB", "AreaLower".Translate()); - if (curJob.targetC.HasThing) - str = str.Replace("TargetC", curJob.targetC.Thing.LabelShort); - else - str = str.Replace("TargetC", "AreaLower".Translate()); + str = str.Replace("TargetA", curJob.targetA.HasThing ? curJob.targetA.Thing.LabelShort : (string)"AreaLower".Translate()); + str = str.Replace("TargetB", curJob.targetB.HasThing ? curJob.targetB.Thing.LabelShort : (string)"AreaLower".Translate()); + str = str.Replace("TargetC", curJob.targetC.HasThing ? curJob.targetC.Thing.LabelShort : (string)"AreaLower".Translate()); return str; } @@ -179,9 +164,7 @@ public void Cleanup(JobCondition condition) } catch (Exception ex) { - Log.Error(string.Concat("Pawn ", caravan, - " threw exception while executing a global finish action (", i, "), jobDriver=", GetType(), - ": ", ex)); + Log.Error($"Pawn {caravan} threw exception while executing a global finish action ({i}), jobDriver={GetType()}: {ex}"); } if (HaveCurToil) CurToil.Cleanup(); @@ -205,8 +188,8 @@ internal void SetupToils() } catch (Exception ex) { - Find.World.GetComponent().Tracker(caravan).StartErrorRecoverJob( - string.Concat("Exception in SetupToils (pawn=", caravan, ", job=", CurJob, "): ", ex)); + CaravanJobsUtility.GetCaravanJobGiver().Tracker(caravan).StartErrorRecoverJob( + $"Exception in SetupToils (pawn={caravan}, job={CurJob}): {ex}"); } } @@ -218,7 +201,7 @@ public void DriverTick() debugTicksSpentThisToil++; if (CurToil == null) { - //if (!this.caravan.stances.FullBodyBusy || this.CanStartNextToilInBusyStance) + //if (!caravan.stances.FullBodyBusy || CanStartNextToilInBusyStance) //{ ReadyForNextToil(); //} @@ -233,8 +216,7 @@ public void DriverTick() return; } } - else if (curToilCompleteMode == ToilCompleteMode.FinishedBusy - ) //&& !this.caravan.stances.FullBodyBusy) + else if (curToilCompleteMode == ToilCompleteMode.FinishedBusy) //&& !caravan.stances.FullBodyBusy { ReadyForNextToil(); return; @@ -245,8 +227,7 @@ public void DriverTick() } else if (curToilCompleteMode == ToilCompleteMode.Instant && debugTicksSpentThisToil > 300) { - Log.Error(string.Concat(caravan, " had to be broken from frozen state. He was doing job ", - CurJob, ", toilindex=", curToilIndex)); + Log.Error($"{caravan} had to be broken from frozen state. He was doing job {CurJob}, toilindex={curToilIndex}"); ReadyForNextToil(); } else @@ -264,16 +245,14 @@ public void DriverTick() return; } } - if (CurToil.tickAction != null) - CurToil.tickAction(); + CurToil.tickAction?.Invoke(); } } } catch (Exception ex) { - Find.World.GetComponent().Tracker(caravan).StartErrorRecoverJob( - string.Concat("Exception in Tick (pawn=", caravan, ", job=", CurJob, ", CurToil=", curToilIndex, - "): ", ex)); + CaravanJobsUtility.GetCaravanJobGiver().Tracker(caravan).StartErrorRecoverJob( + $"Exception in Tick (pawn={caravan}, job={CurJob}, CurToil={curToilIndex}): {ex}"); } } @@ -318,9 +297,8 @@ private void TryActuallyStartNextToil() } catch (Exception ex) { - Find.World.GetComponent().Tracker(caravan) - .StartErrorRecoverJob(string.Concat("JobDriver threw exception in initAction. Pawn=", - caravan, ", Job=", CurJob, ", Exception: ", ex)); + CaravanJobsUtility.GetCaravanJobGiver().Tracker(caravan) + .StartErrorRecoverJob($"JobDriver threw exception in initAction. Pawn={caravan}, Job={CurJob}, Exception: {ex}"); return; } if (CurToilIndex == num && !ended && curToilCompleteMode == ToilCompleteMode.Instant) @@ -334,7 +312,7 @@ public void EndJobWith(JobCondition condition) if (condition == JobCondition.Ongoing) Log.Warning("Ending a job with Ongoing as the condition. This makes no sense."); if (caravan.Spawned) - Find.World.GetComponent().Tracker(caravan).EndCurrentJob(condition, true); + CaravanJobsUtility.GetCaravanJobGiver().Tracker(caravan).EndCurrentJob(condition, true); } private bool CheckCurrentToilEndOrFail() @@ -400,12 +378,7 @@ public virtual void Notify_StanceChanged() public void AddFailCondition(Func newFailCondition) { - globalFailConditions.Add(delegate - { - if (newFailCondition()) - return JobCondition.Incompletable; - return JobCondition.Ongoing; - }); + globalFailConditions.Add(() => newFailCondition() ? JobCondition.Incompletable : JobCondition.Ongoing); } public void AddFinishAction(Action newAct) @@ -420,9 +393,7 @@ public virtual bool ModifyCarriedThingDrawPos(ref Vector3 drawPos, ref bool behi public virtual RandomSocialMode DesiredSocialMode() { - if (CurToil != null) - return CurToil.socialMode; - return RandomSocialMode.Normal; + return CurToil != null ? CurToil.socialMode : RandomSocialMode.Normal; } public virtual bool IsContinuation(Job j) @@ -430,4 +401,4 @@ public virtual bool IsContinuation(Job j) return true; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobGiver.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobGiver.cs index 998b461a..cd4ab0af 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobGiver.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobGiver.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using RimWorld.Planet; using Verse; @@ -14,37 +13,31 @@ public CaravanJobGiver(World world) : base(world) { } - public void NullHandler(Caravan caravan) - { - if (jobTrackers.FirstOrDefault(x => x.Caravan == caravan) == null) - jobTrackers.Add(new Caravan_JobTracker(caravan)); - } - public Caravan_JobTracker Tracker(Caravan caravan) { - NullHandler(caravan); //Log.Message("JecsTools :: CaravanJobGiver :: Tracker Called"); - return jobTrackers.FirstOrDefault(x => x.Caravan == caravan); + foreach (var t in jobTrackers) + { + if (t.Caravan == caravan) + return t; + } + var newTracker = new Caravan_JobTracker(caravan); + jobTrackers.Add(newTracker); + return newTracker; } public CaravanJob CurJob(Caravan caravan) { - NullHandler(caravan); //Log.Message("JecsTools :: CaravanJobGiver :: CurJob Called"); - return jobTrackers.FirstOrDefault(x => x.Caravan == caravan).curJob; + return Tracker(caravan).curJob; } public override void WorldComponentTick() { base.WorldComponentTick(); - if (jobTrackers != null && jobTrackers.Count > 0) - { - Caravan_JobTracker toRemove = null; - foreach (var t in jobTrackers) - if (t.Caravan == null || !t.Caravan.Spawned) toRemove = t; - else t.JobTrackerTick(); - if (toRemove != null) jobTrackers.Remove(toRemove); - } + jobTrackers.RemoveAll(t => t.Caravan == null || !t.Caravan.Spawned); + foreach (var t in jobTrackers) + t.JobTrackerTick(); } //private List jobTrackersKeysWorkingList; @@ -52,7 +45,7 @@ public override void WorldComponentTick() public override void ExposeData() { base.ExposeData(); - Scribe_Collections.Look(ref jobTrackers, "jobTrackers", LookMode.Deep); + Scribe_Collections.Look(ref jobTrackers, nameof(jobTrackers), LookMode.Deep); //if (Scribe.mode == LoadSaveMode.Saving) //{ // jobTrackerSave.Clear(); @@ -65,8 +58,8 @@ public override void ExposeData() // } // } //} - //Scribe_Collections.Look(ref this.jobTrackerSave, "jobTrackerSave", LookMode.Reference, LookMode.Deep, - // ref this.jobTrackersKeysWorkingList, ref this.jobTrackersValuesWorkingList); + //Scribe_Collections.Look(ref jobTrackerSave, nameof(jobTrackerSave), LookMode.Reference, LookMode.Deep, + // ref jobTrackersKeysWorkingList, ref jobTrackersValuesWorkingList); //if (Scribe.mode == LoadSaveMode.PostLoadInit) //{ // if (jobTrackerSave != null && jobTrackerSave.Count > 0) @@ -79,4 +72,4 @@ public override void ExposeData() //} } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobQueue.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobQueue.cs index 329b5cdf..d7e3f879 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobQueue.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobQueue.cs @@ -25,7 +25,7 @@ public bool AnyPlayerForced public void ExposeData() { - Scribe_Collections.Look(ref jobs, "jobs", LookMode.Deep); + Scribe_Collections.Look(ref jobs, nameof(jobs), LookMode.Deep); } public void EnqueueFirst(CaravanJob j, JobTag? tag = null) @@ -40,7 +40,7 @@ public void EnqueueLast(CaravanJob j, JobTag? tag = null) public QueuedCaravanJob Dequeue() { - if (jobs.NullOrEmpty()) + if (jobs.Count == 0) return null; var result = jobs[0]; jobs.RemoveAt(0); @@ -57,4 +57,4 @@ public void Clear() jobs.Clear(); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobsUtility.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobsUtility.cs index 45ebea24..6e4ecb00 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobsUtility.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanJobsUtility.cs @@ -8,19 +8,19 @@ public static class CaravanJobsUtility { public static void TeachCaravan(Caravan c, SkillDef sd, float rate) { - if (c.PawnsListForReading.NullOrEmpty()) + if (c.PawnsListForReading.Count == 0) { Log.Error("JecsTools :: No characters found in caravan."); return; } foreach (var p in c.PawnsListForReading) - if (p.skills != null) p.skills.Learn(sd, rate); + p.skills?.Learn(sd, rate); } public static float GetStatValueTotal(Caravan c, StatDef s) { var result = 1f; - if (c.PawnsListForReading.NullOrEmpty()) + if (c.PawnsListForReading.Count == 0) { Log.Error("JecsTools :: No characters found in caravan."); return result; @@ -33,7 +33,7 @@ public static float GetStatValueTotal(Caravan c, StatDef s) public static float GetStatValueAverage(Caravan c, StatDef s) { var result = 1f; - if (c.PawnsListForReading.NullOrEmpty()) + if (c.PawnsListForReading.Count == 0) { Log.Error("JecsTools :: No characters found in caravan."); return result; @@ -43,5 +43,19 @@ public static float GetStatValueAverage(Caravan c, StatDef s) result /= c.PawnsListForReading.Count; return result; } + + // Avoiding World.GetComponent and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static CaravanJobGiver GetCaravanJobGiver() + { + var comps = Find.World.components; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CaravanJobGiver comp) + return comp; + } + return null; + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToil.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToil.cs index b39b1625..ac0e9b5d 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToil.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToil.cs @@ -61,41 +61,32 @@ public void Cleanup() } catch (Exception ex) { - Log.Error(string.Concat("Pawn ", actor, - " threw exception while executing toil's finish action (", i, "), curJob=", - Find.World.GetComponent().CurJob(actor), ": ", ex)); + var curJob = CaravanJobsUtility.GetCaravanJobGiver().CurJob(actor); + Log.Error($"Pawn {actor} threw exception while executing toil's finish action ({i}), curJob={curJob}: {ex}"); } } public void AddFailCondition(Func newFailCondition) { - endConditions.Add(delegate - { - if (newFailCondition()) - return JobCondition.Incompletable; - return JobCondition.Ongoing; - }); + endConditions.Add(() => newFailCondition() ? JobCondition.Incompletable : JobCondition.Ongoing); } public void AddPreInitAction(Action newAct) { - if (preInitActions == null) - preInitActions = new List(); + preInitActions ??= new List(); preInitActions.Add(newAct); } public void AddPreTickAction(Action newAct) { - if (preTickActions == null) - preTickActions = new List(); + preTickActions ??= new List(); preTickActions.Add(newAct); } public void AddFinishAction(Action newAct) { - if (finishActions == null) - finishActions = new List(); + finishActions ??= new List(); finishActions.Add(newAct); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToils_Effects.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToils_Effects.cs index 7c09b9d0..cecd9c8b 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToils_Effects.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToils_Effects.cs @@ -14,7 +14,7 @@ public static CaravanToil WithProgressBar(this CaravanToil CaravanToil, TargetIn Func progressGetter, bool interpolateBetweenActorAndTarget = false, float offsetZ = -0.5f) { WorldObject_ProgressBar progressBar = null; - CaravanToil.AddPreTickAction(delegate + CaravanToil.AddPreTickAction(() => { if (CaravanToil.actor.Faction != Faction.OfPlayer) return; @@ -24,9 +24,8 @@ public static CaravanToil WithProgressBar(this CaravanToil CaravanToil, TargetIn if (progressBar == null) { progressBar = - (WorldObject_ProgressBar) WorldObjectMaker.MakeWorldObject( - DefDatabase.GetNamed("WorldObject_ProgressBar")); - progressBar.Tile = Find.World.GetComponent().CurJob(CaravanToil.actor) + (WorldObject_ProgressBar)WorldObjectMaker.MakeWorldObject(MiscDefOf.WorldObject_ProgressBar); + progressBar.Tile = CaravanJobsUtility.GetCaravanJobGiver().CurJob(CaravanToil.actor) .GetTarget(ind).Tile; progressBar.offset = offsetZ; Find.WorldObjects.Add(progressBar); @@ -35,13 +34,13 @@ public static CaravanToil WithProgressBar(this CaravanToil CaravanToil, TargetIn { progressBar.curProgress = Mathf.Clamp01(progressGetter()); if (CaravanToil.actor == null || !CaravanToil.actor.Spawned || - CaravanToil.actor.Tile != Find.World.GetComponent().CurJob(CaravanToil.actor) + CaravanToil.actor.Tile != CaravanJobsUtility.GetCaravanJobGiver().CurJob(CaravanToil.actor) .GetTarget(ind).Tile) if (progressBar.Spawned) Find.WorldObjects.Remove(progressBar); } }); - CaravanToil.AddFinishAction(delegate + CaravanToil.AddFinishAction(() => { if (progressBar != null && progressBar.Spawned) { @@ -52,4 +51,4 @@ public static CaravanToil WithProgressBar(this CaravanToil CaravanToil, TargetIn return CaravanToil; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToils_GoTo.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToils_GoTo.cs index 36b1fa26..3503e49d 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToils_GoTo.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/CaravanToils_GoTo.cs @@ -1,5 +1,4 @@ using RimWorld.Planet; -using Verse; using Verse.AI; namespace JecsTools @@ -8,12 +7,12 @@ public static class CaravanToils_Goto { private static Caravan_JobTracker CurTracker(Caravan c) { - return Find.World.GetComponent().Tracker(c); + return CaravanJobsUtility.GetCaravanJobGiver().Tracker(c); } private static CaravanJob CurJob(Caravan c) { - return Find.World.GetComponent().CurJob(c); + return CaravanJobsUtility.GetCaravanJobGiver().CurJob(c); } public static CaravanToil Goto(TargetIndex ind, CaravanArrivalAction arrivalAction = null) @@ -25,7 +24,7 @@ public static CaravanToil GotoObject(TargetIndex ind, CaravanArrivalAction arriv { var tileInt = -1; var toil = new CaravanToil(); - toil.initAction = delegate + toil.initAction = () => { //Log.Message("GoToObject1"); tileInt = CurJob(toil.actor).GetTarget(ind).WorldObject.Tile; @@ -33,9 +32,10 @@ public static CaravanToil GotoObject(TargetIndex ind, CaravanArrivalAction arriv toil.actor.pather.StartPath(tileInt, arrivalAction, true); //Log.Message("GoToObject3"); }; - toil.tickAction = delegate + toil.tickAction = () => { - if (tileInt < 0) tileInt = CurJob(toil.actor).GetTarget(ind).WorldObject.Tile; + if (tileInt < 0) + tileInt = CurJob(toil.actor).GetTarget(ind).WorldObject.Tile; if (toil.actor.Tile == tileInt) CurTracker(toil.actor).curDriver.Notify_PatherArrived(); }; @@ -47,10 +47,10 @@ public static CaravanToil GotoObject(TargetIndex ind, CaravanArrivalAction arriv public static CaravanToil GotoTile(TargetIndex ind, CaravanArrivalAction arrivalAction = null) { var toil = new CaravanToil(); - toil.initAction = delegate + toil.initAction = () => { var actor = toil.actor; - actor.pather.StartPath(Find.World.GetComponent().CurJob(actor).GetTarget(ind).Tile, + actor.pather.StartPath(CaravanJobsUtility.GetCaravanJobGiver().CurJob(actor).GetTarget(ind).Tile, arrivalAction); }; toil.defaultCompleteMode = ToilCompleteMode.PatherArrival; @@ -58,4 +58,4 @@ public static CaravanToil GotoTile(TargetIndex ind, CaravanArrivalAction arrival return toil; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/Caravan_JobTracker.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/Caravan_JobTracker.cs index 53131f85..2cc249fe 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/Caravan_JobTracker.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/Caravan_JobTracker.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +//#define DEBUGLOG + +using System.Collections.Generic; +using System.Diagnostics; using RimWorld; using RimWorld.Planet; using Verse; @@ -6,37 +9,34 @@ namespace JecsTools { + // Based off Pawn_JobTracker. public class Caravan_JobTracker : IExposable { - private const int ConstantThinkTreeJobCheckIntervalTicks = 30; + //private const int ConstantThinkTreeJobCheckIntervalTicks = 30; private const int RecentJobQueueMaxLength = 10; private const int MaxRecentJobs = 10; - private const int DamageCheckMinInterval = 180; - protected Caravan caravan; public CaravanJobDriver curDriver; public CaravanJob curJob; - public bool debugLog; - public CaravanJobQueue jobQueue = new CaravanJobQueue(); - private readonly List jobsGivenRecentTicks = new List(10); + private readonly List jobsGivenRecentTicks = new List(RecentJobQueueMaxLength); - private readonly List jobsGivenRecentTicksTextual = new List(10); + private readonly List jobsGivenRecentTicksTextual = new List(RecentJobQueueMaxLength); private int jobsGivenThisTick; - private string jobsGivenThisTickTextual = string.Empty; + private string jobsGivenThisTickTextual = ""; private int lastJobGivenAtFrame = -1; - private bool startingErrorRecoverJob; + //private bool startingErrorRecoverJob; public Caravan_JobTracker() { @@ -52,10 +52,10 @@ public Caravan_JobTracker(Caravan newCaravan) public virtual void ExposeData() { - Scribe_References.Look(ref caravan, "caravan"); - Scribe_Deep.Look(ref curJob, "curJob"); - Scribe_Deep.Look(ref curDriver, "curDriver"); - Scribe_Deep.Look(ref jobQueue, "jobQueue"); + Scribe_References.Look(ref caravan, nameof(caravan)); + Scribe_Deep.Look(ref curJob, nameof(curJob)); + Scribe_Deep.Look(ref curDriver, nameof(curDriver)); + Scribe_Deep.Look(ref jobQueue, nameof(jobQueue)); if (Scribe.mode == LoadSaveMode.LoadingVars) if (curDriver != null) curDriver.caravan = caravan; @@ -64,23 +64,21 @@ public virtual void ExposeData() public virtual void JobTrackerTick() { jobsGivenThisTick = 0; - jobsGivenThisTickTextual = string.Empty; - if (caravan.IsHashIntervalTick(30)) - { - //ThinkResult thinkResult = this.DetermineNextConstantThinkTreeJob(); - //if (thinkResult.IsValid && this.ShouldStartJobFromThinkTree(thinkResult)) - //{ - // this.CheckLeaveJoinableLordBecauseJobIssued(thinkResult); - // this.StartJob(thinkResult.Job, JobCondition.InterruptForced, thinkResult.SourceNode, false, false, null, null); //this.caravan.thinker.ConstantThinkTree, thinkResult.Tag); - //} - } - if (curDriver != null) - curDriver.DriverTick(); - if (curJob == null && //!this.caravan.Dead && this.caravan.mindState.Active && + jobsGivenThisTickTextual = ""; + //if (caravan.IsHashIntervalTick(ConstantThinkTreeJobCheckIntervalTicks)) + //{ + // var thinkResult = DetermineNextConstantThinkTreeJob(); + // if (thinkResult.IsValid && ShouldStartJobFromThinkTree(thinkResult)) + // { + // CheckLeaveJoinableLordBecauseJobIssued(thinkResult); + // StartJob(thinkResult.Job, JobCondition.InterruptForced, thinkResult.SourceNode, false, false); //caravan.thinker.ConstantThinkTree, thinkResult.Tag); + // } + //} + curDriver?.DriverTick(); + if (curJob == null && //!caravan.Dead && caravan.mindState.Active && CanDoAnyJob()) { - if (debugLog) - DebugLogEvent("Starting job from Tick because curJob == null."); + DebugLogEvent("Starting job from Tick because curJob == null."); TryFindAndStartJob(); } FinalizeTick(); @@ -90,7 +88,7 @@ private void FinalizeTick() { jobsGivenRecentTicks.Add(jobsGivenThisTick); jobsGivenRecentTicksTextual.Add(jobsGivenThisTickTextual); - while (jobsGivenRecentTicks.Count > 10) + while (jobsGivenRecentTicks.Count > RecentJobQueueMaxLength) { jobsGivenRecentTicks.RemoveAt(0); jobsGivenRecentTicksTextual.RemoveAt(0); @@ -100,13 +98,12 @@ private void FinalizeTick() var num = 0; for (var i = 0; i < jobsGivenRecentTicks.Count; i++) num += jobsGivenRecentTicks[i]; - if (num >= 10) + if (num >= MaxRecentJobs) { var text = GenText.ToCommaList(jobsGivenRecentTicksTextual, true); jobsGivenRecentTicks.Clear(); jobsGivenRecentTicksTextual.Clear(); - StartErrorRecoverJob(string.Concat(caravan, " started ", 10, " jobs in ", 10, " ticks. List: ", - text)); + StartErrorRecoverJob($"{caravan} started {MaxRecentJobs} jobs in {RecentJobQueueMaxLength} ticks. List: {text}"); } } } @@ -119,36 +116,32 @@ public void StartJob(CaravanJob newJob, JobCondition lastJobEndCondition = JobCo if (!Find.TickManager.Paused || lastJobGivenAtFrame == RealTime.frameCount) { jobsGivenThisTick++; - jobsGivenThisTickTextual = jobsGivenThisTickTextual + "(" + newJob + ") "; + jobsGivenThisTickTextual += "(" + newJob + ") "; } lastJobGivenAtFrame = RealTime.frameCount; - if (jobsGivenThisTick > 10) + if (jobsGivenThisTick > MaxRecentJobs) { var text = jobsGivenThisTickTextual; jobsGivenThisTick = 0; - jobsGivenThisTickTextual = string.Empty; - StartErrorRecoverJob(string.Concat(caravan, " started 10 jobs in one tick. newJob=", newJob, - " jobGiver=", jobGiver, " jobList=", text)); + jobsGivenThisTickTextual = ""; + StartErrorRecoverJob($"{caravan} started {MaxRecentJobs} jobs in one tick. newJob={newJob} jobGiver={jobGiver} jobList={text}"); return; } - if (debugLog) - DebugLogEvent(string.Concat("StartJob [", newJob, "] lastJobEndCondition=", lastJobEndCondition, - ", jobGiver=", jobGiver, ", cancelBusyStances=", cancelBusyStances)); + DebugLogEvent($"StartJob [{newJob}] lastJobEndCondition={lastJobEndCondition}, jobGiver={jobGiver}, cancelBusyStances={cancelBusyStances}"); if (curJob != null) { if (lastJobEndCondition == JobCondition.None) { - Log.Warning(string.Concat(caravan, " starting job ", newJob, " while already having job ", curJob, - " without a specific job end condition.")); + Log.Warning($"{caravan} starting job {newJob} while already having job {curJob} without a specific job end condition."); lastJobEndCondition = JobCondition.InterruptForced; } if (resumeCurJobAfterwards && curJob.def.suspendable) { jobQueue.EnqueueFirst(curJob, null); - if (debugLog) - DebugLogEvent(" JobQueue EnqueueFirst curJob: " + curJob); + DebugLogEvent(" JobQueue EnqueueFirst curJob: " + curJob); } - CleanupCurrentJob(lastJobEndCondition, !resumeCurJobAfterwards, cancelBusyStances); + //CleanupCurrentJob(lastJobEndCondition, !resumeCurJobAfterwards, cancelBusyStances); + CleanupCurrentJob(lastJobEndCondition); } if (newJob == null) { @@ -170,34 +163,35 @@ public void StartJob(CaravanJob newJob, JobCondition lastJobEndCondition = JobCo public void EndCurrentJob(JobCondition condition, bool startNewJob = true) { - if (debugLog) - DebugLogEvent(string.Concat("EndCurrentJob ", curJob == null ? "null" : curJob.ToString(), - " condition=", condition, " curToil=", - curDriver == null ? "null_driver" : curDriver.CurToilIndex.ToString())); + DebugLogEvent($"EndCurrentJob {curJob?.ToString() ?? "null"} condition={condition} " + + $"curToil={curDriver?.CurToilIndex.ToString() ?? "null_driver"}"); var job = curJob; - CleanupCurrentJob(condition, true, true); + //CleanupCurrentJob(condition, true, true); + CleanupCurrentJob(condition); if (startNewJob) { - if (condition == JobCondition.ErroredPather || condition == JobCondition.Errored) - return; - if (condition == JobCondition.Succeeded && job != null && !caravan.pather.Moving - ) //&& job.def != JobDefOf.WaitMaintainPosture ) + switch (condition) { - //this.StartJob(new CaravanJob(JobDefOf.WaitMaintainPosture, 1, false), JobCondition.None, null, false, false, null, null); - } - else - { - TryFindAndStartJob(); + case JobCondition.Errored: + case JobCondition.ErroredPather: + //StartJob(JobMaker.MakeJob(JobDefOf.Wait, 250)); + return; + case JobCondition.Succeeded: + if (job != null && !caravan.pather.Moving) //&& job.def != JobDefOf.WaitMaintainPosture + { + //StartJob(JobMaker.MakeJob(JobDefOf.WaitMaintainPosture, 1), JobCondition.None, null, false, false); + return; + } + break; } + TryFindAndStartJob(); } } - private void CleanupCurrentJob(JobCondition condition, bool releaseReservations, - bool cancelBusyStancesSoft = true) + //private void CleanupCurrentJob(JobCondition condition, bool releaseReservations, bool cancelBusyStancesSoft = true) + private void CleanupCurrentJob(JobCondition condition) { - if (debugLog) - DebugLogEvent(string.Concat("CleanupCurrentJob ", curJob == null ? "null" : curJob.def.ToString(), - " condition ", condition)); + DebugLogEvent($"CleanupCurrentJob {curJob?.def.ToString() ?? "null"} condition {condition}"); if (curJob == null) return; curDriver.ended = true; @@ -206,29 +200,27 @@ private void CleanupCurrentJob(JobCondition condition, bool releaseReservations, curJob = null; //if (releaseReservations) //{ - // this.caravan.ClearReservations(false); + // caravan.ClearReservations(false); //} //if (cancelBusyStancesSoft) //{ - // this.caravan.stances.CancelBusyStanceSoft(); + // caravan.stances.CancelBusyStanceSoft(); //} - //if (!this.caravan.Destroyed && this.caravan.carryTracker != null && this.caravan.carryTracker.CarriedThing != null) + //if (!caravan.Destroyed && caravan.carryTracker != null && caravan.carryTracker.CarriedThing != null) //{ // Thing thing; - // this.caravan.carryTracker.TryDropCarriedThing(this.caravan.Position, ThingPlaceMode.Near, out thing, null); + // caravan.carryTracker.TryDropCarriedThing(caravan.Position, ThingPlaceMode.Near, out thing, null); //} } public void CheckForJobOverride() { - if (debugLog) - DebugLogEvent("CheckForJobOverride"); - //ThinkTreeDef thinkTree; - //ThinkResult thinkResult = this.DetermineNextJob(out thinkTree); - //if (this.ShouldStartJobFromThinkTree(thinkResult)) + DebugLogEvent("CheckForJobOverride"); + //ThinkResult thinkResult = DetermineNextJob(out var thinkTree); + //if (ShouldStartJobFromThinkTree(thinkResult)) //{ - // this.CheckLeaveJoinableLordBecauseJobIssued(thinkResult); - // this.StartJob(thinkResult.Job, JobCondition.InterruptOptional, thinkResult.SourceNode, false, false, thinkTree, thinkResult.Tag); + // CheckLeaveJoinableLordBecauseJobIssued(thinkResult); + // StartJob(thinkResult.Job, JobCondition.InterruptOptional, thinkResult.SourceNode, false, false, thinkTree, thinkResult.Tag); //} } @@ -236,37 +228,34 @@ public void StopAll(bool ifLayingKeepLaying = false) { if (ifLayingKeepLaying && curJob != null && curDriver.layingDown == LayingDownState.LayingInBed) return; - CleanupCurrentJob(JobCondition.InterruptForced, true, true); + //CleanupCurrentJob(JobCondition.InterruptForced, true, true); + CleanupCurrentJob(JobCondition.InterruptForced); jobQueue.Clear(); } private void TryFindAndStartJob() { - //if (this.caravan.thinker == null) + //if (caravan.thinker == null) //{ - // Log.ErrorOnce(this.caravan + " did TryFindAndStartJob but had no thinker.", 8573261); + // Log.ErrorOnce(caravan + " did TryFindAndStartJob but had no thinker.", 8573261); // return; //} if (curJob != null) Log.Warning(caravan + " doing TryFindAndStartJob while still having job " + curJob); - if (debugLog) - DebugLogEvent("TryFindAndStartJob"); + DebugLogEvent("TryFindAndStartJob"); if (!CanDoAnyJob()) { - if (debugLog) - DebugLogEvent(" CanDoAnyJob is false. Clearing queue and returning"); - if (jobQueue != null) - jobQueue.Clear(); + DebugLogEvent(" CanDoAnyJob is false. Clearing queue and returning"); + jobQueue?.Clear(); return; } - //ThinkTreeDef thinkTreeDef; - //ThinkResult result = this.DetermineNextJob(out thinkTreeDef); + //ThinkResult result = DetermineNextJob(out var thinkTreeDef); //if (result.IsValid) //{ - // this.CheckLeaveJoinableLordBecauseJobIssued(result); + // CheckLeaveJoinableLordBecauseJobIssued(result); // ThinkNode sourceNode = result.SourceNode; // ThinkTreeDef thinkTree = thinkTreeDef; - // this.StartJob(result.Job, JobCondition.None, sourceNode, false, false, thinkTree, result.Tag); + // StartJob(result.Job, JobCondition.None, sourceNode, false, false, thinkTree, result.Tag); //} //ThinkTreeDef thinkTreeDef; @@ -286,14 +275,12 @@ private CaravanJob DetermineNextJob() while (jobQueue.Count > 0 && !jobQueue.Peek().job.CanBeginNow(caravan)) { var queuedJob = jobQueue.Dequeue(); - if (debugLog) - DebugLogEvent(" Throwing away queued job that I cannot begin now: " + queuedJob.job); + DebugLogEvent(" Throwing away queued job that I cannot begin now: " + queuedJob.job); } if (jobQueue.Count > 0) { var queuedJob2 = jobQueue.Dequeue(); - if (debugLog) - DebugLogEvent(" Returning queued job: " + queuedJob2.job); + DebugLogEvent(" Returning queued job: " + queuedJob2.job); return queuedJob2.job; } } @@ -302,32 +289,33 @@ private CaravanJob DetermineNextJob() public void StartErrorRecoverJob(string message) { - var text = message; //+ " lastJobGiver=" + this.caravan.mindState.lastJobGiver; + var text = message; //+ " lastJobGiver=" + caravan.mindState.lastJobGiver; if (curJob != null) - text = text + ", curJob.def=" + curJob.def.defName; + text += ", curJob.def=" + curJob.def.defName; if (curDriver != null) - text = text + ", curDriver=" + curDriver.GetType(); + text += ", curDriver=" + curDriver.GetType(); Log.Error(text); if (curJob != null) EndCurrentJob(JobCondition.Errored, false); - if (startingErrorRecoverJob) - { - Log.Error( - "An error occurred while starting an error recover job. We have to stop now to avoid infinite loops. This means that the Caravan is now jobless which can cause further bugs. Caravan=" + - caravan.ToStringSafe()); - } - else - { - startingErrorRecoverJob = true; - try - { - //this.StartJob(new Job(JobDefOf.Wait, 150, false), JobCondition.None, null, false, true, null, null); - } - finally - { - startingErrorRecoverJob = false; - } - } + //if (startingErrorRecoverJob) + //{ + // Log.Error( + // "An error occurred while starting an error recover job. We have to stop now to avoid infinite loops. " + + // "This means that the Caravan is now jobless which can cause further bugs. Caravan=" + + // caravan.ToStringSafe()); + //} + //else + //{ + // startingErrorRecoverJob = true; + // try + // { + // StartJob(JobMaker.MakeJob(JobDefOf.Wait, 150)); + // } + // finally + // { + // startingErrorRecoverJob = false; + // } + //} } //private void CheckLeaveJoinableLordBecauseJobIssued(ThinkResult result) @@ -336,28 +324,27 @@ public void StartErrorRecoverJob(string message) // { // return; // } - // Lord lord = this.caravan.GetLord(); + // var lord = caravan.GetLord(); // if (lord == null || !(lord.LordJob is LordJob_VoluntarilyJoinable)) // { // return; // } - // bool flag = false; - // ThinkNode thinkNode = result.SourceNode; - // while (!thinkNode.leaveJoinableLordIfIssuesJob) + // var flag = false; + // var thinkNode = result.SourceNode; + // do // { - // thinkNode = thinkNode.parent; - // if (thinkNode == null) + // if (thinkNode.leaveJoinableLordIfIssuesJob) // { - // IL_6F: - // if (flag) - // { - // lord.Notify_CaravanLost(this.caravan, CaravanLostCondition.LeftVoluntarily); - // } - // return; + // flag = true; + // break; // } + // thinkNode = thinkNode.parent; + // } + // while (thinkNode == null); + // if (flag) + // { + // lord.Notify_CaravanLost(caravan, CaravanLostCondition.LeftVoluntarily); // } - // flag = true; - // goto IL_6F; //} private bool CanDoAnyJob() @@ -367,36 +354,35 @@ private bool CanDoAnyJob() //private bool ShouldStartJobFromThinkTree(ThinkResult thinkResult) //{ - // return this.curJob == null || (thinkResult.Job.def != this.curJob.def || thinkResult.SourceNode != this.caravan.mindState.lastJobGiver || !this.curDriver.IsContinuation(thinkResult.Job)); + // return curJob == null || + // thinkResult.Job.def != curJob.def || + // thinkResult.SourceNode != caravan.mindState.lastJobGiver || + // !curDriver.IsContinuation(thinkResult.Job); //} public bool IsCurrentJobPlayerInterruptible() { - return curJob == null || curJob.def.playerInterruptible; //&& !this.caravan.HasAttachment(ThingDefOf.Fire); + return curJob == null || curJob.def.playerInterruptible; //&& !caravan.HasAttachment(ThingDefOf.Fire); } public bool TryTakeOrderedJobPrioritizedWork(CaravanJob job, WorkGiver giver, IntVec3 cell) { - if (TryTakeOrderedJob(job, giver.def.tagToGive)) - return true; - return false; + return TryTakeOrderedJob(job, giver.def.tagToGive); } public bool TryTakeOrderedJob(CaravanJob job, JobTag tag = JobTag.Misc) { - if (debugLog) - DebugLogEvent("TakeOrderedJob " + job); + DebugLogEvent("TakeOrderedJob " + job); job.playerForced = true; if (curJob != null && curJob.JobIsSameAs(job)) return true; caravan.pather.StopDead(); - //this.caravan.Map.CaravanDestinationManager.UnreserveAllFor(this.caravan); + //caravan.Map.CaravanDestinationManager.UnreserveAllFor(caravan); //if (job.def == CaravanJobDefOf.Goto) //{ - // //this.caravan.Map.CaravanDestinationManager.ReserveDestinationFor(this.caravan, job.targetA.Cell); + // //caravan.Map.CaravanDestinationManager.ReserveDestinationFor(caravan, job.targetA.Cell); //} - if (debugLog) - DebugLogEvent(" Queueing job"); + DebugLogEvent(" Queueing job"); jobQueue.Clear(); jobQueue.EnqueueFirst(job, tag); if (IsCurrentJobPlayerInterruptible()) @@ -412,10 +398,10 @@ public void Notify_PathInterrupted() EndCurrentJob(JobCondition.InterruptForced, false); } - public void DebugLogEvent(string s) + [Conditional("DEBUGLOG")] + private void DebugLogEvent(string s) { - if (debugLog) - Log.Message(string.Concat(Find.TickManager.TicksGame, " ", caravan, ": ", s)); + Log.Message($"{Find.TickManager.TicksGame} {caravan}: {s}"); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/HarmonyCaravanJobs.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/HarmonyCaravanJobs.cs index 32e07335..41eeef94 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/HarmonyCaravanJobs.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/HarmonyCaravanJobs.cs @@ -13,73 +13,60 @@ internal static class HarmonyCaravanPatches static HarmonyCaravanPatches() { var harmony = new Harmony("jecstools.jecrell.caravanjobs"); + var type = typeof(HarmonyCaravanPatches); - harmony.Patch(AccessTools.Method(typeof(Caravan), "GetInspectString"), null, - new HarmonyMethod(typeof(HarmonyCaravanPatches), nameof(GetInspectString_Jobs)), null); - harmony.Patch(AccessTools.Method(typeof(WorldSelector), "AutoOrderToTileNow"), null, - new HarmonyMethod(typeof(HarmonyCaravanPatches), nameof(AutoOrderToTileNow_Jobs)), null); - harmony.Patch(AccessTools.Method(typeof(Caravan), "GetGizmos"), null, - new HarmonyMethod(typeof(HarmonyCaravanPatches), nameof(GetGizmos_Jobs)), null); - harmony.Patch( - AccessTools.Method(typeof(WorldSelector), "SelectableObjectsUnderMouse", - new[] {typeof(bool).MakeByRefType(), typeof(bool).MakeByRefType()}), - null, new HarmonyMethod(typeof(HarmonyCaravanPatches), - nameof(SelectableObjectsUnderMouse_InvisHandler)), null); + harmony.Patch(AccessTools.Method(typeof(Caravan), nameof(Caravan.GetInspectString)), + postfix: new HarmonyMethod(type, nameof(GetInspectString_Jobs))); + harmony.Patch(AccessTools.Method(typeof(WorldSelector), "AutoOrderToTileNow"), + postfix: new HarmonyMethod(type, nameof(AutoOrderToTileNow_Jobs))); + harmony.Patch(AccessTools.Method(typeof(Caravan), nameof(Caravan.GetGizmos)), + postfix: new HarmonyMethod(type, nameof(GetGizmos_Jobs))); + harmony.Patch(AccessTools.Method(typeof(WorldSelector), nameof(WorldSelector.SelectableObjectsUnderMouse), + new[] { typeof(bool).MakeByRefType(), typeof(bool).MakeByRefType() }), + postfix: new HarmonyMethod(type, nameof(SelectableObjectsUnderMouse_InvisHandler))); } // RimWorld.Planet.WorldSelector - public static void SelectableObjectsUnderMouse_InvisHandler(ref bool clickedDirectlyOnCaravan, - ref bool usedColonistBar, ref IEnumerable __result) + public static void SelectableObjectsUnderMouse_InvisHandler(ref IEnumerable __result) { - var objects = new List(__result); - if (!objects.NullOrEmpty()) - { - var temp = new HashSet(objects); - foreach (var o in temp) - if (!o.SelectableNow) - objects.Remove(o); - } - __result = objects; + static bool NotSelectableNow(WorldObject o) => !o.SelectableNow; + if (__result is List list) + list.RemoveAll(NotSelectableNow); + else + __result = __result.Where(NotSelectableNow); } - // RimWorld.Planet.Caravan - public static void GetGizmos_Jobs(Caravan __instance, ref IEnumerable __result) { if (__instance.IsPlayerControlled) { var curTile = Find.WorldGrid[__instance.Tile]; - if (Find.World.GetComponent().CurJob(__instance) != null) - __result = __result.Concat(new[] + var caravanJobGiver = CaravanJobsUtility.GetCaravanJobGiver(); + if (caravanJobGiver.CurJob(__instance) != null) + __result = __result.Append(new Command_Action { - new Command_Action - { - defaultLabel = "CommandCancelConstructionLabel".Translate(), - defaultDesc = "CommandClearPrioritizedWorkDesc".Translate(), - icon = TexCommand.ClearPrioritizedWork, - action = delegate - { - Find.World.GetComponent().Tracker(__instance).StopAll(); - } - } + defaultLabel = "CommandCancelConstructionLabel".Translate(), + defaultDesc = "CommandClearPrioritizedWorkDesc".Translate(), + icon = TexCommand.ClearPrioritizedWork, + action = () => caravanJobGiver.Tracker(__instance).StopAll(), }); } } // RimWorld.Planet.WorldSelector - public static void AutoOrderToTileNow_Jobs(Caravan c, int tile) + public static void AutoOrderToTileNow_Jobs(Caravan c) { - Find.World.GetComponent().Tracker(c).StopAll(); + CaravanJobsUtility.GetCaravanJobGiver().Tracker(c).StopAll(); } // RimWorld.Planet.Caravan public static void GetInspectString_Jobs(Caravan __instance, ref string __result) { - if (Find.World.GetComponent()?.Tracker(__instance)?.curDriver?.GetReport() is string s && + if (CaravanJobsUtility.GetCaravanJobGiver().Tracker(__instance)?.curDriver?.GetReport() is string s && __result.Contains("CaravanWaiting".Translate())) __result = __result.Replace("CaravanWaiting".Translate(), s.CapitalizeFirst()); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/QueuedCaravanJob.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/QueuedCaravanJob.cs index da20f7c1..8f75a93b 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/QueuedCaravanJob.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/QueuedCaravanJob.cs @@ -21,8 +21,8 @@ public QueuedCaravanJob(CaravanJob job, JobTag? tag) public void ExposeData() { - Scribe_Deep.Look(ref job, "job"); - Scribe_Values.Look(ref tag, "tag", null, false); + Scribe_Deep.Look(ref job, nameof(job)); + Scribe_Values.Look(ref tag, nameof(tag)); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/StuffCategoryCountClass.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/StuffCategoryCountClass.cs index a7682fed..1febf23f 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/StuffCategoryCountClass.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/StuffCategoryCountClass.cs @@ -4,7 +4,7 @@ namespace JecsTools { - public class StuffCategoryCountClass: IExposable + public class StuffCategoryCountClass : IExposable { public StuffCategoryDef stuffCatDef; @@ -18,31 +18,19 @@ public StuffCategoryCountClass(StuffCategoryDef stuffCatDef, int count) { if (count < 0) { - Log.Warning(string.Concat(new object[] - { - "Tried to set StuffCategoryCountClass count to ", - count, - ". stuffDef=", - stuffCatDef - }), false); + Log.Warning($"Tried to set StuffCategoryCountClass count to {count}. stuffDef={stuffCatDef}", false); count = 0; } this.stuffCatDef = stuffCatDef; this.count = count; } - public string Summary - { - get - { - return this.count + "x " + ((this.stuffCatDef == null) ? "null" : this.stuffCatDef.label); - } - } + public string Summary => $"{count}x {stuffCatDef?.label ?? "null"}"; public void ExposeData() { - Scribe_Defs.Look(ref this.stuffCatDef, "stuffCatDef"); - Scribe_Values.Look(ref this.count, "count", 1, false); + Scribe_Defs.Look(ref stuffCatDef, nameof(stuffCatDef)); + Scribe_Values.Look(ref count, nameof(count), 1); } public void LoadDataFromXmlCustom(XmlNode xmlRoot) @@ -54,30 +42,17 @@ public void LoadDataFromXmlCustom(XmlNode xmlRoot) else { DirectXmlCrossRefLoader.RegisterObjectWantsCrossRef(this, "stuffCatDef", xmlRoot.Name); - this.count = (int)ParseHelper.FromString(xmlRoot.FirstChild.Value, typeof(int)); + count = (int)ParseHelper.FromString(xmlRoot.FirstChild.Value, typeof(int)); } } - public override string ToString() - { - return string.Concat(new object[] - { - "(", - this.count, - "x ", - (this.stuffCatDef == null) ? "null" : this.stuffCatDef.defName, - ")" - }); - } + public override string ToString() => $"{count}x {stuffCatDef?.defName ?? "null"}"; - public override int GetHashCode() - { - return (int)this.stuffCatDef.shortHash + this.count << 16; - } + public override int GetHashCode() => stuffCatDef.shortHash + count << 16; public static implicit operator StuffCategoryCountClass(StuffDefCount t) { return new StuffCategoryCountClass(t.StuffDef, t.Count); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/StuffDefCount.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/StuffDefCount.cs index cb9cbc10..fca6aa2e 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/StuffDefCount.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/StuffDefCount.cs @@ -14,86 +14,37 @@ public StuffDefCount(StuffCategoryDef stuffDef, int count) { if (count < 0) { - Log.Warning(string.Concat(new object[] - { - "Tried to set StuffDefCount count to ", - count, - ". stuffDef=", - stuffDef - }), false); + Log.Warning($"Tried to set StuffDefCount count to {count}. stuffDef={stuffDef}", false); count = 0; } this.stuffDef = stuffDef; this.count = count; } - public StuffCategoryDef StuffDef - { - get - { - return this.stuffDef; - } - } + public StuffCategoryDef StuffDef => stuffDef; - public int Count - { - get - { - return this.count; - } - } + public int Count => count; public void ExposeData() { - Scribe_Defs.Look(ref this.stuffDef, "stuffDef"); - Scribe_Values.Look(ref this.count, "count", 1, false); + Scribe_Defs.Look(ref stuffDef, nameof(stuffDef)); + Scribe_Values.Look(ref count, nameof(count), 1); } - public StuffDefCount WithCount(int newCount) - { - return new StuffDefCount(this.stuffDef, newCount); - } + public StuffDefCount WithCount(int newCount) => new StuffDefCount(stuffDef, newCount); - public override bool Equals(object obj) - { - return obj is StuffDefCount && this.Equals((StuffDefCount)obj); - } + public override bool Equals(object obj) => obj is StuffDefCount other && Equals(other); - public bool Equals(StuffDefCount other) - { - return this == other; - } + public bool Equals(StuffDefCount other) => this == other; - public static bool operator ==(StuffDefCount a, StuffDefCount b) - { - return a.stuffDef == b.stuffDef && a.count == b.count; - } + public static bool operator ==(StuffDefCount a, StuffDefCount b) => a.stuffDef == b.stuffDef && a.count == b.count; - public static bool operator !=(StuffDefCount a, StuffDefCount b) - { - return !(a == b); - } + public static bool operator !=(StuffDefCount a, StuffDefCount b) => !(a == b); - public override int GetHashCode() - { - return Gen.HashCombine(this.count, this.stuffDef); - } + public override int GetHashCode() => Gen.HashCombine(count, stuffDef); - public override string ToString() - { - return string.Concat(new object[] - { - "(", - this.count, - "x ", - (this.stuffDef == null) ? "null" : this.stuffDef.defName, - ")" - }); - } + public override string ToString() => $"({count}x {stuffDef?.defName ?? "null"}"; - public static implicit operator StuffDefCount(StuffCategoryCountClass t) - { - return new StuffDefCount(t.stuffCatDef, t.count); - } + public static implicit operator StuffDefCount(StuffCategoryCountClass t) => new StuffDefCount(t.stuffCatDef, t.count); } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObjectBlueprint.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObjectBlueprint.cs index 2ee3f274..aad7cb8a 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObjectBlueprint.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObjectBlueprint.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using RimWorld; using RimWorld.Planet; @@ -27,44 +26,48 @@ public List ConsumedResources public override void ExposeData() { base.ExposeData(); - Scribe_Values.Look(ref resourcesSupplied, "resourcesSupplied", false); - Scribe_Collections.Look(ref consumedResources, "consumedResources", LookMode.Reference); + Scribe_Values.Look(ref resourcesSupplied, nameof(resourcesSupplied)); + Scribe_Collections.Look(ref consumedResources, nameof(consumedResources), LookMode.Reference); } public virtual void Finish() { if (!ConsumedResources.NullOrEmpty()) + DestroyConsumedResources(); + } + + private void DestroyConsumedResources() + { + // XXX: Not sure if Destroy on each consumed resource can end up modifying ConsumedResources itself, + // so to be safe, enumerating over a copy of the list. + // Also not sure if any code relies on the "remove t from ConsumedResources, then Destroy t" behavior, + // so keeping that behavior as well. + foreach (var t in ConsumedResources.ToArray()) { - var iterable = new HashSet(ConsumedResources); - foreach (var t in iterable) - { - ConsumedResources.Remove(t); - t.Destroy(DestroyMode.Vanish); - } + ConsumedResources.Remove(t); + t.Destroy(); } } - public virtual bool Cancel() { - var c = Find.WorldObjects.PlayerControlledCaravanAt(Tile); - if (ConsumedResources != null && ConsumedResources.Count() > 0) + if (!ConsumedResources.NullOrEmpty()) + { + var c = Find.WorldObjects.PlayerControlledCaravanAt(Tile); if (c != null) { - var temp = new HashSet(ConsumedResources); - foreach (var t in temp) + foreach (var t in ConsumedResources.ToArray()) // using copy for enumeration - see DestroyConsumedResources comments { - var pawn2 = CaravanInventoryUtility.FindPawnToMoveInventoryTo(t, c.PawnsListForReading, null, - null); - if (pawn2 == null) + var pawn = CaravanInventoryUtility.FindPawnToMoveInventoryTo(t, c.PawnsListForReading, null); + if (pawn == null) { Log.Error("Could not find pawn to move bought thing to (bought by player). thing=" + t); - t.Destroy(DestroyMode.Vanish); + t.Destroy(); } - else if (!pawn2.inventory.innerContainer.TryAdd(t, true)) + else if (!pawn.inventory.innerContainer.TryAdd(t)) { Log.Error("Could not add item to inventory."); - t.Destroy(DestroyMode.Vanish); + t.Destroy(); } } return true; @@ -75,32 +78,29 @@ public virtual bool Cancel() var labels = new string[ConsumedResources.Count]; for (var i = 0; i < ConsumedResources.Count; i++) labels[i] = ConsumedResources[i].Label; - var window2 = Dialog_MessageBox.CreateConfirmation( + var window = Dialog_MessageBox.CreateConfirmation( "ConfirmAbandonItemDialog".Translate(string.Join(", ", labels) + " " + - "JecsTools_WorldObjectConst_AbandonReason".Translate()), - delegate + "JecsTools_WorldObjectConst_AbandonReason".Translate()), + () => { - //Pawn ownerOf = CaravanInventoryUtility.GetOwnerOf(caravan, t); + //var ownerOf = CaravanInventoryUtility.GetOwnerOf(caravan, t); //if (ownerOf == null) //{ // Log.Error("Could not find owner of " + t); // return; //} //ownerOf.inventory.innerContainer.Remove(t); - var temp = new HashSet(ConsumedResources); - foreach (var t in temp) - { - t.Destroy(DestroyMode.Vanish); - ConsumedResources.Remove(t); - } + DestroyConsumedResources(); didCancel = true; }, true, null); - Find.WindowStack.Add(window2); + Find.WindowStack.Add(window); return didCancel; } + } return true; } + // Based off Settlement/CaravanArrivalAction_VisitSettlement/CaravanArrivalActionUtility. public override IEnumerable GetFloatMenuOptions(Caravan caravan) { foreach (var f in base.GetFloatMenuOptions(caravan)) @@ -108,42 +108,40 @@ public override IEnumerable GetFloatMenuOptions(Caravan caravan if (ConstructJobDef != null) { if (CheckAndConsumeResources(caravan, Recipe, false)) - yield return new FloatMenuOption("CreateNewZone".Translate(Recipe.FinishedThing.label), () => - { - var t = Find.World.GetComponent().Tracker(caravan); - var curBlueprint = this; - while (curBlueprint != null) + yield return new FloatMenuOption( + "CreateNewZone".Translate(Recipe.FinishedThing.label), () => { - t.jobQueue.EnqueueLast(new CaravanJob(ConstructJobDef, curBlueprint)); - curBlueprint = curBlueprint.NextBlueprint; - } - }, MenuOptionPriority.Default); + var t = CaravanJobsUtility.GetCaravanJobGiver().Tracker(caravan); + var curBlueprint = this; + while (curBlueprint != null) + { + t.jobQueue.EnqueueLast(new CaravanJob(ConstructJobDef, curBlueprint)); + curBlueprint = curBlueprint.NextBlueprint; + } + }); else yield return new FloatMenuOption( - "CreateNewZone".Translate(Recipe.FinishedThing.label) + " (" + "MissingMaterials".Translate() + - ")", - null, MenuOptionPriority.Default, null, null, 0f, null, null); + "CreateNewZone".Translate(Recipe.FinishedThing.label) + " (" + "MissingMaterials".Translate() + ")", + null); yield return new FloatMenuOption("VisitSite".Translate(Label), - delegate { caravan.pather.StartPath(Tile, null, true); }, MenuOptionPriority.Default, null, null, - 0f, null, this); + () => caravan.pather.StartPath(Tile, null, true), revalidateWorldClickTarget: this); if (Prefs.DevMode) { yield return new FloatMenuOption( - "CreateNewZone".Translate(Recipe.FinishedThing.label) + " (Dev: instantly)", delegate - { - //this.caravan.Tile = this.<> f__this.Tile; - //this.caravan.pather.StopDead(); - //new CaravanArrivalAction_VisitSettlement(this.<> f__this).Arrived(this.caravan); - Finish(); - }, MenuOptionPriority.Default, null, null, 0f, null, this); + "CreateNewZone".Translate(Recipe.FinishedThing.label) + " (Dev: instantly)", Finish); + //{ + // caravan.Tile = Tile; + // caravan.pather.StopDead(); + // new CaravanArrivalAction_VisitSettlement(this).Arrived(caravan); + //}); yield return new FloatMenuOption( - "VisitSite".Translate(Recipe.FinishedThing.label) + " (Dev: instantly)", delegate + "VisitSite".Translate(Recipe.FinishedThing.label) + " (Dev: instantly)", () => { caravan.Tile = Tile; caravan.pather.StopDead(); - //new CaravanArrivalAction_VisitSettlement(this.<> f__this).Arrived(this.caravan); - //this.FinishConstruction(); - }, MenuOptionPriority.Default, null, null, 0f, null, this); + //new CaravanArrivalAction_VisitSettlement(this).Arrived(caravan); + //FinishConstruction(); + }); } } } @@ -157,28 +155,29 @@ public override IEnumerable GetGizmos() defaultLabel = "CommandRemoveWaypointLabel".Translate(), defaultDesc = "CommandRemoveWaypointDesc".Translate(), icon = TexCommand.RemoveRoutePlannerWaypoint, - action = delegate { Cancel(); } + action = () => Cancel(), }; if (DebugSettings.godMode) yield return new Command_Action { defaultLabel = "Dev: Instant build", - action = delegate { Finish(); } + action = Finish, }; } public void AddNumOfCheapestThings(List allItems, Dictionary toBeConsumed, ThingDefCountClass thingCount) { - var matchingItemsPriceSorted = allItems.Where(thing => thing.def == thingCount.thingDef - && (!toBeConsumed.TryGetValue(thing, - out int value) || thing.stackCount > value)) - .OrderBy(thing => thing.GetStatValue(StatDefOf.MarketValue)); - int remainingCount = thingCount.count; + var matchingItemsPriceSorted = allItems.FindAll(thing => + thing.def == thingCount.thingDef && + (!toBeConsumed.TryGetValue(thing, out var value) || thing.stackCount > value)); + matchingItemsPriceSorted.Sort(CompareMarketValue); + ; + var remainingCount = thingCount.count; foreach (var thing in matchingItemsPriceSorted) { - toBeConsumed.TryGetValue(thing, out int currentTaken); - int numberToTake = Math.Min(thing.stackCount - currentTaken, remainingCount); + toBeConsumed.TryGetValue(thing, out var currentTaken); + var numberToTake = Math.Min(thing.stackCount - currentTaken, remainingCount); if (currentTaken != 0) toBeConsumed[thing] += numberToTake; else @@ -197,18 +196,15 @@ public void AddNumOfCheapestThings(List allItems, Dictionary public void AddNumOfCheapestStuff(List allItems, Dictionary toBeConsumed, StuffCategoryCountClass stuffCount) { - var matchingItemsPriceSorted = allItems.Where(thing => ((thing?.Stuff?.stuffProps ?? thing.def.stuffProps) - ?.categories?.Contains(stuffCount.stuffCatDef) ?? - false) - && (toBeConsumed.TryGetValue(thing, out int value) - ? thing.stackCount > value - : true)) - .OrderBy(thing => thing.GetStatValue(StatDefOf.MarketValue)); - int remainingCount = stuffCount.count; + var matchingItemsPriceSorted = allItems.FindAll(thing => + ((thing.Stuff?.stuffProps ?? thing.def.stuffProps)?.categories?.Contains(stuffCount.stuffCatDef) ?? false) && + (!toBeConsumed.TryGetValue(thing, out var value) || thing.stackCount > value)); + matchingItemsPriceSorted.Sort(CompareMarketValue); + var remainingCount = stuffCount.count; foreach (var thing in matchingItemsPriceSorted) { - toBeConsumed.TryGetValue(thing, out int currentTaken); - int numberToTake = Math.Min(thing.stackCount - currentTaken, remainingCount); + toBeConsumed.TryGetValue(thing, out var currentTaken); + var numberToTake = Math.Min(thing.stackCount - currentTaken, remainingCount); if (currentTaken != 0) toBeConsumed[thing] += numberToTake; else @@ -224,76 +220,68 @@ public void AddNumOfCheapestStuff(List allItems, Dictionary t 9534713); } + private static int CompareMarketValue(Thing x, Thing y) + { + return x.GetStatValue(StatDefOf.MarketValue).CompareTo(y.GetStatValue(StatDefOf.MarketValue)); + } public virtual bool CheckAndConsumeResources(Caravan c, WorldObjectRecipeDef recipe, bool consumeResources = true) { - if (resourcesSupplied) return true; + if (resourcesSupplied) + return true; var toBeConsumed = new Dictionary(); var caravanInv = CaravanInventoryUtility.AllInventoryItems(c); - if (caravanInv == null || caravanInv.Count() == 0) + if (caravanInv.NullOrEmpty()) return false; var passed = true; var allItems = CaravanInventoryUtility.AllInventoryItems(c); var missingResourcesMessage = new StringBuilder(); - foreach (var thingCount in recipe?.costList ?? Enumerable.Empty()) + var costList = recipe?.costList; + if (costList != null) { -//<<<<<<< Previous code before merging with Pull Request #23 -// var passed = false; -// foreach (var t in recipe.stuffCategories) -// { -// var yy = CaravanInventoryUtility.AllInventoryItems(c) -// .FindAll(x => x?.def?.stuffProps?.categories?.Contains(t) ?? false); -// if (!yy.NullOrEmpty()) -// { -// var totalCount = yy.Sum(x => x.stackCount); -// if (totalCount - recipe.costStuffCount >= 0) -// { -// totalCount -= totalCount - recipe.costStuffCount; -// passed = true; -// foreach (var y in yy) -// { -// if (totalCount > 0) -// { -// var math = Math.Min(y.stackCount, totalCount); -// toBeConsumed.Add(y, math); -// //Log.Message(y + " x" + math); -// } -// totalCount -= y.stackCount; -// } -// } -// } -//======= - int thingsFound = allItems.Where(thing => thing.def == thingCount.thingDef) - .Sum(thing => thing.stackCount); - if (thingsFound >= thingCount.count) - AddNumOfCheapestThings(allItems, toBeConsumed, thingCount); - else + foreach (var thingCount in costList) { - missingResourcesMessage.AppendLine("JecsTools_WorldObjectConst_NotEnoughThings" - .Translate(thingsFound, thingCount.count, thingCount.thingDef.LabelCap)); - passed = false; -//>>>>>>> pr/23 + var thingsFound = 0; + foreach (var thing in allItems) + { + if (thing.def == thingCount.thingDef) + thingsFound += thing.stackCount; + } + if (thingsFound >= thingCount.count) + AddNumOfCheapestThings(allItems, toBeConsumed, thingCount); + else + { + missingResourcesMessage.AppendLine("JecsTools_WorldObjectConst_NotEnoughThings" + .Translate(thingsFound, thingCount.count, thingCount.thingDef.LabelCap)); + passed = false; + } } } - foreach (var stuffCount in recipe?.stuffCostList ?? Enumerable.Empty()) + var stuffCostList = recipe?.stuffCostList; + if (stuffCostList != null) { - //Ensure I find stuffProps either under Stuff or def if any - int stuffFound = allItems.Where(thing => (thing?.Stuff?.stuffProps ?? thing.def.stuffProps) - ?.categories?.Contains(stuffCount.stuffCatDef) ?? false) - .Sum(thing => thing.stackCount - - (toBeConsumed.TryGetValue(thing, out int value) ? value : 0)); - if (stuffFound >= stuffCount.count) - AddNumOfCheapestStuff(allItems, toBeConsumed, stuffCount); - else + foreach (var stuffCount in stuffCostList) { - missingResourcesMessage.AppendLine("JecsTools_WorldObjectConst_NotEnoughStuff" - .Translate(stuffFound, stuffCount.count, stuffCount.stuffCatDef.LabelCap)); - passed = false; + //Ensure I find stuffProps either under Stuff or def if any + var stuffFound = 0; + foreach (var thing in allItems) + { + if ((thing.Stuff?.stuffProps ?? thing.def.stuffProps)?.categories?.Contains(stuffCount.stuffCatDef) ?? false) + stuffFound += thing.stackCount - (toBeConsumed.TryGetValue(thing, out var value) ? value : 0); + } + if (stuffFound >= stuffCount.count) + AddNumOfCheapestStuff(allItems, toBeConsumed, stuffCount); + else + { + missingResourcesMessage.AppendLine("JecsTools_WorldObjectConst_NotEnoughStuff" + .Translate(stuffFound, stuffCount.count, stuffCount.stuffCatDef.LabelCap)); + passed = false; + } } } @@ -314,30 +302,27 @@ public virtual bool CheckAndConsumeResources(Caravan c, WorldObjectRecipeDef rec public bool ConsumeResources(Caravan c, Dictionary toBeConsumed) { - if (toBeConsumed != null && toBeConsumed.Count > 0) - foreach (var pair in toBeConsumed) + foreach (var (t, count) in toBeConsumed) + { + var ownerOf = CaravanInventoryUtility.GetOwnerOf(c, t); + if (ownerOf == null) { - var t = pair.Key; - var count = pair.Value; - var ownerOf = CaravanInventoryUtility.GetOwnerOf(c, t); - if (ownerOf == null) - { - Log.Error("Could not find owner of " + t); - return false; - } - if (count == t.stackCount) - { - ownerOf.inventory.innerContainer.Remove(t); - ConsumedResources.Add(t); - //t.Destroy(DestroyMode.Vanish); - } - else - { - ConsumedResources.Add(t.SplitOff(count)); //Destroy(DestroyMode.Vanish); - } - c.RecacheImmobilizedNow(); - c.RecacheDaysWorthOfFood(); + Log.Error("Could not find owner of " + t); + return false; } + if (count == t.stackCount) + { + ownerOf.inventory.innerContainer.Remove(t); + ConsumedResources.Add(t); + //t.Destroy(DestroyMode.Vanish); + } + else + { + ConsumedResources.Add(t.SplitOff(count)); //Destroy(DestroyMode.Vanish); + } + c.RecacheImmobilizedNow(); + c.RecacheDaysWorthOfFood(); + } resourcesSupplied = true; return true; } @@ -348,13 +333,13 @@ public override string GetInspectString() s.Append(base.GetInspectString()); if (Recipe != null) { - if (!Recipe.costList.NullOrEmpty()) + if (Recipe.costList != null) foreach (var t in Recipe.costList) { var amtFilled = resourcesSupplied ? t.count.ToString() : "0"; s.AppendLine(t.thingDef.LabelCap + ": " + amtFilled + " / " + t.count); } - if (!Recipe.stuffCostList.NullOrEmpty()) + if (Recipe.stuffCostList != null) foreach (var stuffCat in Recipe.stuffCostList) { var amtFilled = resourcesSupplied ? stuffCat.count.ToString() : "0"; @@ -364,4 +349,4 @@ public override string GetInspectString() return s.ToString().TrimEndNewlines(); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObjectRecipeDef.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObjectRecipeDef.cs index c809c891..9f3c6077 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObjectRecipeDef.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObjectRecipeDef.cs @@ -14,10 +14,11 @@ public class WorldObjectRecipeDef : Def public virtual bool CanMake() { - if (!researchPrerequisites.NullOrEmpty()) + if (researchPrerequisites != null) foreach (var r in researchPrerequisites) - if (!r.IsFinished) return false; + if (!r.IsFinished) + return false; return true; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObject_ProgressBar.cs b/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObject_ProgressBar.cs index 7dfb1dc2..5ad5af04 100644 --- a/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObject_ProgressBar.cs +++ b/Source/AllModdingComponents/JecsTools/CaravanJobs/WorldObject_ProgressBar.cs @@ -23,17 +23,16 @@ public class WorldObject_ProgressBar : WorldObject //{ // get // { - // float d = 0.15f * Find.WorldGrid.averageTileSize; + // var d = 0.15f * Find.WorldGrid.averageTileSize; // Rand.PushState(); - // Rand.Seed = this.ID; - // float f = Rand.Range(0f, 360f); + // Rand.Seed = ID; + // var f = Rand.Range(0f, 360f); // Rand.PopState(); // Vector2 point = new Vector2(Mathf.Cos(f), Mathf.Sin(f)) * d; - // return WorldRendererUtility.ProjectOnQuadTangentialToPlanet(Find.WorldGrid.GetTileCenter(this.Tile), point); + // return WorldRendererUtility.ProjectOnQuadTangentialToPlanet(Find.WorldGrid.GetTileCenter(Tile), point); // } //} - public override void Draw() { if (curProgress < 0) @@ -67,22 +66,17 @@ public static void DrawShrinkableQuadTangentialToPlanet(Vector3 pos, float curSi return; } var normalized = pos.normalized; - Vector3 vector; - if (counterClockwise) - vector = -normalized; - else - vector = normalized; + var vector = counterClockwise ? -normalized : normalized; var q = Quaternion.LookRotation(Vector3.Cross(vector, Vector3.up), vector); var leftDrawStart = (curSize - totalSize) / 2; pos += new Vector3(leftDrawStart, 0, 0); var s = new Vector3(totalSize * scaleHeight, 1f, curSize * scaleWidth); - var matrix = default(Matrix4x4); - matrix.SetTRS(pos + normalized * altOffset, q, s); - var layer = !useSkyboxLayer ? WorldCameraManager.WorldLayer : WorldCameraManager.WorldSkyboxLayer; + var matrix = Matrix4x4.TRS(pos + normalized * altOffset, q, s); + var layer = useSkyboxLayer ? WorldCameraManager.WorldSkyboxLayer : WorldCameraManager.WorldLayer; if (propertyBlock != null) Graphics.DrawMesh(MeshPool.plane10, matrix, material, layer, null, 0, propertyBlock); else Graphics.DrawMesh(MeshPool.plane10, matrix, material, layer); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/DamageDefCleave.cs b/Source/AllModdingComponents/JecsTools/DamageDefCleave.cs index c276d47c..2eacbd5d 100644 --- a/Source/AllModdingComponents/JecsTools/DamageDefCleave.cs +++ b/Source/AllModdingComponents/JecsTools/DamageDefCleave.cs @@ -9,4 +9,4 @@ public class DamageDefCleave : DamageDef public float cleaveFactor = 0.7f; //Damage factor for the cleave attack public int cleaveTargets = 0; //Number of bonus targets } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/DamageWorker_Cleave.cs b/Source/AllModdingComponents/JecsTools/DamageWorker_Cleave.cs index 3c198c2a..530be39f 100644 --- a/Source/AllModdingComponents/JecsTools/DamageWorker_Cleave.cs +++ b/Source/AllModdingComponents/JecsTools/DamageWorker_Cleave.cs @@ -21,46 +21,45 @@ public virtual int NumToCleave(Thing t) { if (t is Pawn p) { - if (p?.equipment?.Primary is ThingWithComps w) - return (int) w.GetStatValue(StatDefOf.Mass); - return (int) p.BodySize; + if (p.equipment?.Primary is ThingWithComps w) + return (int)w.GetStatValue(StatDefOf.Mass); + return (int)p.BodySize; } return 1; } return Def.cleaveTargets; } + private const int maxDist = 4; + public override DamageResult Apply(DamageInfo dinfo, Thing victim) { - float maxDist; - int cleaveAttacks; - if (!dinfo.InstantPermanentInjury) if (dinfo.Instigator != null) { - maxDist = 4; - cleaveAttacks = NumToCleave(dinfo.Instigator); + int cleaveAttacks = NumToCleave(dinfo.Instigator); if (victim?.PositionHeld != default(IntVec3)) for (var i = 0; i < 8; i++) { var c = victim.PositionHeld + GenAdj.AdjacentCells[i]; if (cleaveAttacks > 0 && (dinfo.Instigator.Position - c).LengthHorizontalSquared < maxDist) { - var pawnsInCell = c.GetThingList(victim.Map).FindAll(x => - x is Pawn && x != dinfo.Instigator && x?.Faction != dinfo.Instigator?.Faction); - for (var k = 0; cleaveAttacks > 0 && k < pawnsInCell.Count; k++) + var things = c.GetThingList(victim.Map); + for (var k = 0; cleaveAttacks > 0 && k < things.Count; k++) { - --cleaveAttacks; - var p = (Pawn) pawnsInCell[k]; - p.TakeDamage(new DamageInfo(Def.cleaveDamage, - (int) (dinfo.Amount * Def.cleaveFactor), Def.armorPenetration, -1, dinfo.Instigator)); + if (things[k] is Pawn pawn && pawn != dinfo.Instigator && + pawn.Faction != dinfo.Instigator.Faction) + { + --cleaveAttacks; + pawn.TakeDamage(new DamageInfo(Def.cleaveDamage, + (int)(dinfo.Amount * Def.cleaveFactor), Def.armorPenetration, -1, + dinfo.Instigator)); + } } } } } - DamageResult result; - result = base.Apply(dinfo, victim); - return result; + return base.Apply(dinfo, victim); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/GrappleUtility.cs b/Source/AllModdingComponents/JecsTools/GrappleUtility.cs index 835da523..084bd634 100644 --- a/Source/AllModdingComponents/JecsTools/GrappleUtility.cs +++ b/Source/AllModdingComponents/JecsTools/GrappleUtility.cs @@ -19,6 +19,10 @@ public enum GrappleType None } + public interface IGrappleModifier + { + float Resolve(Pawn pawn); + } public static bool TryGrapple(this Pawn grappler, Pawn victim, int grapplerBonusMod = 0, int victimBonusMod = 0) { @@ -27,8 +31,7 @@ public static bool TryGrapple(this Pawn grappler, Pawn victim, int grapplerBonus if (!CanGrapple(grappler, victim)) return false; - BodyPartRecord grapplingPart; - if (!TryGetGrapplingPart(grappler, out grapplingPart)) + if (!TryGetGrapplingPart(grappler, out var grapplingPart)) return false; //Special Case Handling @@ -41,9 +44,7 @@ public static bool TryGrapple(this Pawn grappler, Pawn victim, int grapplerBonus //Resolve Grapple Rolls //--------------------------------------------------------- - if (IsGrappleSuccessful(grappler, victim, grapplingPart, grapplerBonusMod, victimBonusMod)) - return true; - return false; + return IsGrappleSuccessful(grappler, victim, grapplingPart, grapplerBonusMod, victimBonusMod); } public static bool IsGrappleSuccessful(Pawn grappler, Pawn victim, BodyPartRecord grapplingPart, @@ -64,26 +65,24 @@ public static bool IsGrappleSuccessful(Pawn grappler, Pawn victim, BodyPartRecor modifierVictim += victimBonusMod; //Throw a mental warning - if (victim?.mindState is Pawn_MindState mind) + if (victim.mindState is Pawn_MindState mind) mind.Notify_DamageTaken(new DamageInfo(DamageDefOf.Bite, -1, 0f, -1, grappler)); //Determine success of grapples if (rollGrappler + modifierGrappler > rollVictim + modifierVictim) { MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, - rollGrappler + " + " + modifierGrappler + " = " + (rollGrappler + modifierGrappler) - + " vs " + - rollVictim + " + " + modifierVictim + " = " + (rollVictim + modifierVictim) - + " : " + "JTGrapple_Success".Translate(), -1f); + $"{rollGrappler} + {modifierGrappler} = {rollGrappler + modifierGrappler} vs " + + $"{rollVictim} + {modifierVictim} = {rollVictim + modifierVictim} : " + + "JTGrapple_Success".Translate()); TryMakeBattleLog(victim, grappler, grapplingPart); return true; } MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, - rollGrappler + " + " + modifierGrappler + " = " + (rollGrappler + modifierGrappler) - + " vs " + - rollVictim + " + " + modifierVictim + " = " + (rollVictim + modifierVictim) - + " : " + "JTGrapple_Failed".Translate(), -1f); + $"{rollGrappler} + {modifierGrappler} = {rollGrappler + modifierGrappler} vs " + + $"{rollVictim} + {modifierVictim} = {rollVictim + modifierVictim} : " + + "JTGrapple_Failed".Translate()); return false; } @@ -134,23 +133,32 @@ public static bool CanGrappleNoContest(Pawn grappler, Pawn victim, bool throwTex if (!victim.Awake()) { if (throwText) - MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, "JTGrapple_SleepingGrapple".Translate(), -1f); + MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, "JTGrapple_SleepingGrapple".Translate()); return true; } if (victim.Downed) { if (throwText) - MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, "JTGrapple_DownedGrapple".Translate(), -1f); + MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, "JTGrapple_DownedGrapple".Translate()); return true; } if (victim.IsPrisonerOfColony && RestraintsUtility.InRestraints(victim)) { if (throwText) - MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, "JTGrapple_PrisonerGrapple".Translate(), -1f); + MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, "JTGrapple_PrisonerGrapple".Translate()); return true; } + + // If grappler attempts to grapple an animal from the same faction as him, grapple always succeeds + if (victim.Faction != null && victim.Faction == grappler.Faction && victim.RaceProps.Animal) + { + if (throwText) + MoteMaker.ThrowText(grappler.DrawPos, grappler.Map, "JTGrapple_PetGrapple".Translate()); + return true; + } + return false; } @@ -162,14 +170,14 @@ public static bool CanGrappleNoContest(Pawn grappler, Pawn victim, bool throwTex /// public static bool TryGetGrapplingPart(Pawn grappler, out BodyPartRecord bodyPartRec) { - BodyPartRecord result = null; - if (grappler.health.hediffSet.GetNotMissingParts().ToList().FindAll(x => - x.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbSegment) || - x.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbCore)) is - List recs && !recs.NullOrEmpty()) - result = recs.RandomElement(); - bodyPartRec = result; - return bodyPartRec != null; + var grapplingParts = new List(); + foreach (var part in grappler.health.hediffSet.GetNotMissingParts()) + { + if (part.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbSegment) || + part.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbCore)) + grapplingParts.Add(part); + } + return grapplingParts.TryRandomElement(out bodyPartRec); } /// @@ -228,9 +236,52 @@ public static void ResolveModifiers(Pawn grappler, Pawn victim, ref float modifi /// public static float ResolveToolModifier(Pawn pawn) { - return pawn?.def?.tools?.Max(x => x.power) ?? 0; + var maxPower = 0f; + var tools = pawn.def?.tools; + if (tools != null) + { + foreach (var tool in tools) + { + if (maxPower < tool.power) + maxPower = tool.power; + } + } + return maxPower; } + private class CompAbilityUserGrappleModifier : IGrappleModifier + { + // This checks that the CompAbilityUser type is available - if this fails, this GrappleModifier won't be used. + static CompAbilityUserGrappleModifier() => typeof(CompAbilityUser).ToString(); + + public float Resolve(Pawn pawn) + { + var result = 0f; + var abilityUsers = pawn.GetCompAbilityUsers(); + foreach (var a in abilityUsers) + result += a.GrappleModifier; + return result; + } + } + + private static readonly IGrappleModifier[] additionalModifiers = GenTypes.AllTypes + .Select(type => + { + if (type.IsAbstract || !typeof(IGrappleModifier).IsAssignableFrom(type)) + return null; + try + { + return (IGrappleModifier)Activator.CreateInstance(type); + } + catch + { + Log.Message($"{typeof(GrappleUtility).FullName}: couldn't load or create instance of {type} - skipping"); + return null; + } + }) + .Where(x => x != null) + .ToArray(); + /// /// Checks humanoid characters for ability user components and their modifiers. /// @@ -239,19 +290,8 @@ public static float ResolveToolModifier(Pawn pawn) public static float ResolveAdditionalModifiers(Pawn pawn) { var result = 0f; - try - { - ((Action) (() => - { - var abilityUsers = pawn.GetComps(); - foreach (var a in abilityUsers) - result += a.GrappleModifier; - })).Invoke(); - } - catch (TypeLoadException) - { - } - + for (var i = 0; i < additionalModifiers.Length; i++) + result += additionalModifiers[i].Resolve(pawn); return result; } @@ -263,24 +303,14 @@ public static float ResolveAdditionalModifiers(Pawn pawn) /// public static GrappleType ResolveGrappleType(Pawn grappler, Pawn victim) { - var grappleType = GrappleType.None; - - if (grappler.RaceProps.Humanlike && - victim.RaceProps.Humanlike) - grappleType = GrappleType.Humanoid; - - else if (grappler.RaceProps.Humanlike && - victim.RaceProps.Animal) - grappleType = GrappleType.HumanoidXAnimal; - - else if (grappler.RaceProps.Animal && - victim.RaceProps.Humanlike) - grappleType = GrappleType.AnimalXHumanoid; - + if (grappler.RaceProps.Humanlike && victim.RaceProps.Humanlike) + return GrappleType.Humanoid; + else if (grappler.RaceProps.Humanlike && victim.RaceProps.Animal) + return GrappleType.HumanoidXAnimal; + else if (grappler.RaceProps.Animal && victim.RaceProps.Humanlike) + return GrappleType.AnimalXHumanoid; else - grappleType = GrappleType.AnimalXAnimal; - - return grappleType; + return GrappleType.AnimalXAnimal; } /// @@ -293,19 +323,9 @@ public static GrappleType ResolveGrappleType(Pawn grappler, Pawn victim) /// public static bool TryMakeBattleLog(Pawn victim, Pawn grappler, BodyPartRecord grapplingPart) { - try - { - Find.BattleLog.Add( - new BattleLogEntry_StateTransition(victim, - RulePackDef.Named("JT_GrappleSuccess"), grappler, null, grapplingPart) - ); - return true; - } - catch (Exception e) - { - Log.Warning("TruMakeBattleLog Failed Due To :: " + e); - } - return false; + Find.BattleLog.Add( + new BattleLogEntry_StateTransition(victim, MiscDefOf.JT_GrappleSuccess, grappler, null, grapplingPart)); + return true; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HarmonyPatches.cs b/Source/AllModdingComponents/JecsTools/HarmonyPatches.cs index b724ea2c..08fa21cc 100644 --- a/Source/AllModdingComponents/JecsTools/HarmonyPatches.cs +++ b/Source/AllModdingComponents/JecsTools/HarmonyPatches.cs @@ -1,132 +1,114 @@ -using System; +//#define DEBUGLOG + +using System; +using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; -using AbilityUser; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Emit; using HarmonyLib; using RimWorld; using UnityEngine; using Verse; -using Verse.AI; -using Verse.Sound; namespace JecsTools { [StaticConstructorOnStartup] public static partial class HarmonyPatches { - public static bool DEBUGMODE = false; - //For alternating fire on some weapons public static Dictionary AlternatingFireTracker = new Dictionary(); - // Verse.Pawn_HealthTracker - public static bool StopPreApplyDamageCheck; - - public static int? tempDamageAmount = null; - public static int? tempDamageAbsorbed = null; + public static float? tempDamageAmount = null; + public static float? tempDamageAbsorbed = null; static HarmonyPatches() { - // Changed by Tad : New Harmony Instance creation required - var instance = new Harmony("jecstools.jecrell.main"); - //Allow fortitude to soak damage + var harmony = new Harmony("jecstools.jecrell.main"); var type = typeof(HarmonyPatches); //Debug Line //------------ -// instance.Patch( -// AccessTools.Method(typeof(PawnGroupKindWorker_Normal), -// nameof(PawnGroupKindWorker_Normal.MinPointsToGenerateAnything)), -// new HarmonyMethod(type, nameof(MinPointsTest)), null); + //harmony.Patch(AccessTools.Method(typeof(PawnGroupKindWorker_Normal), nameof(PawnGroupKindWorker_Normal.MinPointsToGenerateAnything)), + // prefix: new HarmonyMethod(type, nameof(MinPointsTest))); //------------ - //Adds HediffCompProperties_DamageSoak checks to damage - instance.Patch(AccessTools.Method(typeof(Pawn_HealthTracker), nameof(Pawn_HealthTracker.PreApplyDamage)), - new HarmonyMethod(type, nameof(PreApplyDamage_PrePatch)), null); + //Applies hediff-based extra damage to melee attacks. + harmony.Patch(typeof(Verb_MeleeAttackDamage).FindIteratorMethod("DamageInfosToApply"), + transpiler: new HarmonyMethod(type, nameof(Verb_MeleeAttackDamage_DamageInfosToApply_Transpiler))); + //Allow fortitude (HediffComp_DamageSoak) to soak damage + //Adds HediffCompProperties_DamageSoak checks to damage + harmony.Patch(AccessTools.Method(typeof(Pawn_HealthTracker), nameof(Pawn_HealthTracker.PreApplyDamage)), + prefix: new HarmonyMethod(type, nameof(PreApplyDamage_PrePatch))); //Applies cached armor damage and absorption - instance.Patch(AccessTools.Method(typeof(ArmorUtility), "ApplyArmor"), - new HarmonyMethod(type, nameof(ApplyProperDamage)), null); - + harmony.Patch(AccessTools.Method(typeof(ArmorUtility), "ApplyArmor"), + prefix: new HarmonyMethod(type, nameof(Pre_ApplyArmor))); //Applies damage soak motes - instance.Patch(AccessTools.Method(typeof(ArmorUtility), nameof(ArmorUtility.GetPostArmorDamage)), null, - new HarmonyMethod(type, nameof(Post_GetPostArmorDamage))); + harmony.Patch(AccessTools.Method(typeof(ArmorUtility), nameof(ArmorUtility.GetPostArmorDamage)), + postfix: new HarmonyMethod(type, nameof(Post_GetPostArmorDamage))); + + //Applies knockback + harmony.Patch(AccessTools.Method(typeof(Pawn), nameof(Pawn.PreApplyDamage)), + prefix: new HarmonyMethod(type, nameof(Pawn_PreApplyDamage_Prefix)) { priority = Priority.High }, + postfix: new HarmonyMethod(type, nameof(Pawn_PreApplyDamage_Postfix)) { priority = Priority.Low }); + harmony.Patch(AccessTools.Method(typeof(Scenario), nameof(Scenario.TickScenario)), + postfix: new HarmonyMethod(type, nameof(Scenario_TickScenario_Postfix))); - //Allows for adding additional HediffSets when characters spawn using the StartWithHediff class. - instance.Patch( - AccessTools.Method(typeof(PawnGenerator), "GeneratePawn", new[] {typeof(PawnGenerationRequest)}), null, - new HarmonyMethod(type, nameof(Post_GeneratePawn))); + //Allows for adding additional HediffSets when characters spawn using the StartWithHediff class. + harmony.Patch(AccessTools.Method(typeof(PawnGenerator), nameof(PawnGenerator.GeneratePawn), + new[] { typeof(PawnGenerationRequest) }), + postfix: new HarmonyMethod(type, nameof(Post_GeneratePawn))); //Checks apparel that uses the ApparelExtension - instance.Patch(AccessTools.Method(typeof(ApparelUtility), nameof(ApparelUtility.CanWearTogether)), null, - new HarmonyMethod(type, nameof(Post_CanWearTogether))); + harmony.Patch(AccessTools.Method(typeof(ApparelUtility), nameof(ApparelUtility.CanWearTogether)), + postfix: new HarmonyMethod(type, nameof(Post_CanWearTogether))); - //Handles special cases of faction disturbances - instance.Patch(AccessTools.Method(typeof(Faction), nameof(Faction.Notify_MemberDied)), - new HarmonyMethod(type, nameof(Notify_MemberDied)), null); + //Handles cases where gendered apparel swaps out for individual genders. + harmony.Patch(AccessTools.Method(typeof(PawnApparelGenerator), nameof(PawnApparelGenerator.GenerateStartingApparelFor)), + postfix: new HarmonyMethod(type, nameof(GenerateStartingApparelFor_PostFix))); - //Handles FactionSettings extension to allow for fun effects when factions arrive. - instance.Patch( - AccessTools.Method(typeof(PawnGroupMakerUtility), nameof(PawnGroupMakerUtility.GeneratePawns)), null, - new HarmonyMethod(type, nameof(GeneratePawns)), null); + //BuildingExtension prevents some things from wiping other things when spawned/constructing/blueprinted. + harmony.Patch(AccessTools.Method(typeof(GenSpawn), nameof(GenSpawn.SpawningWipes)), + postfix: new HarmonyMethod(type, nameof(SpawningWipes_PostFix))); + harmony.Patch(AccessTools.Method(typeof(GenConstruct), nameof(GenConstruct.CanPlaceBlueprintOver)), + postfix: new HarmonyMethod(type, nameof(CanPlaceBlueprintOver_PostFix))); - //Handles cases where gendered apparel swaps out for individual genders. - instance.Patch( - AccessTools.Method(typeof(PawnApparelGenerator), - nameof(PawnApparelGenerator.GenerateStartingApparelFor)), null, - new HarmonyMethod(type, nameof(GenerateStartingApparelFor_PostFix)), null); - - //BuildingExtension prevents some things from wiping other things when spawned. - instance.Patch( - AccessTools.Method(typeof(GenSpawn), - nameof(GenSpawn.SpawningWipes)), null, - new HarmonyMethod(type, nameof(SpawningWipes_PostFix)), null); - //BuildingExtension is also checked here to make sure things do not block construction. - instance.Patch( - AccessTools.Method(typeof(GenConstruct), - nameof(GenConstruct.BlocksConstruction)), null, - new HarmonyMethod(type, nameof(BlocksConstruction_PostFix)), null); - // - instance.Patch( - AccessTools.Method(typeof(Projectile), - "CanHit"), null, - new HarmonyMethod(type, nameof(CanHit_PostFix)), null); - instance.Patch( - AccessTools.Method(typeof(Verb), - "CanHitCellFromCellIgnoringRange"), - new HarmonyMethod(type, nameof(CanHitCellFromCellIgnoringRange_Prefix)), null); + harmony.Patch(AccessTools.Method(typeof(Projectile), "CanHit"), + postfix: new HarmonyMethod(type, nameof(CanHit_PostFix))); + harmony.Patch(AccessTools.Method(typeof(Verb), "CanHitCellFromCellIgnoringRange"), + prefix: new HarmonyMethod(type, nameof(CanHitCellFromCellIgnoringRange_Prefix))); + + //Improve DamageInfo.ToString for debugging purposes. + harmony.Patch(AccessTools.Method(typeof(DamageInfo), nameof(DamageInfo.ToString)), + postfix: new HarmonyMethod(type, nameof(DamageInfo_ToString_Postfix))); //optionally use "CutoutComplex" shader for apparel that wants it - //instance.Patch(AccessTools.Method(typeof(ApparelGraphicRecordGetter), nameof(ApparelGraphicRecordGetter.TryGetGraphicApparel)), null, null, new HarmonyMethod(type, nameof(CutOutComplexApparel_Transpiler))); + //harmony.Patch(AccessTools.Method(typeof(ApparelGraphicRecordGetter), nameof(ApparelGraphicRecordGetter.TryGetGraphicApparel)), + // transpiler: new HarmonyMethod(type, nameof(CutOutComplexApparel_Transpiler))); } - public static void DebugMessage(string s) + [Conditional("DEBUGLOG")] + private static void DebugMessage(string s) { - if (DEBUGMODE) - Log.Message(s); + Log.Message(s); } //Added B19, Oct 2019 //ProjectileExtension check //Allows a bullet to pass through walls when fired. - public static bool CanHitCellFromCellIgnoringRange_Prefix(Verb __instance, IntVec3 sourceSq, IntVec3 targetLoc, bool includeCorners, ref bool __result) + public static bool CanHitCellFromCellIgnoringRange_Prefix(Verb __instance, ref bool __result) { - try + if (__instance.EquipmentCompSource?.PrimaryVerb?.verbProps?.defaultProjectile?.GetProjectileExtension() is ProjectileExtension ext) { - - if (__instance?.EquipmentCompSource?.PrimaryVerb?.verbProps?.defaultProjectile is ThingDef proj && - proj?.HasModExtension() == true && - proj?.GetModExtension() is ProjectileExtension ext) + if (ext.passesWalls) { - if (ext.passesWalls) - __result = true; - return false; + // TODO: While this does bypass the line-of-sight checks (and should it really bypass all LOS checks?), + // this also bypasses non-LOS checks, which doesn't look right. + __result = true; } - - } - catch (Exception e) - { - + return false; } return true; } @@ -136,313 +118,357 @@ public static bool CanHitCellFromCellIgnoringRange_Prefix(Verb __instance, IntVe //Ignores all structures as part of objects that disallow being fired through. public static void CanHit_PostFix(Projectile __instance, Thing thing, ref bool __result) { - if (!__result && __instance?.def?.HasModExtension() == true && - __instance.def.GetModExtension() is ProjectileExtension ext) + // TODO: This patch looks pointless since it can only change __result from false to ... false. + if (__result == false && __instance.def?.GetProjectileExtension() is ProjectileExtension ext) { - //Mods will often have their own walls, so we cannot do a def check for - //ThingDefOf.Wall - //Most "walls" should either be in the structure category or be able to hold walls. - if (thing?.def?.designationCategory == DesignationCategoryDefOf.Structure || - thing?.def?.holdsRoof == true) + if (ext.passesWalls) { - if (ext.passesWalls) + //Mods will often have their own walls, so we cannot do a def check for ThingDefOf.Wall + //Most "walls" should either be in the structure category or be able to hold walls. + // TODO: In RW 1.3+, it seems like BuildingProperties.isPlaceOverableWall indicates whether something is a "wall", + // but it may be better to just look at ThingDef.Fillage/fillPercent instead, + // or maybe use PlaceWorker_OnTopOfWalls's heuristic of checking whether the defName contains "Wall"? + if (thing?.def is ThingDef def && (def.designationCategory == DesignationCategoryDefOf.Structure || def.holdsRoof)) { __result = false; return; } } - } } - public static void BlocksConstruction_PostFix(Thing constructible, Thing t, ref bool __result) + public static void SpawningWipes_PostFix(BuildableDef newEntDef, BuildableDef oldEntDef, ref bool __result) { - ThingDef thingDef = constructible.def; - ThingDef thingDef2 = t.def; - if (thingDef == null || thingDef2 == null) - return; - if (thingDef.HasModExtension() || thingDef2.HasModExtension()) + // If SpawningWipes is already returning true, don't need to do anything. + if (__result == false && newEntDef is ThingDef newDef && oldEntDef is ThingDef oldDef) { - BuildableDef buildableDef = GenConstruct.BuiltDefOf(thingDef); - BuildableDef buildableDef2 = GenConstruct.BuiltDefOf(thingDef2); - __result = ShouldWipe(buildableDef, buildableDef2, t.PositionHeld, t.MapHeld); + if (HasSharedWipeCategory(newDef, oldDef)) + __result = true; } } - public static void SpawningWipes_PostFix(BuildableDef newEntDef, BuildableDef oldEntDef, ref bool __result) + public static void CanPlaceBlueprintOver_PostFix(BuildableDef newDef, ThingDef oldDef, ref bool __result) { - ThingDef thingDef = newEntDef as ThingDef; - ThingDef thingDef2 = oldEntDef as ThingDef; - if (thingDef == null || thingDef2 == null) - return; - if (thingDef.HasModExtension() || thingDef2.HasModExtension()) + // If CanPlaceBlueprintOver is already returning false, don't need to do anything. + if (__result == true && newDef is ThingDef thingDef) { - BuildableDef buildableDef = GenConstruct.BuiltDefOf(thingDef); - BuildableDef buildableDef2 = GenConstruct.BuiltDefOf(thingDef2); - __result = ShouldWipe(buildableDef, buildableDef2, IntVec3.Invalid, null); + if (HasSharedWipeCategory(thingDef, oldDef)) + __result = false; } } - private static bool ShouldWipe(BuildableDef newEntDef, BuildableDef oldEntDef, IntVec3 loc, Map map) + private static bool HasSharedWipeCategory(ThingDef newDef, ThingDef oldDef) { - if (map == null || loc == null || !loc.IsValid) + static HashSet GetWipeCategories(ThingDef thingDef) { - var buildingExtensionA = newEntDef?.GetModExtension(); - var buildingExtensionB = oldEntDef?.GetModExtension(); - if (buildingExtensionB == null && buildingExtensionA == null) - { - //Log.Message("Both null"); - return true; - } + var buildingExtension = GenConstruct.BuiltDefOf(thingDef)?.GetBuildingExtension(); + if (buildingExtension == null) + return null; + var wipeCategorySet = buildingExtension.WipeCategories; + return wipeCategorySet == null || wipeCategorySet.Count == 0 ? null : wipeCategorySet; + } - //Log.Message("A: " + newEntDef.label); - //Log.Message("B: " + oldEntDef.label); - if (buildingExtensionA != null && buildingExtensionB == null && - buildingExtensionA.wipeCategories?.Count > 0) + var wipeCategoriesA = GetWipeCategories(newDef); + DebugMessage($"{newDef} wipeCategoriesA: {wipeCategoriesA.ToStringSafeEnumerable()}"); + var wipeCategoriesB = GetWipeCategories(oldDef); + DebugMessage($"{oldDef} wipeCategoriesB: {wipeCategoriesB.ToStringSafeEnumerable()}"); + if (wipeCategoriesB == null && wipeCategoriesA == null) + { + DebugMessage("both wipeCategories null => false"); + return false; + } + else if (wipeCategoriesA != null && wipeCategoriesB == null) + { + DebugMessage("wipeCategoriesB null => false"); + return false; + } + else if (wipeCategoriesB != null && wipeCategoriesA == null) + { + DebugMessage("wipeCategoriesA null => false"); + return false; + } + else + { + foreach (var strB in wipeCategoriesB) { - //Log.Message("B null"); - - return false; + if (wipeCategoriesA.Contains(strB)) + { + DebugMessage($"found shared wipeCategories ({strB}) => true"); + return true; + } } + DebugMessage("no shared wipeCategories => false"); + return false; + } + } - if (buildingExtensionB != null && buildingExtensionA == null && - buildingExtensionB.wipeCategories?.Count > 0) - { - //Log.Message("A null"); + //public static void MinPointsTest(PawnGroupMaker groupMaker) + //{ + // if (!(groupMaker?.options?.Count > 0)) + // { + // Log.Message("No options available."); + // return; + // } + // foreach (var x in groupMaker.options) + // { + // Log.Message(x.kind.defName + " " + x.kind.isFighter.ToString() + " " + x.Cost); + // } + //} - return false; + //PawnApparelGenerator + public static void GenerateStartingApparelFor_PostFix(Pawn pawn) + { + var allWornApparel = pawn.apparel?.WornApparel; + if (allWornApparel.NullOrEmpty()) + return; + List<(Apparel, Apparel)> swapEntries = null; + foreach (var wornApparel in allWornApparel) + { + if (wornApparel.def?.GetApparelExtension()?.swapCondition is SwapCondition sc && + sc.swapWhenGender is Gender gen && + gen != Gender.None && gen == pawn.gender) + { + var swapApparel = (Apparel)ThingMaker.MakeThing(sc.swapTo, wornApparel.Stuff); + // Avoid modifying WornApparel during its enumeration by doing the swaps afterwards. + swapEntries ??= new List<(Apparel worn, Apparel swap)>(); + swapEntries.Add((wornApparel, swapApparel)); } - - if (buildingExtensionA != null && buildingExtensionB != null && - buildingExtensionA.wipeCategories?.Count > 0 && - buildingExtensionB.wipeCategories?.Count > 0) + } + if (swapEntries != null) + { + foreach (var (wornApparel, swapApparel) in swapEntries) { - var hashes = new HashSet(); - foreach (var str in buildingExtensionA.wipeCategories) - hashes.Add(str); - foreach (var strB in buildingExtensionB.wipeCategories) + PawnGenerator.PostProcessGeneratedGear(swapApparel, pawn); + if (ApparelUtility.HasPartsToWear(pawn, swapApparel.def)) { - if (!hashes.Contains(strB)) continue; - //Log.Message("ShouldWipe"); - return true; + pawn.apparel.Wear(swapApparel, false); + DebugMessage($"apparel generation for {pawn}: swapped from {wornApparel} to {swapApparel}"); } + wornApparel.Destroy(); + DebugMessage($"apparel generation for {pawn}: destroyed old {wornApparel}"); } - - return true; } - - var locThings = loc.GetThingList(map); - for (var index = 0; index < locThings.Count; index++) - { - var thing = locThings[index]; - if (thing.def is ThingDef thingDef && - ShouldWipe(newEntDef, GenConstruct.BuiltDefOf(thingDef), IntVec3.Invalid, null)) - return true; - } - - return true; } - public static void MinPointsTest(PawnGroupKindWorker_Normal __instance, PawnGroupMaker groupMaker) + /// + /// Using the new ApparelExtension, we can have a string based apparel check. + /// + public static void Post_CanWearTogether(ThingDef A, ThingDef B, BodyDef body, ref bool __result) { -// if (groupMaker?.options?.Count == null || -// groupMaker.options.Count <= 0) -// { -// Log.Message("No options available."); -// } -// foreach (var x in groupMaker.options) -// { -// Log.Message(x.kind.defName + " " + x.kind.isFighter.ToString() + " " + x.Cost); -// } - } - + static HashSet GetCoverage(ThingDef thingDef) + { + var coverage = thingDef.GetApparelExtension()?.Coverage; + return coverage == null || coverage.Count == 0 ? null : coverage; + } - //PawnApparelGenerator - public static void GenerateStartingApparelFor_PostFix(Pawn pawn, PawnGenerationRequest request) - { - var swappables = pawn?.apparel?.WornApparel?.FindAll(x => x.def.HasModExtension()); - if (swappables == null || swappables?.Count <= 0) return; - var destroyables = new HashSet(); - foreach (var swap in swappables) + if (A == null || B == null || body == null || __result == true) + return; + var coverageA = GetCoverage(A); + var coverageB = GetCoverage(B); + if (coverageA != null && coverageB != null) { - if (swap.def?.GetModExtension()?.swapCondition is SwapCondition sc && - sc?.swapWhenGender is Gender gen && - gen != Gender.None && gen == pawn.gender) + foreach (var coverageItem in coverageB) { - Apparel apparel = (Apparel) ThingMaker.MakeThing(sc.swapTo, swap.Stuff); - PawnGenerator.PostProcessGeneratedGear(apparel, pawn); - if (ApparelUtility.HasPartsToWear(pawn, apparel.def)) + if (coverageA.Contains(coverageItem)) { - pawn.apparel.Wear(apparel, false); + __result = false; + break; } - - destroyables.Add(swap); } } - - if (destroyables == null || destroyables?.Count <= 0) return; - while (destroyables?.Count > 0) + else if ((coverageA != null && coverageB == null) || (coverageA == null && coverageB != null)) { - var first = destroyables.First(); - first.Destroy(); - destroyables.Remove(first); + __result = true; } } -// -// //PawnApparelGenerator -// public static void IsNaked(Gender gender, ref bool __result) -// { -// if (!__result) return; -// var aps = Traverse.Create(AccessTools.TypeByName("PossibleApparelSet")).Field("aps").GetValue>(); -// if (aps == null || aps?.Count <= 0) return; -// for (int i = 0; i < aps.Count; i++) -// { -// if (!aps[i].thing.HasModExtension()) -// continue; -// var aExt = aps[i].thing.GetModExtension(); -// if (aExt.forcedGender == Gender.None) -// continue; -// if (aExt.forcedGender == gender) continue; -// __result = false; -// return; -// } -// } - - public static Faction lastPhoneAideFaction = null; - public static int lastPhoneAideTick = 0; - - //public class PawnGroupMakerUtility - //{ - public static void GeneratePawns(PawnGroupMakerParms parms, - bool warnOnZeroResults, ref IEnumerable __result) + public static void Post_GeneratePawn(Pawn __result) { - if (__result?.Count() > 0 && - parms.faction.def.GetModExtension() is FactionSettings settings) + var hediffGiverSets = __result?.def?.race?.hediffGiverSets; + if (hediffGiverSets != null) { - settings.entrySoundDef?.PlayOneShotOnCamera(); + foreach (var hediffGiverSet in hediffGiverSets) + { + foreach (var hediffGiver in hediffGiverSet.hediffGivers) + { + if (hediffGiver is HediffGiver_StartWithHediff hediffGiverStartWithHediff) + { + hediffGiverStartWithHediff.GiveHediff(__result); + // TODO: Should this really only use the first found HediffGiver_StartWithHediff? + return; + } + } + } } } - //Faction - public static bool Notify_MemberDied(Faction __instance, Pawn member, DamageInfo? dinfo, bool wasWorldPawn, - Map map) + public static IEnumerable Verb_MeleeAttackDamage_DamageInfosToApply_Transpiler( + IEnumerable instructions, MethodBase method, ILGenerator ilGen) { - //Log.Message("1"); - if (member?.Faction == null) return true; - if (!dinfo.HasValue) return true; - if (!(dinfo.Value.Instigator is Pawn instigator)) return true; - //Log.Message("2"); - - - var notLeader = __instance?.leader != member; - //Log.Message("3"); - - var notPlayerKiller = instigator?.Faction != Faction.OfPlayerSilentFail; - //Log.Message("4"); - - //var notAttackingPlayer = member.LastAttackedTarget.IsValid && member?.LastAttackedTarget.Thing is Pawn p && p?.Faction != Faction.OfPlayerSilentFail; - //Log.Message("5"); - - var inTime = lastPhoneAideTick < (Find.TickManager?.TicksGame + GenDate.HoursPerDay ?? 0); - //Log.Message("6"); - - - var isPhoneFaction = __instance == lastPhoneAideFaction; - //Log.Message("7"); - - - if (isPhoneFaction && - inTime && - notLeader && - notPlayerKiller) // && - //notAttackingPlayer) + // Transforms following: + // if (tool != null && tool.extraMeleeDamages != null) + // { + // foreach (ExtraDamage extraMeleeDamage in tool.extraMeleeDamages) + // ... + // } + // into: + // var extraDamages = DamageInfosToApply_ExtraDamages(this); + // if (extraDamages != null) + // { + // foreach (ExtraDamage extraMeleeDamage in extraDamages) + // ... + // } + // Note: We're actually modifying an iterator method, which delegates all of its logic to a compiler-generated + // IEnumerator class with a convoluted FSM with the primary logic in the MoveNext method. + // The logic surrounding yields within loops is especially complex, so it's best to just modify what's being + // looped over; in this case, that's replacing the tool.extraMeleeDamages with our own enumerable + // (along with adjusting the null check conditionals). + + var fieldof_Verb_tool = AccessTools.Field(typeof(Verb), nameof(Verb.tool)); + var fieldof_Tool_extraMeleeDamages = AccessTools.Field(typeof(Tool), nameof(Tool.extraMeleeDamages)); + var methodof_List_GetEnumerator = + AccessTools.Method(typeof(List), nameof(IEnumerable.GetEnumerator)); + var instructionList = instructions.AsList(); + var locals = new Locals(method, ilGen); + + var extraDamagesVar = locals.DeclareLocal>(); + + var verbToolFieldNullCheckIndex = instructionList.FindSequenceIndex( + locals.IsLdloc, + instr => instr.Is(OpCodes.Ldfld, fieldof_Verb_tool), + instr => instr.IsBrfalse()); + var toolExtraDamagesIndex = instructionList.FindIndex(verbToolFieldNullCheckIndex + 3, // after above 3 predicates + instr => instr.Is(OpCodes.Ldfld, fieldof_Tool_extraMeleeDamages)); + var verbToolFieldIndex = verbToolFieldNullCheckIndex + 1; + instructionList.SafeReplaceRange(verbToolFieldIndex, toolExtraDamagesIndex + 1 - verbToolFieldIndex, new[] { - return false; - } + new CodeInstruction(OpCodes.Call, + AccessTools.Method(typeof(HarmonyPatches), nameof(DamageInfosToApply_ExtraDamages))), + extraDamagesVar.ToStloc(), + extraDamagesVar.ToLdloc(), + }); + + var verbToolExtraDamagesEnumeratorIndex = instructionList.FindSequenceIndex(verbToolFieldIndex, + locals.IsLdloc, + instr => instr.Is(OpCodes.Ldfld, fieldof_Verb_tool), + instr => instr.Is(OpCodes.Ldfld, fieldof_Tool_extraMeleeDamages), + instr => instr.Calls(methodof_List_GetEnumerator)); + instructionList.SafeReplaceRange(verbToolExtraDamagesEnumeratorIndex, 4, new[] // after above 4 predicates + { + extraDamagesVar.ToLdloc(), + new CodeInstruction(OpCodes.Call, + AccessTools.Method(typeof(List), nameof(IEnumerable.GetEnumerator))), + }); - return true; + return instructionList; } - /// - /// Using the new ApparelExtension, we can have a string based apparel check. - /// - /// - /// - /// - /// - public static void Post_CanWearTogether(ThingDef A, ThingDef B, BodyDef body, ref bool __result) + [ThreadStatic] + private static Dictionary<(Tool, Pawn), List> extraDamageCache; + + // In the above transpiler, this replaces tool.extraMeleeDamages as the foreach loop enumeration target in + // Verb_MeleeAttackDamage.DamageInfosToApply. + // This must return a List rather than IEnumerator since Tool.extraMeleeDamages is a list. + // Specifically, the compiler-generated code calls List.GetEnumerator(), stores it in a + // List.Enumerator field in the internal iterator class (necessary for the FSM to work), then explicitly + // calls List.Enumerator methods/properties in multiple iterator class methods along with an initobj + // rather than ldnull for clearing it (since List.Enumerator is a struct). Essentially, it would be + // difficult to replace all this with IEnumerator versions in the above transpiler, we just have this + // method return the same type as Tool.extraMeleeDamages: List. + // If either tool.extraMeleeDamages and CasterPawn.GetHediffComp().Props.ExtraDamages + // are null, we can simply return the other, since both are lists. However, if both are non-null, we cannot simply + // return Enumerable.Concat of them both; we need to create a new list that contains both. Since list creation and + // getting the hediff extra damages are both relatively expensive operations, we utilize a cache. + // This cache is ThreadStatic to be optimized for single-threaded usage yet safe for multithreaded usage. + private static List DamageInfosToApply_ExtraDamages(Verb_MeleeAttackDamage verb) { - try + extraDamageCache ??= new Dictionary<(Tool, Pawn), List>(); + var key = (verb.tool, verb.CasterPawn); + if (!extraDamageCache.TryGetValue(key, out var extraDamages)) { - if (A == null || B == null || body == null || __result == true) return; - var aHasExt = A.HasModExtension(); - var bHasExt = B.HasModExtension(); - if (aHasExt && bHasExt) - { - var aExt = A.GetModExtension(); - var bExt = B.GetModExtension(); - var check = new HashSet(); - if (aExt.coverage?.Count > 0) - for (int i = 0; i < aExt.coverage.Count; i++) - { - var coverageItem = aExt.coverage[i].ToLowerInvariant(); - if (!check.Contains(coverageItem)) - check.Add(coverageItem); - else - { - Log.Warning("JecsTools :: ApparelExtension :: Warning:: " + A.label + - " has multiple of the same tags."); - return; - } - } - - if (bExt.coverage?.Count > 0) - for (int j = 0; j < bExt.coverage.Count; j++) - { - var coverageItem = bExt.coverage[j].ToLowerInvariant(); - if (!check.Contains(coverageItem)) - check.Add(coverageItem); - else - { - __result = false; - break; - } - } - } - else if ((aHasExt && !bHasExt) || (!aHasExt && bHasExt)) + var toolExtraDamages = key.tool?.extraMeleeDamages; + var hediffExtraDamages = key.CasterPawn.GetHediffComp()?.Props?.ExtraDamages; + if (toolExtraDamages == null) + extraDamages = hediffExtraDamages; + else if (hediffExtraDamages == null) + extraDamages = toolExtraDamages; + else { - __result = true; + extraDamages = new List(toolExtraDamages.Count + hediffExtraDamages.Count); + extraDamages.AddRange(toolExtraDamages); + extraDamages.AddRange(hediffExtraDamages); } + DebugMessage($"DamageInfosToApply_ExtraDamages({verb}) => caching for {key}: {extraDamages.Join(ToString)}"); + extraDamageCache[key] = extraDamages; } - catch (Exception e) - { - Log.Message(e.ToString()); - } + return extraDamages; } - public static void Post_GeneratePawn(PawnGenerationRequest request, ref Pawn __result) + private static string ToString(ExtraDamage ed) { - var hediffGiverSet = __result?.def?.race?.hediffGiverSets?.FirstOrDefault( - x => x.hediffGivers.Any(y => y is HediffGiver_StartWithHediff)); - if (hediffGiverSet == null) return; + return $"(def={ed.def}, amount={ed.amount}, armorPenetration={ed.armorPenetration}, chance={ed.chance})"; + } - if (hediffGiverSet.hediffGivers.FirstOrDefault(x => x is HediffGiver_StartWithHediff) is - HediffGiver_StartWithHediff hediffGiver) + // ArmorUtility patches: + // These are a workaround for PreApplyDamage_PrePatch changes to the dinfo struct not being saved, due to + // Pawn_HealthTracker.PreApplyDamage dinfo parameter being passed by value (PreApplyDamage_PrePatch has it passed + // by reference, but this only affects the patch; Pawn_HealthTracker.PreApplyDamage still has it passed by value). + // Incidentally, these patches have another purpose: it allows other Pawn_HealthTracker.PreApplyDamage code like + // Apparel.CheckPreAbsorbDamage (like shield belts), various pawn-specific notifications affecting pawn behavior, + // and other mod's patches on the method to run, some of which could affect dinfo.Amount and absorbed flag. + // Indeed, the choice of prefix patching Pawn_HealthTracker.PreApplyDamage rather than a Pawn.PreApplyDamage prefix + // or a Pawn_HealthTracker.PreApplyDamage postfix is likely a compromise to allow as much change to dinfo as + // possible yet still apply damage soaks before shield belt absorption. + // Pawn_HealthTracker.PreApplyDamage notification specifics: if it runs (no ThingComp.PostPreApplyDamage sets + // absorbed flag), prisoner guilt, AI updates, and current danger are triggered. If no Apparel.CheckPreAbsorbDamage + // sets the absorbed flag, stun effects, pawn thought/memory, and tale recording are triggered. + // XXX: I do not think this patch is reliable because: + // 1) It's not guaranteed to run under certain conditions (e.g. if dinfo.IgnoreArmor) when it should. + // 2) dinfo.Amount can be divided into multiple DamageInfos under certain conditions (bomb/flame damage), + // which this doesn't take into account. + // 3) It assumes that all new damage amount since our PreApplyDamage_PrePatch ran should be damage soaked + // (as long as this patch runs, e.g. not absorbed, etc.), by setting the damage amount back to tempDamageAmount, + // the final damage amount recorded in PreApplyDamage_PrePatch, even if no damage soaks exist + // (see TODO in PreApplyDamage_PrePatch). + // 4) If damage amount decreased yet still non-zero since our PreApplyDamage_PrePatch ran, this patch will + // increase the damage amount back to tempDamageAmount, which is the total opposite of damage soaking. + // 5) The relationship of PreApplyDamage_PrePatch and this patch with respect to tempDamageAmount is fragile, + // especially since (1) and tempDamageAmount not always being set in PreApplyDamage_PrePatch. + // If another mod happens to use ArmorUtility without going through PreApplyDamage, this scheme will break. + // TODO: + // If we want to retain damage soaking before shield belt absorption: + // Instead of this patch, postfix patch (highest patch priority) Pawn.PreApplyDamage to update the original + // dinfo struct with any changes from PreApplyDamage_PrePatch. Make PreApplyDamage_PrePatch patch with lowest + // patch priority so that it runs right before Pawn_HealthTracker.PreApplyDamage. This should ensure that there + // no other changes to dinfo in between PreApplyDamage_PrePatch and the new Pawn.PreApplyDamage postfix patch + // that should've been tracked. tempDamageAmount is still needed to to transfer the damage amount info between + // these patches. + // If we're fine with damage soaks applying after shield belt absorption: + // Simplify into a single Pawn.PreApplyDamage postfix patch. + public static void Pre_ApplyArmor(ref float damAmount, Pawn pawn) + { + if (tempDamageAmount != null && damAmount > 0f) { - hediffGiver.GiveHediff(__result); + var damageDiff = Mathf.Max(damAmount - tempDamageAmount.Value, 0f); + var newDamAmount = GenMath.RoundRandom(tempDamageAmount.Value); + DebugMessage($"c6c:: ApplyArmor prefix on {pawn}: tempDamageAmount {tempDamageAmount} => null, damAmount {damAmount} => {newDamAmount}"); + damAmount = newDamAmount; + tempDamageAmount = null; + if (damageDiff > 0f) + tempDamageAbsorbed = damageDiff; } } - //ArmorUtility - public static void Post_GetPostArmorDamage(Pawn pawn, float amount, BodyPartRecord part, DamageDef damageDef, - ref float __result) + // XXX: Damage soak mote is already emitted in PreApplyDamage_ApplyDamageSoakers, so this leads to a misleading + // redundant soak mote. Worse, if the damage amount actually changes between PreApplyDamage_ApplyDamageSoakers + // and Pre_ApplyArmor, leading to a tempDamageAbsorbed that's different from PreApplyDamage_ApplyDamageSoakers's + // totalSoakedDamage, this is even more misleading. + public static void Post_GetPostArmorDamage(Pawn pawn) { if (tempDamageAbsorbed != null) { - var hasFortitudeHediffs = - pawn?.health?.hediffSet?.hediffs?.Any(x => x.TryGetComp() != null); - if (hasFortitudeHediffs ?? false) + DebugMessage($"c6c:: GetPostArmorDamage postfix on {pawn}: tempDamageAbsorbed {tempDamageAbsorbed}"); + if (pawn.GetHediffComp() != null) { DamageSoakedMote(pawn, tempDamageAbsorbed.Value); } @@ -451,385 +477,268 @@ public static void Post_GetPostArmorDamage(Pawn pawn, float amount, BodyPartReco } } - public static void ApplyProperDamage(ref float damAmount, float armorRating, Thing armorThing, - DamageDef damageDef, Pawn pawn, ref bool metalArmor) - { - if (tempDamageAmount != null && damAmount > 0) - { - float damageDiff = Mathf.Clamp(damAmount - tempDamageAmount.Value, 0, damAmount); - - //Log.Message("Apply amount original: " + damAmount); - //Log.Message("Apply amount modified: " + tempDamageAmount.Value); - damAmount = GenMath.RoundRandom(tempDamageAmount.Value); - tempDamageAmount = null; - if (damageDiff > 0) - tempDamageAbsorbed = GenMath.RoundRandom(damageDiff); - } - } - - public static bool PreApplyDamage_PrePatch(Pawn_HealthTracker __instance, ref DamageInfo dinfo, - out bool absorbed) + public static bool PreApplyDamage_PrePatch(Pawn ___pawn, ref DamageInfo dinfo, out bool absorbed) { - - DebugMessage($"c6c:: === Enter Harmony Prefix --- PreApplyDamage_ApplyExtraDamages ==="); - - var pawn = (Pawn) AccessTools.Field(typeof(Pawn_HealthTracker), "pawn").GetValue(__instance); - if (pawn != null && !StopPreApplyDamageCheck) + DebugMessage($"c6c:: === Enter Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); + if (___pawn != null) { - DebugMessage("c6c:: Pawn exists. StopPreApplyDamageCheck: False"); - if (pawn?.health?.hediffSet?.hediffs != null && pawn?.health?.hediffSet?.hediffs?.Count > 0) + DebugMessage("c6c:: Pawn exists."); + var hediffSet = ___pawn.health.hediffSet; + if (hediffSet.hediffs.Count > 0) { - DebugMessage("c6c:: Pawn has health."); - //A list will stack. - var fortitudeHediffs = - pawn?.health?.hediffSet?.hediffs?.FindAll(x => x.TryGetComp() != null); - if (!fortitudeHediffs.NullOrEmpty()) + DebugMessage("c6c:: Pawn has hediffs."); + // See above ArmorUtility comments. + if (PreApplyDamage_ApplyDamageSoakers(ref dinfo, hediffSet, ___pawn)) { - DebugMessage("c6c:: Pawn has Damage Soak hediff."); - try - { - if (PreApplyDamage_ApplyDamageSoakers(ref dinfo, out absorbed, fortitudeHediffs, pawn)) - { - DebugMessage($"c6c:: === Exit Harmony Prefix --- PreApplyDamage_ApplyExtraDamages ==="); - return false; - } - } - catch (NullReferenceException e) - { - DebugMessage($"c6c:: Soak failure:: {e.Message}"); - } + DebugMessage($"c6c:: === Exit Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); + absorbed = true; + return false; } - - if (dinfo.Weapon is ThingDef weaponDef && !weaponDef.IsRangedWeapon) - if (dinfo.Instigator is Pawn instigator) - { - DebugMessage("c6c:: Pawn has non-ranged weapon."); - try - { - if (PreApplyDamage_ApplyExtraDamages(dinfo, out absorbed, instigator, pawn)) return false; - } - catch (NullReferenceException e) - { - DebugMessage($"c6c:: Extra damages failure:: {e.Message}"); - } - - try - { - PreApplyDamage_ApplyKnockback(instigator, pawn); - } - catch (NullReferenceException e) - { - DebugMessage($"c6c:: Apply knockback failure:: {e.Message}"); - } - } } } - tempDamageAmount = (int) dinfo.Amount; + // TODO: tempDamageAmount shouldn't be set if there are no damage soaks. + tempDamageAmount = dinfo.Amount; + DebugMessage($"c6c:: tempDamageAmount <= {tempDamageAmount}"); absorbed = false; - DebugMessage($"c6c:: === Exit Harmony Prefix --- PreApplyDamage_ApplyExtraDamages ==="); + DebugMessage($"c6c:: === Exit Harmony Prefix --- PreApplyDamage_PrePatch for {___pawn} and {dinfo} ==="); return true; } - private static void PreApplyDamage_ApplyKnockback(Pawn instigator, Pawn pawn) + // Stores original dinfo.Amount in __state, that below Pawn_PreApplyDamage_Postfix can access. + public static void Pawn_PreApplyDamage_Prefix(ref DamageInfo dinfo, ref float __state) { - var knockbackHediff = - instigator?.health?.hediffSet?.hediffs.FirstOrDefault(y => - y.TryGetComp() != null); - var knocker = knockbackHediff?.TryGetComp(); - if (knocker != null) - if (knocker?.Props?.knockbackChance >= Rand.Value) - { - if (knocker.Props.explosiveKnockback) - { - var explosion = (Explosion) GenSpawn.Spawn(ThingDefOf.Explosion, - instigator.PositionHeld, instigator.MapHeld); - explosion.radius = knocker.Props.explosionSize; - explosion.damType = knocker.Props.explosionDmg; - explosion.instigator = instigator; - explosion.damAmount = 0; - explosion.weapon = null; - explosion.projectile = null; - explosion.preExplosionSpawnThingDef = null; - explosion.preExplosionSpawnChance = 0f; - explosion.preExplosionSpawnThingCount = 1; - explosion.postExplosionSpawnThingDef = null; - explosion.postExplosionSpawnChance = 0f; - explosion.postExplosionSpawnThingCount = 1; - explosion.applyDamageToExplosionCellsNeighbors = false; - explosion.chanceToStartFire = 0f; - explosion.damageFalloff = false; // dealMoreDamageAtCenter = false; - explosion.StartExplosion(null,null); - } - - if (pawn != instigator && !pawn.Dead && !pawn.Downed && pawn.Spawned) - { - if (knocker.Props.stunChance > -1 && knocker.Props.stunChance >= Rand.Value) - pawn.stances.stunner.StunFor(knocker.Props.stunTicks, instigator); - PushEffect(instigator, pawn, knocker.Props.knockDistance.RandomInRange, - true); - } - } + __state = dinfo.Amount; } - private static bool PreApplyDamage_ApplyExtraDamages(DamageInfo dinfo, out bool absorbed, Pawn instigator, Pawn pawn) + // This should happen after all modifications to dinfo and any possible setting of absorbed flag, + // i.e. after all ThingComp.PostPreApplyDamage and Apparel.CheckPreAbsorbDamage (shield belts). + public static void Pawn_PreApplyDamage_Postfix(Pawn __instance, ref DamageInfo dinfo, ref bool absorbed, + float __state) { - - DebugMessage($"c6c:: --- Enter PreApplyDamage_ApplyExtraDamages ---"); - var extraDamagesHediff = - instigator.health.hediffSet.hediffs.FirstOrDefault(y => - y.TryGetComp() != null); - DebugMessage("c6c:: ExtraDamagesHediff variable assigned."); - var damages = extraDamagesHediff?.TryGetComp(); - DebugMessage("c6c:: Damages variable assigned."); - if (damages?.Props != null && damages.Props.ExtraDamages is List extraDamages) + if (dinfo.Weapon is ThingDef weaponDef && !weaponDef.IsRangedWeapon && + dinfo.Instigator is Pawn instigator) { - DebugMessage("c6c:: Extra damages list exists."); - StopPreApplyDamageCheck = true; - foreach (var dmg in extraDamages) + DebugMessage($"c6c:: Instigator using non-ranged weapon: {dinfo}"); + var hediffCompKnockback = instigator.GetHediffComp(); + if (hediffCompKnockback != null) { - DebugMessage($"c6c:: Extra Damage: {dmg.def.defName}"); - if (pawn == null || !pawn.Spawned || pawn.Dead) - { - DebugMessage($"c6c:: Pawn is null, unspawned, or dead. Aborting."); - absorbed = false; - StopPreApplyDamageCheck = false; - return true; - } - - //BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = new BattleLogEntry_MeleeCombat(dinfo.Def.combatLogRules, true, - // instigator, pawn, ImplementOwnerTypeDefOf.Bodypart, (dinfo.Weapon != null) ? dinfo.Weapon.label : dinfo.Def.label ); - //DebugMessage($"c6c:: MeleeCombat Log generated."); - //DamageWorker.DamageResult damageResult = new DamageWorker.DamageResult(); - //DebugMessage($"c6c:: MeleeCombat Damage Result generated."); - //damageResult = pawn.TakeDamage(new DamageInfo(dmg.def, dmg.amount, dmg.armorPenetration, -1, instigator)); - pawn.TakeDamage(new DamageInfo(dmg.def, dmg.amount, dmg.armorPenetration, -1, instigator)); - DebugMessage($"c6c:: MeleeCombat TakeDamage set to -- Def:{dmg.def.defName} Amt:{dmg.amount} ArmorPen:{dmg.armorPenetration}."); - //try - //{ - // damageResult.AssociateWithLog(battleLogEntry_MeleeCombat); - // DebugMessage($"c6c:: MeleeCombat Damage associated with log."); - //} - //catch (Exception e) - //{ - // DebugMessage($"c6c:: Failed to associate log: {e.Message}"); - //} - //battleLogEntry_MeleeCombat.def = LogEntryDefOf.MeleeAttack; - //DebugMessage($"c6c:: MeleeCombat Log def set as MeleeAttack."); - //Find.BattleLog.Add(battleLogEntry_MeleeCombat); - //DebugMessage($"c6c:: MeleeCombat Log added to battle log."); - + // Hack to prevent multiple knockbacks occurring due to multiple damage infos (e.g. extra damage) for same instigator+target: + // prevent knockback if tick hasn't passed since last knockback for instigator+target pair. + // This requires a (instigator+target)=>tick cache, which is cleared after every tick via Scenario_TickScenario_Postfix. + var pair = new Pair(instigator, __instance); + var ticks = Find.TickManager.TicksGame; + if (knockbackLastTicks.TryGetValue(pair, out var lastTicks) && lastTicks == ticks) + return; + knockbackLastTicks[pair] = ticks; + hediffCompKnockback.ApplyKnockback(__instance, + damageAbsorbedPercent: absorbed ? 1f : 1f - Mathf.Clamp01(dinfo.Amount / __state)); } - - StopPreApplyDamageCheck = false; } - DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyExtraDamages ---"); - absorbed = false; - return false; } - private static bool PreApplyDamage_ApplyDamageSoakers(ref DamageInfo dinfo, out bool absorbed, - List fortitudeHediffs, - Pawn pawn) + public static void Scenario_TickScenario_Postfix() { + knockbackLastTicks.Clear(); + } - DebugMessage($"c6c:: --- Enter PreApplyDamage_ApplyDamageSoakers ---"); - var soakedDamage = 0; - foreach (var fortitudeHediff in fortitudeHediffs) + private static readonly ConcurrentDictionary, int> knockbackLastTicks = + new ConcurrentDictionary, int>(); + + private static bool PreApplyDamage_ApplyDamageSoakers(ref DamageInfo dinfo, HediffSet hediffSet, Pawn pawn) + { + // Multiple damage soak hediff comps stack. + DebugMessage($"c6c:: --- Enter PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); + var damageDef = dinfo.Def; + var totalSoakedDamage = 0f; + foreach (var hediffComp in hediffSet.GetAllComps()) { + if (!(hediffComp is HediffComp_DamageSoak damageSoakComp)) + continue; DebugMessage("c6c:: Soak Damage Hediff checked."); - var soaker = fortitudeHediff.TryGetComp(); - var soakSetting = soaker?.Props; - if (soakSetting == null) { + var soakProps = damageSoakComp.Props; + if (soakProps == null) + { DebugMessage("c6c:: Soak Damage Hediff has no damage soak XML properties."); - continue; } - if (soakSetting.settings.NullOrEmpty()) + continue; + } + if (soakProps.settings.NullOrEmpty()) { DebugMessage("c6c:: Soak Damage Hediff has no damage soak settings."); - //Null, here, means "all damage types" - //So Null should pass this check. - if (soakSetting.damageType != null && soakSetting.damageType != dinfo.Def) + // Null, here, means "all damage types", so null should pass this check. + if (soakProps.damageType != null && soakProps.damageType != damageDef) { - DebugMessage($"c6c:: {dinfo.Def.label.CapitalizeFirst()} is not in soak settings."); - continue; + DebugMessage($"c6c:: {damageDef.label.CapitalizeFirst()} is not in soak settings."); + continue; } - - if (!soakSetting.damageTypesToExclude.NullOrEmpty() && - soakSetting.damageTypesToExclude.Contains(dinfo.Def)) + if (soakProps.damageTypesToExclude != null && + soakProps.damageTypesToExclude.Contains(damageDef)) { - DebugMessage($"c6c:: {dinfo.Def.label.CapitalizeFirst()} is to be excluded from damage soak."); + DebugMessage($"c6c:: {damageDef.label.CapitalizeFirst()} is to be excluded from damage soak."); continue; } - var dmgAmount = Mathf.Clamp(dinfo.Amount - soakSetting.damageToSoak, 0, dinfo.Amount); - DebugMessage($"c6c:: Min: 0, Max: {dinfo.Amount}. Calc: {dinfo.Amount} - {soakSetting.damageToSoak}."); - soakedDamage += (int)Mathf.Min(dinfo.Amount, soakSetting.damageToSoak); - DebugMessage($"c6c:: Soaked Running Total: {soakedDamage}"); + + var dmgAmount = dinfo.Amount; + var soakedDamage = Mathf.Min(soakProps.damageToSoak, dmgAmount); + DebugMessage($"c6c:: Soaked: Min({soakProps.damageToSoak}, {dinfo.Amount}) => {soakedDamage}"); + dmgAmount -= soakedDamage; + DebugMessage($"c6c:: Damage amount: {dinfo.Amount} - {soakedDamage} => {dmgAmount}"); + totalSoakedDamage += soakedDamage; + DebugMessage($"c6c:: Total soaked: {totalSoakedDamage}"); dinfo.SetAmount(dmgAmount); - DebugMessage($"c6c:: Result: {dinfo.Amount}"); + if (dinfo.Amount > 0) { DebugMessage($"c6c:: More damage exists. Continuing check for soakers."); continue; } - DamageSoakedMote(pawn, soakedDamage); + + DamageSoakedMote(pawn, totalSoakedDamage); DebugMessage($"c6c:: Damage absorbed."); - DebugMessage($"c6c:: FINAL RESULT -- Soak: {soakedDamage} Damage: {dinfo.Amount}."); - DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers ---"); - absorbed = true; + DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); + DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); return true; } else { DebugMessage("c6c:: Soak Damage Hediff has damage soak settings."); - foreach (var soakSettings in soaker.Props.settings) + foreach (var soakSettings in soakProps.settings) { - DamageInfo info = dinfo; - - DebugMessage($"c6c:: Hediff Damage: {info.Def.defName}"); + DebugMessage($"c6c:: Hediff Damage: {damageDef}"); if (soakSettings.damageType != null) - DebugMessage($"c6c:: Soak Type: {soakSettings.damageType.defName}"); + DebugMessage($"c6c:: Soak Type: {soakSettings.damageType}"); else DebugMessage($"c6c:: Soak Type: All"); //Null, here, means "all damage types" //So Null should pass this check. - if (soakSettings.damageType != null && soakSettings.damageType != info.Def) + if (soakSettings.damageType != null && soakSettings.damageType != damageDef) { DebugMessage($"c6c:: No match. No soak."); continue; } - // ReSharper disable once PossibleNullReferenceException + // This variable tracks whether the damage should be excluded by a damageTypesToExclude + // rule for breaking out of a nested for loop without using goto + bool damageExcluded = false; if (!soakSettings.damageTypesToExclude.NullOrEmpty()) { DebugMessage($"c6c:: Damage Soak Exlusions: "); foreach (var exclusion in soakSettings.damageTypesToExclude) { - DebugMessage($"c6c:: {exclusion.defName}"); - if (exclusion == info.Def) + DebugMessage($"c6c:: {exclusion}"); + if (exclusion == damageDef) { DebugMessage($"c6c:: Exclusion match. Damage soak aborted."); - continue; + damageExcluded = true; + break; } } + if (damageExcluded) + continue; } - var dmgAmount = Mathf.Clamp(dinfo.Amount - soakSettings.damageToSoak, 0, dinfo.Amount); - DebugMessage($"c6c:: Min: 0, Max: {dinfo.Amount}. Calc: {dinfo.Amount} - {soakSettings.damageToSoak}."); - soakedDamage += (int)Mathf.Min(soakSettings.damageToSoak, dinfo.Amount); + var dmgAmount = dinfo.Amount; + var soakedDamage = Mathf.Min(soakSettings.damageToSoak, dmgAmount); + DebugMessage($"c6c:: Soaked: Min({soakSettings.damageToSoak}, {dinfo.Amount}) => {soakedDamage}"); + dmgAmount -= soakedDamage; + DebugMessage($"c6c:: Damage amount: {dinfo.Amount} - {soakedDamage} => {dmgAmount}"); + totalSoakedDamage += soakedDamage; + DebugMessage($"c6c:: Total soaked: {totalSoakedDamage}"); dinfo.SetAmount(dmgAmount); - DebugMessage($"c6c:: Result: {dinfo.Amount}"); - DebugMessage($"c6c:: Total soaked: {soakedDamage}"); + if (dinfo.Amount > 0) { DebugMessage($"c6c:: Unsoaked damage remains. Checking for more soakers."); continue; } - DamageSoakedMote(pawn, soakedDamage); + + DamageSoakedMote(pawn, totalSoakedDamage); DebugMessage($"c6c:: Damage absorbed."); - DebugMessage($"c6c:: FINAL RESULT -- Soak: {soakedDamage} Damage: {dinfo.Amount}."); - DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers ---"); - absorbed = true; + DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); + DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); return true; } } } - if (soakedDamage > 0) + if (totalSoakedDamage > 0) { - DamageSoakedMote(pawn, soakedDamage); - DebugMessage($"c6c:: FINAL RESULT -- Soak: {soakedDamage} Damage: {dinfo.Amount}."); + DamageSoakedMote(pawn, totalSoakedDamage); + DebugMessage($"c6c:: FINAL RESULT -- Total soaked: {totalSoakedDamage}, damage amount: {dinfo.Amount}."); } - DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers ---"); - absorbed = false; + DebugMessage($"c6c:: --- Exit PreApplyDamage_ApplyDamageSoakers for {pawn} and {dinfo} ---"); return false; } - private static void DamageSoakedMote(Pawn pawn, int soakedDamage) + private static void DamageSoakedMote(Pawn pawn, float soakedDamage) { - if (soakedDamage > 0 && pawn != null && pawn.Spawned && pawn.MapHeld != null && + if (soakedDamage > 0f && pawn != null && pawn.Spawned && pawn.MapHeld != null && pawn.DrawPos is Vector3 drawVecDos && drawVecDos.InBounds(pawn.MapHeld)) - MoteMaker.ThrowText(drawVecDos, pawn.MapHeld, - "JT_DamageSoaked".Translate(soakedDamage), -1f); + { + // To avoid any rounding bias, use RoundRandom for converting int to float. + var roundedSoakedDamage = GenMath.RoundRandom(soakedDamage); + DebugMessage($"c6c:: DamageSoakedMote for {pawn}: {soakedDamage} rounded to {roundedSoakedDamage}"); + MoteMaker.ThrowText(drawVecDos, pawn.MapHeld, "JT_DamageSoaked".Translate(roundedSoakedDamage)); + } } + // Not sure if another mod is using this, so obsoleting it rather than deleting it. + [Obsolete] public static Vector3 PushResult(Thing Caster, Thing thingToPush, int pushDist, out bool collision) { - var origin = thingToPush.TrueCenter(); - var result = origin; - var collisionResult = false; - for (var i = 1; i <= pushDist; i++) - { - var pushDistX = i; - var pushDistZ = i; - if (origin.x < Caster.TrueCenter().x) pushDistX = -pushDistX; - if (origin.z < Caster.TrueCenter().z) pushDistZ = -pushDistZ; - var tempNewLoc = new Vector3(origin.x + pushDistX, 0f, origin.z + pushDistZ); - if (tempNewLoc.ToIntVec3().Standable(Caster.Map)) - { - result = tempNewLoc; - } - else - { - if (thingToPush is Pawn) - { - //target.TakeDamage(new DamageInfo(DamageDefOf.Blunt, Rand.Range(3, 6), -1, null, null, null)); - collisionResult = true; - break; - } - } - } - - collision = collisionResult; - return result; + return HediffComp_Knockback.PushResult(Caster, thingToPush, pushDist, out var _, out collision); } + // Not sure if another mod is using this, so obsoleting it rather than deleting it. + [Obsolete] public static void PushEffect(Thing Caster, Thing target, int distance, bool damageOnCollision = false) { - LongEventHandler.QueueLongEvent(delegate + HediffComp_Knockback.PushEffect(Caster, target, damageAbsorbedPercent: 0f, new HediffCompProperties_Knockback { - if (target != null && target is Pawn p && p.Spawned && !p.Downed && !p.Dead && p?.MapHeld != null) - { - bool applyDamage; - var loc = PushResult(Caster, target, distance, out applyDamage); - //if (((Pawn)target).RaceProps.Humanlike) ((Pawn)target).needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("PJ_ThoughtPush"), null); - var flyingObject = (FlyingObject) GenSpawn.Spawn(ThingDef.Named("JT_FlyingObject"), p.PositionHeld, - p.MapHeld); - if (applyDamage && damageOnCollision) - flyingObject.Launch(Caster, new LocalTargetInfo(loc.ToIntVec3()), target, - new DamageInfo(DamageDefOf.Blunt, Rand.Range(8, 10))); - else flyingObject.Launch(Caster, new LocalTargetInfo(loc.ToIntVec3()), target); - } - }, "PushingCharacter", false, null); + knockDistance = new FloatRange(distance, distance), + knockDistanceAbsorbedPercentCurve = HediffComp_Knockback.AlwaysOneCurve, + knockDistanceMassCurve = HediffComp_Knockback.AlwaysOneCurve, + knockImpactDamage = damageOnCollision ? new FloatRange(8f, 10f) : default, + knockImpactDamageDistancePercentCurve = HediffComp_Knockback.AlwaysOneCurve, + knockImpactDamageType = DamageDefOf.Blunt, + }); + } + + public static string DamageInfo_ToString_Postfix(string result, ref DamageInfo __instance) + { + var insertIndex = result.IndexOf(", angle="); + return result.Insert(insertIndex, $", hitPart={__instance.HitPart.ToStringSafe()}, " + + $"weapon={__instance.Weapon.ToStringSafe()}, armorPenetration={__instance.ArmorPenetrationInt}"); } //added 2018/12/13 - Mehni. //Uses CutoutComplex shader for apparel that wants it. - // private static IEnumerable CutOutComplexApparel_Transpiler(IEnumerable instructions) - // { - // MethodInfo shader = AccessTools.Method(typeof(HarmonyPatches), nameof(HarmonyPatches.Shader)); - // FieldInfo cutOut = AccessTools.Field(typeof(ShaderDatabase), nameof(ShaderDatabase.Cutout)); - // - // foreach (CodeInstruction codeInstruction in instructions) - // { - // if (codeInstruction.opcode == OpCodes.Ldsfld && codeInstruction.operand == cutOut) - // { - // yield return new CodeInstruction(OpCodes.Ldarg_0); //apparel - // yield return new CodeInstruction(OpCodes.Call, shader); //return shader type - // continue; //skip instruction. - // } - // yield return codeInstruction; - // } - // } - - // private static Shader Shader (Apparel apparel) - // { - // if (apparel.def.graphicData.shaderType.Shader == ShaderDatabase.CutoutComplex) - // return ShaderDatabase.CutoutComplex; - // - // return ShaderDatabase.Cutout; - // } + //private static IEnumerable CutOutComplexApparel_Transpiler(IEnumerable instructions) + //{ + // MethodInfo shader = AccessTools.Method(typeof(HarmonyPatches), nameof(HarmonyPatches.Shader)); + // FieldInfo cutOut = AccessTools.Field(typeof(ShaderDatabase), nameof(ShaderDatabase.Cutout)); + + // foreach (CodeInstruction codeInstruction in instructions) + // { + // if (codeInstruction.opcode == OpCodes.Ldsfld && codeInstruction.operand == cutOut) + // { + // yield return new CodeInstruction(OpCodes.Ldarg_0); //apparel + // yield return new CodeInstruction(OpCodes.Call, shader); //return shader type + // continue; //skip instruction. + // } + // yield return codeInstruction; + // } + //} + + //private static Shader Shader(Apparel apparel) + //{ + // if (apparel.def.graphicData.shaderType.Shader == ShaderDatabase.CutoutComplex) + // return ShaderDatabase.CutoutComplex; + + // return ShaderDatabase.Cutout; + //} } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HarmonyPatches_GUI.cs b/Source/AllModdingComponents/JecsTools/HarmonyPatches_GUI.cs index 8dd2ba05..0869cefc 100644 --- a/Source/AllModdingComponents/JecsTools/HarmonyPatches_GUI.cs +++ b/Source/AllModdingComponents/JecsTools/HarmonyPatches_GUI.cs @@ -1,92 +1,83 @@ using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; using System.Reflection.Emit; using HarmonyLib; using RimWorld; -using UnityEngine; using Verse; -using Verse.Sound; namespace JecsTools { + // TODO: This doesn't seem to be used - remove? public static partial class HarmonyPatches { - private static bool drawButtonsPatched; - - public static void GUIPatches(Harmony harmony) + public static void GUIPatches() { - // Changed by Tad : New Harmony Instance creation required - var instance = new Harmony("jecstools.jecrell.main-gui"); - - //Allow fortitude to soak damage + var harmony = new Harmony("jecstools.jecrell.main-gui"); var type = typeof(HarmonyPatches); - //harmony.Patch(AccessTools.Method(typeof(DebugWindowsOpener), "DrawButtons"), null, - // null, new HarmonyMethod(type, nameof(DrawAdditionalButtons))); - instance.Patch(AccessTools.Method(typeof(MoteMaker), "MakeMoodThoughtBubble"), null, - new HarmonyMethod(type, nameof(ToggleMoodThoughtBubble)), - null); + + harmony.Patch(AccessTools.Method(typeof(MoteMaker), nameof(MoteMaker.MakeMoodThoughtBubble)), + postfix: new HarmonyMethod(type, nameof(ToggleMoodThoughtBubble))); } - public static void ToggleMoodThoughtBubble(Pawn pawn, Thought thought, ref MoteBubble __result) + public static void ToggleMoodThoughtBubble(ref MoteBubble __result) { - if (!bubblesEnabled) __result = null; + if (!bubblesEnabled) + __result = null; } -// -// public static IEnumerable DrawAdditionalButtons(IEnumerable instructions) { -// var instructionsArr = instructions.ToArray(); -// var widgetRowIndex = TryGetLocalIndexOfConstructedObject(instructionsArr, typeof(WidgetRow)); -// foreach (var inst in instructionsArr) { -// if (!drawButtonsPatched && widgetRowIndex >= 0 && inst.opcode == OpCodes.Bne_Un) { -// yield return new CodeInstruction(OpCodes.Ldloc, widgetRowIndex); -// yield return new CodeInstruction(OpCodes.Call, ((Action)HarmonyPatches.DrawDebugToolbarButton).Method); -// drawButtonsPatched = true; -// } -// yield return inst; -// } -// } - - private static int TryGetLocalIndexOfConstructedObject(IEnumerable instructions, Type constructedType, Type[] constructorParams = null) { + + private static int TryGetLocalIndexOfConstructedObject(IEnumerable instructions, Type constructedType, Type[] constructorParams = null) + { var constructor = AccessTools.Constructor(constructedType, constructorParams); - int localIndex = -1; - if (constructor == null) { + var localIndex = -1; + if (constructor == null) + { Log.Message($"Could not reflect constructor for type {constructedType}: {Environment.StackTrace}"); return localIndex; } CodeInstruction prevInstruction = null; - foreach (var inst in instructions) { - if (prevInstruction != null && prevInstruction.opcode == OpCodes.Newobj && constructor.Equals(prevInstruction.operand)) { - if (inst.opcode == OpCodes.Stloc_0) { + foreach (var inst in instructions) + { + if (prevInstruction != null && prevInstruction.opcode == OpCodes.Newobj && constructor.Equals(prevInstruction.operand)) + { + if (inst.opcode == OpCodes.Stloc_0) + { localIndex = 0; - } else if (inst.opcode == OpCodes.Stloc_1) { + } + else if (inst.opcode == OpCodes.Stloc_1) + { localIndex = 1; - } else if (inst.opcode == OpCodes.Stloc_2) { + } + else if (inst.opcode == OpCodes.Stloc_2) + { localIndex = 2; - } else if (inst.opcode == OpCodes.Stloc_3) { + } + else if (inst.opcode == OpCodes.Stloc_3) + { localIndex = 3; - } else if (inst.opcode == OpCodes.Stloc && inst.operand is int) { + } + else if (inst.opcode == OpCodes.Stloc && inst.operand is int) + { localIndex = (int)inst.operand; } - if (localIndex >= 0) break; + if (localIndex >= 0) + break; } prevInstruction = inst; } - if (localIndex < 0) { + if (localIndex < 0) + { Log.Message($"Could not determine local index for constructed type {constructedType}: {Environment.StackTrace}"); } return localIndex; } private static bool bubblesEnabled = true; - internal static void DrawDebugToolbarButton(WidgetRow widgetRow) { + internal static void DrawDebugToolbarButton(WidgetRow widgetRow) + { if (Current.ProgramState == ProgramState.Playing) { widgetRow.ToggleableIcon(ref bubblesEnabled, TexButton.quickstartIconTex, "Toggle thought/speech bubbles.", null, null); } } - - - } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffCompDamageOverTime.cs b/Source/AllModdingComponents/JecsTools/HediffCompDamageOverTime.cs index e93fea88..6da62794 100644 --- a/Source/AllModdingComponents/JecsTools/HediffCompDamageOverTime.cs +++ b/Source/AllModdingComponents/JecsTools/HediffCompDamageOverTime.cs @@ -21,8 +21,7 @@ public override void CompPostTick(ref float severityAdjustment) public DamageInfo GetDamageInfo() { - return new DamageInfo(Props.cycleDamage, Props.cycleDamageAmt, Props.armorPenetration, -1, parent.pawn, parent.Part, null, - DamageInfo.SourceCategory.ThingOrUnknown); + return new DamageInfo(Props.cycleDamage, Props.cycleDamageAmt, Props.armorPenetration, -1, parent.pawn, parent.Part); } public virtual void MakeDamage() @@ -41,7 +40,7 @@ public override string CompDebugString() public override void CompExposeData() { base.CompExposeData(); - Scribe_Values.Look(ref ticksUntilDamage, "ticksUntilDamage", -1); + Scribe_Values.Look(ref ticksUntilDamage, nameof(ticksUntilDamage), -1); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageOverTime.cs b/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageOverTime.cs index ad3f53ec..4d7307b0 100644 --- a/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageOverTime.cs +++ b/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageOverTime.cs @@ -16,4 +16,4 @@ public HediffCompProperties_DamageOverTime() compClass = typeof(HediffCompDamageOverTime); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageSoak.cs b/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageSoak.cs index 12cf9eff..5ab7e915 100644 --- a/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageSoak.cs +++ b/Source/AllModdingComponents/JecsTools/HediffCompProperties_DamageSoak.cs @@ -10,17 +10,17 @@ public class DamageSoakSettings public List damageTypesToExclude = null; //E.g. vampires have a general damage immunity, but not to //sunlight and burning damages. } - + public class HediffCompProperties_DamageSoak : HediffCompProperties { public List settings = null; public int damageToSoak = 1; public DamageDef damageType = null; public List damageTypesToExclude = null; //E.g. vampires have a general damage immunity, but not to - + public HediffCompProperties_DamageSoak() { compClass = typeof(HediffComp_DamageSoak); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffCompProperties_ExtraMeleeDamages.cs b/Source/AllModdingComponents/JecsTools/HediffCompProperties_ExtraMeleeDamages.cs index f7d957bb..2f994d0b 100644 --- a/Source/AllModdingComponents/JecsTools/HediffCompProperties_ExtraMeleeDamages.cs +++ b/Source/AllModdingComponents/JecsTools/HediffCompProperties_ExtraMeleeDamages.cs @@ -5,10 +5,22 @@ namespace JecsTools { public class HediffCompProperties_ExtraMeleeDamages : HediffCompProperties { - public List ExtraDamages = new List(); + public List ExtraDamages = new List(); + public HediffCompProperties_ExtraMeleeDamages() { compClass = typeof(HediffComp_ExtraMeleeDamages); } + + public override IEnumerable ConfigErrors(HediffDef parentDef) + { + foreach (var error in base.ConfigErrors(parentDef)) + yield return error; + for (var i = 0; i < ExtraDamages.Count; i++) + { + if (ExtraDamages[i]?.def == null) + yield return $"{nameof(ExtraDamages)}[{i}] is null or has null def"; + } + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffCompProperties_Knockback.cs b/Source/AllModdingComponents/JecsTools/HediffCompProperties_Knockback.cs index 35b3e02b..8318a515 100644 --- a/Source/AllModdingComponents/JecsTools/HediffCompProperties_Knockback.cs +++ b/Source/AllModdingComponents/JecsTools/HediffCompProperties_Knockback.cs @@ -1,22 +1,103 @@ -using RimWorld; +using System; +using System.Collections.Generic; +using RimWorld; using Verse; namespace JecsTools { public class HediffCompProperties_Knockback : HediffCompProperties { - public DamageDef explosionDmg = DefDatabase.GetNamedSilentFail("Stun"); - public float explosionSize = 2f; + [Obsolete("Use explosiveProps != null")] public bool explosiveKnockback = false; + [Obsolete("Use explosiveProps.explosiveDamageType")] + public DamageDef explosionDmg; + [Obsolete("Use explosiveProps.explosiveRadius")] + public float explosionSize = 2f; + // Note: following CompProperties_Explosive are ignored: + // explodeOnKilled + // explosiveExpandPerStackcount + // explosiveExpandPerFuel + // startWickOnDamageTaken + // startWickHitPointsPercent + // wickTicks + // wickScale (also never used in vanilla) + // chanceNeverExplodeFromDamage + // destroyThingOnExplosionSize + // requiredDamageTypeToExplode + // countdownTicks + public CompProperties_Explosive explosiveProps; + public float knockbackChance = 0.2f; - public SoundDef knockbackSound = DefDatabase.GetNamedSilentFail("Pawn_Melee_Punch_HitPawn"); - public IntRange knockDistance = new IntRange(2, 3); - public float stunChance = -1f; + public float knockbackSpeed = 30f; + public SoundDef knockbackSound; + public ThoughtDef knockbackThought; + + // original distance = knockDistance.RandomInRange + // damage absorbed % (before armor calculations) = + // if absorbed flag set, 100% + // if absorbed flag unset, 100% - (post-PreApplyDamage dinfo.Amount / pre-PreApplyDamage dinfo.Amount) + // distance = + // original distance * + // knockbackDistanceDamagePercentCurve.Evaluate(damage absorbed %) + // knockDistanceMassCurve.Evaluate(mass excluding pawn's inventory mass) + public FloatRange knockDistance = new FloatRange(2f, 3f); + public SimpleCurve knockDistanceAbsorbedPercentCurve = new SimpleCurve + { + new CurvePoint(1f, 0f), // 100% damage soaked/absorbed => 0% knockback distance + new CurvePoint(0f, 1f), // 0% damage soaked/absorbed => 100% knockback distance + }; + public SimpleCurve knockDistanceMassCurve = new SimpleCurve + { + new CurvePoint(0f, 2f), + new CurvePoint(60f, 1f), // 60 is base pawn mass (typical humanoid pawn is a bit higher due to apparel/equipment) + new CurvePoint(120f, 0.5f), + new CurvePoint(240f, 0.25f), // 4 is largest vanilla body size, and 60*4 = 240 + }; + + // distance % = actual distance traveled accounting for obstacles / distance + // impact damage = knockImpactDamage.RandomInRange * knockImpactDamageDistancePercentCurve.Evaluate(distance %) + public FloatRange knockImpactDamage = new FloatRange(8f, 10f); + public SimpleCurve knockImpactDamageDistancePercentCurve = new SimpleCurve + { + new CurvePoint(0f, 0f), + new CurvePoint(0.5f, 0.75f), + new CurvePoint(1f, 1f), + }; + + public DamageDef knockImpactDamageType; + + public float stunChance = 0f; public int stunTicks = 60; public HediffCompProperties_Knockback() { compClass = typeof(HediffComp_Knockback); } + + public override void ResolveReferences(HediffDef parent) + { + knockImpactDamageType ??= DamageDefOf.Blunt; + if (explosiveProps == null && +#pragma warning disable CS0618 // Type or member is obsolete + explosiveKnockback) +#pragma warning restore CS0618 // Type or member is obsolete + { + explosiveProps = new CompProperties_Explosive + { +#pragma warning disable CS0618 // Type or member is obsolete + explosiveDamageType = explosionDmg, + explosiveRadius = explosionSize, +#pragma warning restore CS0618 // Type or member is obsolete + damageAmountBase = 0, + }; + } + } + + public override IEnumerable ConfigErrors(HediffDef parentDef) + { + foreach (var error in base.ConfigErrors(parentDef)) + yield return error; + // Note: knockbackSound can be null - if it is, the explosion sound defaults to explosionDamageType.soundExplosion. + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffComp_DamageSoak.cs b/Source/AllModdingComponents/JecsTools/HediffComp_DamageSoak.cs index e4eebca8..a18cc9de 100644 --- a/Source/AllModdingComponents/JecsTools/HediffComp_DamageSoak.cs +++ b/Source/AllModdingComponents/JecsTools/HediffComp_DamageSoak.cs @@ -5,31 +5,29 @@ namespace JecsTools { public class HediffComp_DamageSoak : HediffComp { - public HediffCompProperties_DamageSoak Props => (HediffCompProperties_DamageSoak) props; + public HediffCompProperties_DamageSoak Props => (HediffCompProperties_DamageSoak)props; public override string CompTipStringExtra { get { var s = new StringBuilder(); - var b = base.CompTipStringExtra; - if (b != "") + if (!b.NullOrEmpty()) s.Append(b); - if (Props.settings.NullOrEmpty()) { - s.AppendLine("JT_HI_DamageSoaked".Translate((Props.damageType != null) ? Props.damageToSoak.ToString() + " (" +Props.damageType.LabelCap + ") " : Props.damageToSoak.ToString() + " (" +"AllDays".Translate() + ")")); + s.AppendLine("JT_HI_DamageSoaked".Translate((Props.damageType != null) ? Props.damageToSoak.ToString() + " (" + Props.damageType.LabelCap + ") " : Props.damageToSoak.ToString() + " (" + "AllDays".Translate() + ")")); } else { foreach (var setting in Props.settings) { - s.AppendLine("JT_HI_DamageSoaked".Translate((setting.damageType != null) ? setting.damageToSoak.ToString() + " (" +setting.damageType.LabelCap + ") " : setting.damageToSoak.ToString() + " (" +"AllDays".Translate() + ")")); + s.AppendLine("JT_HI_DamageSoaked".Translate((setting.damageType != null) ? setting.damageToSoak.ToString() + " (" + setting.damageType.LabelCap + ") " : setting.damageToSoak.ToString() + " (" + "AllDays".Translate() + ")")); } } return s.ToString().TrimEndNewlines(); } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffComp_ExtraMeleeDamages.cs b/Source/AllModdingComponents/JecsTools/HediffComp_ExtraMeleeDamages.cs index d59cf88e..f3080c4f 100644 --- a/Source/AllModdingComponents/JecsTools/HediffComp_ExtraMeleeDamages.cs +++ b/Source/AllModdingComponents/JecsTools/HediffComp_ExtraMeleeDamages.cs @@ -5,7 +5,7 @@ namespace JecsTools { public class HediffComp_ExtraMeleeDamages : HediffComp { - public HediffCompProperties_ExtraMeleeDamages Props => (HediffCompProperties_ExtraMeleeDamages) props; + public HediffCompProperties_ExtraMeleeDamages Props => (HediffCompProperties_ExtraMeleeDamages)props; public override string CompTipStringExtra { @@ -13,16 +13,17 @@ public override string CompTipStringExtra { var s = new StringBuilder(); var b = base.CompTipStringExtra; - if (b != "") + if (!b.NullOrEmpty()) s.Append(b); - if ((Props?.ExtraDamages?.Count ?? 0) > 0) + var extraDamages = Props?.ExtraDamages; + if (!extraDamages.NullOrEmpty()) { s.AppendLine("JT_HI_ExtraDamages".Translate()); - for (var i = 0; i < Props.ExtraDamages.Count; i++) - s.AppendLine(" +" + Props.ExtraDamages[i].amount + " " + Props.ExtraDamages[i].def.LabelCap); + for (var i = 0; i < extraDamages.Count; i++) + s.AppendLine(" +" + extraDamages[i].amount + " " + extraDamages[i].def.LabelCap); } return s.ToString().TrimEndNewlines(); } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffComp_Knockback.cs b/Source/AllModdingComponents/JecsTools/HediffComp_Knockback.cs index a283cb20..1249964a 100644 --- a/Source/AllModdingComponents/JecsTools/HediffComp_Knockback.cs +++ b/Source/AllModdingComponents/JecsTools/HediffComp_Knockback.cs @@ -1,26 +1,38 @@ -using System.Text; +//#define DEBUGLOG + +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using AbilityUser; +using RimWorld; +using UnityEngine; using Verse; namespace JecsTools { public class HediffComp_Knockback : HediffComp { - public HediffCompProperties_Knockback Props => (HediffCompProperties_Knockback) props; + public static readonly SimpleCurve AlwaysOneCurve = new SimpleCurve { new CurvePoint(0f, 1f) }; + + public HediffCompProperties_Knockback Props => (HediffCompProperties_Knockback)props; public override string CompTipStringExtra { get { var s = new StringBuilder(); - s.Append(base.CompTipStringExtra); - //Changed by Tad. - //s.AppendLine("JT_HI_Knockback".Translate(Props.knockbackChance.ToStringPercent()) + (Props.explosiveKnockback ? " (" + "JT_HI_KnockbackExplosive".Translate() + ")" : "")); - s.AppendLine("JT_HI_Knockback".Translate(Props.knockbackChance.ToStringPercent()) +" "+ Props.explosiveKnockback + " " + " (JT_HI_KnockbackExplosive".Translate() + ")"); + s.Append("JT_HI_Knockback".Translate(Props.knockbackChance.ToStringPercent())); + var explosiveProps = Props.explosiveProps; + if (explosiveProps != null) + { + s.AppendLine().Append("JT_HI_KnockbackExplosive".Translate()); + var extraInspectStringKey = explosiveProps.extraInspectStringKey; + if (extraInspectStringKey != null) + s.AppendLine().Append(extraInspectStringKey); + } return s.ToString(); } } -<<<<<<< Updated upstream -======= public void ApplyKnockback(Pawn target, float damageAbsorbedPercent) { @@ -246,6 +258,5 @@ private static void DebugMessage(string s) { Log.Message(s); } ->>>>>>> Stashed changes } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffExpandedDef.cs b/Source/AllModdingComponents/JecsTools/HediffExpandedDef.cs index 7ce4eb13..60717a83 100644 --- a/Source/AllModdingComponents/JecsTools/HediffExpandedDef.cs +++ b/Source/AllModdingComponents/JecsTools/HediffExpandedDef.cs @@ -11,19 +11,19 @@ public class HediffExpandedDef : HediffDef /// Determines if the description should be shown for a hediff. /// public bool showDescription; - + ///Reminder: the string description already exists in the Def class we inherit in this class //public string description; - + /// /// Text key that appears before the list of modifiers. /// public string preListText; - + /// /// Text key that appears after the list of modifiers. /// public string postListText; - + } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffGiver_StartWithHediff.cs b/Source/AllModdingComponents/JecsTools/HediffGiver_StartWithHediff.cs index 04e2d6d2..0edb0001 100644 --- a/Source/AllModdingComponents/JecsTools/HediffGiver_StartWithHediff.cs +++ b/Source/AllModdingComponents/JecsTools/HediffGiver_StartWithHediff.cs @@ -13,11 +13,12 @@ public class HediffGiver_StartWithHediff : HediffGiver public float maleCommonality = 100.0f; public float femaleCommonality = 100.0f; public HediffExpandedDef expandedDef; - + public void GiveHediff(Pawn pawn) { //If the random number is not within the chance range, exit. - if (!(chance >= Rand.Range(0.0f, 100.0f))) return; + if (!(chance >= Rand.Range(0.0f, 100.0f))) + return; //If the gender is male, check the male commonality chance, and if it fails, exit. if (pawn.gender == Gender.Male && !(maleCommonality >= Rand.Range(0.0f, 100.0f))) return; @@ -28,8 +29,8 @@ public void GiveHediff(Pawn pawn) if (expandedDef != null) HealthUtility.AdjustSeverity(pawn, expandedDef, 1f); else - HealthUtility.AdjustSeverity(pawn, this.hediff, 1f); - + HealthUtility.AdjustSeverity(pawn, hediff, 1f); + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/HediffWithComps_Expanded.cs b/Source/AllModdingComponents/JecsTools/HediffWithComps_Expanded.cs index cad78b3c..058cd8b2 100644 --- a/Source/AllModdingComponents/JecsTools/HediffWithComps_Expanded.cs +++ b/Source/AllModdingComponents/JecsTools/HediffWithComps_Expanded.cs @@ -1,5 +1,4 @@ -using System.Linq; -using System.Text; +using System.Text; using Verse; namespace JecsTools @@ -7,22 +6,25 @@ namespace JecsTools public class HediffWithComps_Expanded : HediffWithComps { private HediffExpandedDef Def => def as HediffExpandedDef; - + public override string TipStringExtra { get { - if (Def == null) return base.TipStringExtra; - StringBuilder s = new StringBuilder(); + if (Def == null) + return base.TipStringExtra; + var s = new StringBuilder(); if (Def.showDescription) { s.AppendLine(def.description); } - if (!string.IsNullOrEmpty(Def.preListText)) s.AppendLine(Def.preListText.Translate()); + if (!string.IsNullOrEmpty(Def.preListText)) + s.AppendLine(Def.preListText.Translate()); s.AppendLine(base.TipStringExtra); - if (!string.IsNullOrEmpty(Def.postListText)) s.AppendLine(Def.postListText.Translate()); + if (!string.IsNullOrEmpty(Def.postListText)) + s.AppendLine(Def.postListText.Translate()); return s.ToString(); } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/Hediff_InjuryCustomLabel.cs b/Source/AllModdingComponents/JecsTools/Hediff_InjuryCustomLabel.cs index b72572b8..b62e6bcd 100644 --- a/Source/AllModdingComponents/JecsTools/Hediff_InjuryCustomLabel.cs +++ b/Source/AllModdingComponents/JecsTools/Hediff_InjuryCustomLabel.cs @@ -8,4 +8,4 @@ public class Hediff_InjuryCustomLabel : Hediff_Injury private static readonly Color OldInjuryColor = new Color(0.72f, 0.72f, 0.72f); public override Color LabelColor => this.IsPermanent() ? OldInjuryColor : def.defaultLabelColor; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/JecsTools.csproj b/Source/AllModdingComponents/JecsTools/JecsTools.csproj index ce506803..203f8f79 100644 --- a/Source/AllModdingComponents/JecsTools/JecsTools.csproj +++ b/Source/AllModdingComponents/JecsTools/JecsTools.csproj @@ -1,128 +1,11 @@  - - + + - Debug - AnyCPU - {106BF102-0379-41CF-9C5D-E21AAC5F051B} - Library - Properties JecsTools 0JecsTools - v4.7.2 - 512 - - - false - none - true - ..\..\..\Assemblies\ - - - prompt - 4 - false - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - False - ..\..\..\Assemblies\AbilityUser.dll - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - + - - \ No newline at end of file diff --git a/Source/AllModdingComponents/JecsTools/JobGiver_AIFirelessTrashColonyClose.cs b/Source/AllModdingComponents/JecsTools/JobGiver_AIFirelessTrashColonyClose.cs index 43bb920a..c0ba99ae 100644 --- a/Source/AllModdingComponents/JecsTools/JobGiver_AIFirelessTrashColonyClose.cs +++ b/Source/AllModdingComponents/JecsTools/JobGiver_AIFirelessTrashColonyClose.cs @@ -13,7 +13,7 @@ protected override Job TryGiveJob(Pawn pawn) if (!pawn.HostileTo(Faction.OfPlayer)) return null; var flag = pawn.natives.IgniteVerb != null && pawn.HostileTo(Faction.OfPlayer); - var cellRect = CellRect.CenteredOn(pawn.Position, 5); + var cellRect = CellRect.CenteredOn(pawn.Position, CloseSearchRadius); for (var i = 0; i < 35; i++) { var randomCell = cellRect.RandomCell; @@ -45,4 +45,4 @@ protected override Job TryGiveJob(Pawn pawn) return null; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/JobGiver_AIFirelessTrashColonyDistant.cs b/Source/AllModdingComponents/JecsTools/JobGiver_AIFirelessTrashColonyDistant.cs index 83f78ba3..84eb951c 100644 --- a/Source/AllModdingComponents/JecsTools/JobGiver_AIFirelessTrashColonyDistant.cs +++ b/Source/AllModdingComponents/JecsTools/JobGiver_AIFirelessTrashColonyDistant.cs @@ -21,4 +21,4 @@ protected override Job TryGiveJob(Pawn pawn) return null; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/PatchOperationModLoaded.cs b/Source/AllModdingComponents/JecsTools/PatchOperationModLoaded.cs index 24531a6e..69864e9d 100644 --- a/Source/AllModdingComponents/JecsTools/PatchOperationModLoaded.cs +++ b/Source/AllModdingComponents/JecsTools/PatchOperationModLoaded.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Xml; using Verse; @@ -7,15 +8,16 @@ namespace JecsTools //Original code from NoImageAvailable's Combat Extended (You're a legend, sir) //https://github.com/NoImageAvailable/CombatExtended/blob/master/Source/CombatExtended/CombatExtended/PatchOperationFindMod.cs //Using under ShareAlike license: https://creativecommons.org/licenses/by-nc-sa/4.0/ + [Obsolete("Use vanilla PatchOperationFindMod instead")] public class PatchOperationModLoaded : PatchOperation { #pragma warning disable 649 private string modName; #pragma warning restore 649 - + protected override bool ApplyWorker(XmlDocument xml) { return !modName.NullOrEmpty() && ModsConfig.ActiveModsInLoadOrder.Any(mod => mod.Name == modName); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/PlaceWorker_OnTopOfWalls.cs b/Source/AllModdingComponents/JecsTools/PlaceWorker_OnTopOfWalls.cs index 9ba58ab6..c1fb13b9 100644 --- a/Source/AllModdingComponents/JecsTools/PlaceWorker_OnTopOfWalls.cs +++ b/Source/AllModdingComponents/JecsTools/PlaceWorker_OnTopOfWalls.cs @@ -1,18 +1,26 @@ -using System.Linq; -using RimWorld; -using Verse; +using Verse; namespace JecsTools { public class PlaceWorker_OnTopOfWalls : PlaceWorker { - // Changed by Tad : Missing two on the overrides - public override AcceptanceReport AllowsPlacing(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, Map map, Thing thingToIgnore = null, Thing thing = null) + public override AcceptanceReport AllowsPlacing(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, Map map, + Thing thingToIgnore = null, Thing thing = null) { - if (loc.GetThingList(map).FirstOrDefault(x => - x.def.defName.Contains("Wall")) != null) + if (loc.GetThingList(map).Exists(IsWall)) return true; return new AcceptanceReport("JT_PlaceWorker_OnTopOfWalls".Translate()); } + + static bool IsWall(Thing thing) + { + // In RW 1.3+, it seems like BuildingProperties.isPlaceOverableWall indicates whether something is a "wall". + if (thing.def.building?.isPlaceOverableWall ?? false) + return true; + // Legacy heuristic for mods that don't use isPlaceOverableWall. + if (thing.def.defName.Contains("Wall")) + return true; + return false; + } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/PlaceWorker_Outline.cs b/Source/AllModdingComponents/JecsTools/PlaceWorker_Outline.cs index 05ffc398..705da159 100644 --- a/Source/AllModdingComponents/JecsTools/PlaceWorker_Outline.cs +++ b/Source/AllModdingComponents/JecsTools/PlaceWorker_Outline.cs @@ -17,4 +17,4 @@ public override void DrawGhost(ThingDef def, IntVec3 center, Rot4 rot, Color gho } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/PlaceWorker_UnderCeiling.cs b/Source/AllModdingComponents/JecsTools/PlaceWorker_UnderCeiling.cs index 5063c2bf..2130edfd 100644 --- a/Source/AllModdingComponents/JecsTools/PlaceWorker_UnderCeiling.cs +++ b/Source/AllModdingComponents/JecsTools/PlaceWorker_UnderCeiling.cs @@ -1,22 +1,15 @@ -using System.Linq; -using RimWorld; -using Verse; +using Verse; namespace JecsTools { public class PlaceWorker_UnderCeiling : PlaceWorker { - //Tad Changed - Again override was modified with additional checks. - public override AcceptanceReport AllowsPlacing(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, Map map, Thing thingToIgnore = null, Thing thing = null) + public override AcceptanceReport AllowsPlacing(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, Map map, + Thing thingToIgnore = null, Thing thing = null) { - return base.AllowsPlacing(checkingDef, loc, rot, map, thingToIgnore, thing); + if (!loc.Roofed(map)) + return new AcceptanceReport("JT_PlaceWorker_UnderCeiling".Translate()); + return true; } } - //public override AcceptanceReport AllowsPlacing(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, Map map, - // Thing thingToIgnore = null) - //{ - // if (!loc.Roofed(map)) - // return new AcceptanceReport("JT_PlaceWorker_UnderCeiling".Translate()); - // return true; - //} -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/ProjectileExtension.cs b/Source/AllModdingComponents/JecsTools/ProjectileExtension.cs index a42e8ee9..4eac5c50 100644 --- a/Source/AllModdingComponents/JecsTools/ProjectileExtension.cs +++ b/Source/AllModdingComponents/JecsTools/ProjectileExtension.cs @@ -1,18 +1,18 @@ -using System.Collections.Generic; +using System; using Verse; -using Verse.AI; namespace JecsTools { /// /// Projectile Extension allows extra control over - /// damage + /// damage /// + [Obsolete("Seems to have never worked properly due to incomplete implementation")] public class ProjectileExtension : DefModExtension { public bool passesWalls = false; - public bool passesRoofs = false; - public bool damagesTargetsBetween = false; - public float damageMultiplierPerTarget = 1.0f; + public bool passesRoofs = false; // TODO: unused + public bool damagesTargetsBetween = false; // TODO: unused + public float damageMultiplierPerTarget = 1.0f; // TODO: unused } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/Projectile_Laser.cs b/Source/AllModdingComponents/JecsTools/Projectile_Laser.cs index e49f2e33..1631fec7 100644 --- a/Source/AllModdingComponents/JecsTools/Projectile_Laser.cs +++ b/Source/AllModdingComponents/JecsTools/Projectile_Laser.cs @@ -43,40 +43,19 @@ public class Projectile_Laser : Projectile public Material drawingTexture; - protected virtual void Explode(Thing hitThing, bool destroy = false) { - Map map = base.Map; - IntVec3 targetPosition = hitThing?.PositionHeld ?? this.destination.ToIntVec3(); - if (destroy) this.Destroy(DestroyMode.Vanish); - if (this.def.projectile.explosionEffect != null) + var map = Map; + var targetPosition = hitThing?.PositionHeld ?? destination.ToIntVec3(); + if (destroy) + Destroy(); + if (def.projectile.explosionEffect != null) { - Effecter effecter = this.def.projectile.explosionEffect.Spawn(); - effecter.Trigger(new TargetInfo(targetPosition, map, false), - new TargetInfo(targetPosition, map, false)); + var effecter = def.projectile.explosionEffect.Spawn(); + effecter.Trigger(new TargetInfo(targetPosition, map), + new TargetInfo(targetPosition, map)); effecter.Cleanup(); } -<<<<<<< Updated upstream - IntVec3 position = targetPosition; - Map map2 = map; - float explosionRadius = this.def.projectile.explosionRadius; - DamageDef damageDef = this.def.projectile.damageDef; - Thing launcher = this.launcher; - int damageAmountBase = this.def.projectile.GetDamageAmount(1f); - SoundDef soundExplode = this.def.projectile.soundExplode; - ThingDef equipmentDef = this.equipmentDef; - ThingDef def = this.def; - ThingDef postExplosionSpawnThingDef = this.def.projectile.postExplosionSpawnThingDef; - float postExplosionSpawnChance = this.def.projectile.postExplosionSpawnChance; - int postExplosionSpawnThingCount = this.def.projectile.postExplosionSpawnThingCount; - ThingDef preExplosionSpawnThingDef = this.def.projectile.preExplosionSpawnThingDef; - GenExplosion.DoExplosion(position, map2, explosionRadius, damageDef, launcher, damageAmountBase, 0f, - soundExplode, equipmentDef, def, null, postExplosionSpawnThingDef, postExplosionSpawnChance, - postExplosionSpawnThingCount, this.def.projectile.applyDamageToExplosionCellsNeighbors, - preExplosionSpawnThingDef, this.def.projectile.preExplosionSpawnChance, - this.def.projectile.preExplosionSpawnThingCount, this.def.projectile.explosionChanceToStartFire, - this.def.projectile.explosionDamageFalloff); -======= GenExplosion.DoExplosion( targetPosition, map, @@ -100,15 +79,12 @@ protected virtual void Explode(Thing hitThing, bool destroy = false) def.projectile.explosionChanceToStartFire, def.projectile.explosionDamageFalloff ); ->>>>>>> Stashed changes } - private int ticksToDetonation; - public override void SpawnSetup(Map map, bool blabla) { base.SpawnSetup(map, blabla); - drawingTexture = this.def.DrawMatSingle; + drawingTexture = def.DrawMatSingle; } /// @@ -116,7 +92,7 @@ public override void SpawnSetup(Map map, bool blabla) /// public void GetParametersFromXml() { - ThingDef_LaserProjectile additionalParameters = def as ThingDef_LaserProjectile; + var additionalParameters = def as ThingDef_LaserProjectile; preFiringDuration = additionalParameters.preFiringDuration; postFiringDuration = additionalParameters.postFiringDuration; @@ -127,7 +103,7 @@ public void GetParametersFromXml() postFiringInitialIntensity = additionalParameters.postFiringInitialIntensity; postFiringFinalIntensity = additionalParameters.postFiringFinalIntensity; startFireChance = additionalParameters.StartFireChance; - this.canStartFire = additionalParameters.CanStartFire; + canStartFire = additionalParameters.CanStartFire; } /// @@ -136,7 +112,7 @@ public void GetParametersFromXml() public override void ExposeData() { base.ExposeData(); - Scribe_Values.Look(ref tickCounter, "tickCounter", 0); + Scribe_Values.Look(ref tickCounter, nameof(tickCounter)); if (Scribe.mode == LoadSaveMode.PostLoadInit) { @@ -166,7 +142,7 @@ public override void Tick() GetPreFiringDrawingParameters(); } // Firing. - else if (tickCounter == this.preFiringDuration) + else if (tickCounter == preFiringDuration) { Fire(); GetPostFiringDrawingParameters(); @@ -176,18 +152,18 @@ public override void Tick() { GetPostFiringDrawingParameters(); } - if (tickCounter == (this.preFiringDuration + this.postFiringDuration) && !this.Destroyed) + if (tickCounter == (preFiringDuration + postFiringDuration) && !Destroyed) { - this.Destroy(DestroyMode.Vanish); + Destroy(); } - if (this.launcher != null) + if (launcher != null) { - if (this.launcher is Pawn) + if (launcher is Pawn) { - Pawn launcherPawn = this.launcher as Pawn; - if ((((launcherPawn.Dead) == true) && !this.Destroyed)) + var launcherPawn = launcher as Pawn; + if (launcherPawn.Dead && !Destroyed) { - this.Destroy(DestroyMode.Vanish); + Destroy(); } } } @@ -195,7 +171,7 @@ public override void Tick() } catch { - this.Destroy(DestroyMode.Vanish); + Destroy(); } } @@ -205,61 +181,58 @@ public override void Tick() public virtual void PerformPreFiringTreatment() { DetermineImpactExactPosition(); - Vector3 cannonMouthOffset = ((this.destination - this.origin).normalized * 0.9f); - if (this.Def.graphicSettings.NullOrEmpty()) + var cannonMouthOffset = (destination - origin).normalized * 0.9f; + if (Def.graphicSettings.NullOrEmpty()) { var drawingScale = new Vector3(1f, 1f, - (this.destination - this.origin).magnitude - cannonMouthOffset.magnitude); - var drawingPosition = this.origin + (cannonMouthOffset / 2) + ((this.destination - this.origin) / 2) + - Vector3.up * this.def.Altitude; + (destination - origin).magnitude - cannonMouthOffset.magnitude); + var drawingPosition = origin + (cannonMouthOffset / 2) + ((destination - origin) / 2) + + Vector3.up * def.Altitude; drawingMatrix = new List(); - var drawing = default(Matrix4x4); - drawing.SetTRS(drawingPosition, this.ExactRotation, drawingScale); + var drawing = Matrix4x4.TRS(drawingPosition, ExactRotation, drawingScale); drawingMatrix.Add(drawing); } else { drawingMatrix = new List(); - if (!this.Def.cycleThroughFiringPositions) + if (!Def.cycleThroughFiringPositions) { - foreach (var setting in this.Def.graphicSettings) + foreach (var setting in Def.graphicSettings) { AddLaserGraphicUsing(setting); } } else { - var curIndex = 0; - if (HarmonyPatches.AlternatingFireTracker.ContainsKey(this.launcher)) + if (HarmonyPatches.AlternatingFireTracker.TryGetValue(launcher, out var curIndex)) { - curIndex = (HarmonyPatches.AlternatingFireTracker[this.launcher] + 1) % - this.Def.graphicSettings.Count; - HarmonyPatches.AlternatingFireTracker[this.launcher] = curIndex; + curIndex = (curIndex + 1) % Def.graphicSettings.Count; + HarmonyPatches.AlternatingFireTracker[launcher] = curIndex; } else { - HarmonyPatches.AlternatingFireTracker.Add(this.launcher, curIndex); + curIndex = 0; // technically unnecessary but good to be explicit + HarmonyPatches.AlternatingFireTracker.Add(launcher, curIndex); } - AddLaserGraphicUsing(this.Def.graphicSettings[curIndex]); + AddLaserGraphicUsing(Def.graphicSettings[curIndex]); } } } private void AddLaserGraphicUsing(Projectile_LaserConfig setting) { - var curCannonMouthOffset = ((this.destination - this.origin).normalized * 0.9f); + var curCannonMouthOffset = (destination - origin).normalized * 0.9f; var drawingScale = new Vector3(1f, 1f, - (this.destination - this.origin).magnitude - curCannonMouthOffset.magnitude); - var drawingPosition = this.origin + (curCannonMouthOffset / 2) + ((this.destination - this.origin) / 2) + - Vector3.up * this.def.Altitude; - float num = 0f; - if ((this.destination - this.origin).MagnitudeHorizontalSquared() > 0.001f) + (destination - origin).magnitude - curCannonMouthOffset.magnitude); + var drawingPosition = origin + (curCannonMouthOffset / 2) + ((destination - origin) / 2) + + Vector3.up * def.Altitude; + var num = 0f; + if ((destination - origin).MagnitudeHorizontalSquared() > 0.001f) { - num = (this.destination - this.origin).AngleFlat(); + num = (destination - origin).AngleFlat(); } drawingPosition += setting.offset.RotatedBy(num); - var drawing = default(Matrix4x4); - drawing.SetTRS(drawingPosition, this.ExactRotation, drawingScale); + var drawing = Matrix4x4.TRS(drawingPosition, ExactRotation, drawingScale); drawingMatrix.Add(drawing); } @@ -277,7 +250,7 @@ public virtual void GetPreFiringDrawingParameters() if (preFiringDuration != 0) { drawingIntensity = preFiringInitialIntensity + (preFiringFinalIntensity - preFiringInitialIntensity) * - (float) tickCounter / (float) preFiringDuration; + tickCounter / preFiringDuration; } } @@ -290,7 +263,7 @@ public virtual void GetPostFiringDrawingParameters() { drawingIntensity = postFiringInitialIntensity + (postFiringFinalIntensity - postFiringInitialIntensity) * - (((float) tickCounter - (float) preFiringDuration) / (float) postFiringDuration); + ((tickCounter - (float)preFiringDuration) / postFiringDuration); } } @@ -300,52 +273,50 @@ public virtual void GetPostFiringDrawingParameters() protected void DetermineImpactExactPosition() { // We split the trajectory into small segments of approximatively 1 cell size. - Vector3 trajectory = (this.destination - this.origin); - int numberOfSegments = (int) trajectory.magnitude; - Vector3 trajectorySegment = (trajectory / trajectory.magnitude); + var trajectory = destination - origin; + var numberOfSegments = (int)trajectory.magnitude; + var trajectorySegment = trajectory / trajectory.magnitude; - Vector3 - temporaryDestination = this.origin; // Last valid tested position in case of an out of boundaries shot. - Vector3 exactTestedPosition = this.origin; - IntVec3 testedPosition = exactTestedPosition.ToIntVec3(); + var temporaryDestination = origin; // Last valid tested position in case of an out of boundaries shot. + var exactTestedPosition = origin; - for (int segmentIndex = 1; segmentIndex <= numberOfSegments; segmentIndex++) + for (var segmentIndex = 1; segmentIndex <= numberOfSegments; segmentIndex++) { exactTestedPosition += trajectorySegment; - testedPosition = exactTestedPosition.ToIntVec3(); + var testedPosition = exactTestedPosition.ToIntVec3(); - if (!exactTestedPosition.InBounds(this.Map)) + if (!exactTestedPosition.InBounds(Map)) { - this.destination = temporaryDestination; + destination = temporaryDestination; break; } - if (!this.def.projectile.flyOverhead && segmentIndex >= 5) + if (!def.projectile.flyOverhead && segmentIndex >= 5) { - List list = this.Map.thingGrid.ThingsListAt(base.Position); - for (int i = 0; i < list.Count; i++) + var list = Map.thingGrid.ThingsListAt(Position); + for (var i = 0; i < list.Count; i++) { - Thing current = list[i]; + var current = list[i]; // Check impact on a wall. if (current.def.Fillage == FillCategory.Full) { - this.destination = testedPosition.ToVector3Shifted() + + destination = testedPosition.ToVector3Shifted() + new Vector3(Rand.Range(-0.3f, 0.3f), 0f, Rand.Range(-0.3f, 0.3f)); - this.hitThing = current; + hitThing = current; break; } // Check impact on a pawn. if (current.def.category == ThingCategory.Pawn) { - Pawn pawn = current as Pawn; - float chanceToHitCollateralTarget = 0.45f; + var pawn = current as Pawn; + var chanceToHitCollateralTarget = 0.45f; if (pawn.Downed) { chanceToHitCollateralTarget *= 0.1f; } - float targetDistanceFromShooter = (this.ExactPosition - this.origin).MagnitudeHorizontal(); + var targetDistanceFromShooter = (ExactPosition - origin).MagnitudeHorizontal(); if (targetDistanceFromShooter < 4f) { chanceToHitCollateralTarget *= 0f; @@ -368,9 +339,9 @@ protected void DetermineImpactExactPosition() if (Rand.Value < chanceToHitCollateralTarget) { - this.destination = testedPosition.ToVector3Shifted() + + destination = testedPosition.ToVector3Shifted() + new Vector3(Rand.Range(-0.3f, 0.3f), 0f, Rand.Range(-0.3f, 0.3f)); - this.hitThing = (Thing) pawn; + hitThing = pawn; break; } } @@ -386,7 +357,7 @@ protected void DetermineImpactExactPosition() /// public virtual void Fire() { - ApplyDamage(this.hitThing); + ApplyDamage(hitThing); } /// @@ -397,11 +368,11 @@ protected void ApplyDamage(Thing hitThing) if (hitThing != null) { // Impact collateral target. - this.Impact(hitThing); + Impact(hitThing); } else { - this.ImpactSomething(); + ImpactSomething(); } } @@ -411,50 +382,45 @@ protected void ApplyDamage(Thing hitThing) protected void ImpactSomething() { // Check impact on a thick mountain. - if (this.def.projectile.flyOverhead) + if (def.projectile.flyOverhead) { - RoofDef roofDef = this.Map.roofGrid.RoofAt(this.DestinationCell); + var roofDef = Map.roofGrid.RoofAt(DestinationCell); if (roofDef != null && roofDef.isThickRoof) { - SoundInfo info = SoundInfo.InMap(new TargetInfo(this.DestinationCell, this.Map, false), - MaintenanceType.None); - this.def.projectile.soundHitThickRoof.PlayOneShot(info); + def.projectile.soundHitThickRoof.PlayOneShot(SoundInfo.InMap(new TargetInfo(DestinationCell, Map))); return; } } // Impact the initial targeted pawn. - if (this.usedTarget != null) + if (usedTarget != null) { - Pawn pawn = this.usedTarget.Thing as Pawn; - if (pawn != null && pawn.Downed && (this.origin - this.destination).magnitude > 5f && Rand.Value < 0.2f) - { - this.Impact(null); - return; - } - this.Impact(this.usedTarget.Thing); - return; + if (usedTarget.Thing is Pawn pawn && pawn.Downed && (origin - destination).magnitude > 5f && Rand.Value < 0.2f) + Impact(null); + else + Impact(usedTarget.Thing); } else { // Impact a pawn in the destination cell if present. - Thing thing = this.Map.thingGrid.ThingAt(this.DestinationCell, ThingCategory.Pawn); + var thing = Map.thingGrid.ThingAt(DestinationCell, ThingCategory.Pawn); if (thing != null) { - this.Impact(thing); - return; + Impact(thing); } - // Impact any cover object. - foreach (Thing current in this.Map.thingGrid.ThingsAt(this.DestinationCell)) + else { - if (current.def.fillPercent > 0f || current.def.passability != Traversability.Standable) + // Impact any cover object. + foreach (var current in Map.thingGrid.ThingsAt(DestinationCell)) { - this.Impact(current); - return; + if (current.def.fillPercent > 0f || current.def.passability != Traversability.Standable) + { + Impact(current); + return; + } } + Impact(null); } - this.Impact(null); - return; } } @@ -463,52 +429,38 @@ protected void ImpactSomething() /// protected override void Impact(Thing hitThing, bool blockedByShield = false) { - if (this.Def.createsExplosion) + if (Def.createsExplosion) { - this.Explode(hitThing, false); - GenExplosion.NotifyNearbyPawnsOfDangerousExplosive(this, this.def.projectile.damageDef, - this.launcher.Faction); + Explode(hitThing, false); + GenExplosion.NotifyNearbyPawnsOfDangerousExplosive(this, def.projectile.damageDef, + launcher.Faction); } if (hitThing != null) { - Map map = base.Map; - BattleLogEntry_RangedImpact battleLogEntry_RangedImpact = new BattleLogEntry_RangedImpact(this.launcher, - hitThing, this.intendedTarget.Thing, this.equipmentDef, this.def, this.targetCoverDef); + var battleLogEntry_RangedImpact = new BattleLogEntry_RangedImpact(launcher, + hitThing, intendedTarget.Thing, equipmentDef, def, targetCoverDef); Find.BattleLog.Add(battleLogEntry_RangedImpact); - - int damageAmountBase = this.def.projectile.GetDamageAmount(1f); - DamageDef damageDef = this.def.projectile.damageDef; - int amount = damageAmountBase; - float y = this.ExactRotation.eulerAngles.y; - Thing launcher = this.launcher; - ThingDef equipmentDef = this.equipmentDef; - DamageInfo dinfo = new DamageInfo(damageDef, amount, this.def.projectile.GetArmorPenetration(1f), y, launcher, null, equipmentDef, - DamageInfo.SourceCategory.ThingOrUnknown); - hitThing.TakeDamage(dinfo).AssociateWithLog(battleLogEntry_RangedImpact); - - //int damageAmountBase = this.def.projectile.DamageAmount; - //DamageInfo dinfo = new DamageInfo(this.def.projectile.damageDef, damageAmountBase, this.ExactRotation.eulerAngles.y, this.launcher, null, equipmentDef); - //hitThing.TakeDamage(dinfo); - //hitThing.TakeDamage(dinfo); - if (this.canStartFire && Rand.Range(0f, 1f) > startFireChance) + + var dinfo = new DamageInfo(def.projectile.damageDef, def.projectile.GetDamageAmount(1f), def.projectile.GetArmorPenetration(1f), ExactRotation.eulerAngles.y, launcher, weapon: equipmentDef); + hitThing.TakeDamage(dinfo).AssociateWithLog(battleLogEntry_RangedImpact); + + if (canStartFire && Rand.Range(0f, 1f) > startFireChance) { hitThing.TryAttachFire(0.05f); } - Pawn pawn = hitThing as Pawn; - if (pawn != null) + if (hitThing is Pawn pawn) { - PostImpactEffects(this.launcher as Pawn, pawn); - MoteMaker.ThrowMicroSparks(this.destination, this.Map); - MoteMaker.MakeStaticMote(this.destination, this.Map, ThingDefOf.Mote_ShotHit_Dirt, 1f); + PostImpactEffects(launcher as Pawn, pawn); + FleckMaker.ThrowMicroSparks(destination, Map); + FleckMaker.Static(destination, Map, FleckDefOf.ShotHit_Dirt); } } else { - SoundInfo info = SoundInfo.InMap(new TargetInfo(base.Position, this.Map, false), MaintenanceType.None); - SoundDefOf.BulletImpact_Ground.PlayOneShot(info); - MoteMaker.MakeStaticMote(this.ExactPosition, this.Map, ThingDefOf.Mote_ShotHit_Dirt, 1f); - MoteMaker.ThrowMicroSparks(this.ExactPosition, this.Map); + SoundDefOf.BulletImpact_Ground.PlayOneShot(SoundInfo.InMap(new TargetInfo(Position, Map))); + FleckMaker.Static(ExactPosition, Map, FleckDefOf.ShotHit_Dirt); + FleckMaker.ThrowMicroSparks(ExactPosition, Map); } } @@ -526,15 +478,15 @@ public virtual void PostImpactEffects(Pawn launcher, Pawn hitTarget) /// public override void Draw() { - this.Comps_PostDraw(); - if (!drawingMatrix.NullOrEmpty()) + Comps_PostDraw(); + if (drawingMatrix != null) { foreach (var drawing in drawingMatrix) { - UnityEngine.Graphics.DrawMesh(MeshPool.plane10, drawing, + Graphics.DrawMesh(MeshPool.plane10, drawing, FadedMaterialPool.FadedVersionOf(drawingTexture, drawingIntensity), 0); } } } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/ThingDef_LaserProjectile.cs b/Source/AllModdingComponents/JecsTools/ThingDef_LaserProjectile.cs index efe1c1c9..3860715e 100644 --- a/Source/AllModdingComponents/JecsTools/ThingDef_LaserProjectile.cs +++ b/Source/AllModdingComponents/JecsTools/ThingDef_LaserProjectile.cs @@ -19,4 +19,4 @@ public class ThingDef_LaserProjectile : ThingDef public bool cycleThroughFiringPositions = false; public bool createsExplosion = false; } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/TransformedPart.cs b/Source/AllModdingComponents/JecsTools/TransformedPart.cs index cb5cdfe3..981447a7 100644 --- a/Source/AllModdingComponents/JecsTools/TransformedPart.cs +++ b/Source/AllModdingComponents/JecsTools/TransformedPart.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using System.Text; using RimWorld; using Verse; @@ -10,29 +9,20 @@ public class Hediff_TransformedPart : Hediff_AddedPart { private readonly List temporarilyRemovedParts = new List(); - public override bool ShouldRemove - { - get - { - if (this.TryGetComp() is HediffComp_Disappears hdc_Disappears) - return hdc_Disappears.CompShouldRemove; - return false; - } - } - + public override bool ShouldRemove => + this.GetHediffComp() is HediffComp_Disappears hdc_Disappears && hdc_Disappears.CompShouldRemove; public override string TipStringExtra { get { var stringBuilder = new StringBuilder(); - if (base.TipStringExtra is string baseString && baseString != "") + var baseString = base.TipStringExtra; + if (!baseString.NullOrEmpty()) stringBuilder.Append(baseString); - if (def.comps.FirstOrDefault(x => x is HediffCompProperties_VerbGiver) is HediffCompProperties_VerbGiver - props && - props?.tools?.Count() > 0) - for (var i = 0; i < props?.tools?.Count(); i++) - stringBuilder.AppendLine("Damage".Translate() + ": " + props.tools[i].power); + if (def.GetHediffCompProps()?.tools is List tools) + for (var i = 0; i < tools.Count; i++) + stringBuilder.AppendLine("Damage".Translate() + ": " + tools[i].power); return stringBuilder.ToString(); } } @@ -50,7 +40,7 @@ public override void PostAdd(DamageInfo? dinfo) for (var i = 0; i < Part.parts.Count; i++) { var hediff_MissingPart = - (Hediff_MissingPart) HediffMaker.MakeHediff(HediffDefOf.MissingBodyPart, pawn, null); + (Hediff_MissingPart)HediffMaker.MakeHediff(HediffDefOf.MissingBodyPart, pawn, null); hediff_MissingPart.IsFresh = false; hediff_MissingPart.lastInjury = null; hediff_MissingPart.Part = Part.parts[i]; @@ -63,10 +53,9 @@ public override void PostRemoved() { base.PostRemoved(); pawn.health.RestorePart(Part, this, false); - //for (int i = 0; i < base.Part.parts.Count; i++) + //for (var i = 0; i < Part.parts.Count; i++) //{ - //} } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/JecsTools/Utility/DefModExtensionUtility.cs b/Source/AllModdingComponents/JecsTools/Utility/DefModExtensionUtility.cs new file mode 100644 index 00000000..2bc193cc --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/Utility/DefModExtensionUtility.cs @@ -0,0 +1,50 @@ +using Verse; + +namespace JecsTools +{ + public static class DefModExtensionUtility + { + // Avoiding Def.GetModExtension and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + + public static ProjectileExtension GetProjectileExtension(this Def def) + { + var modExtensions = def.modExtensions; + if (modExtensions == null) + return null; + for (int i = 0, count = modExtensions.Count; i < count; i++) + { + if (modExtensions[i] is ProjectileExtension modExtension) + return modExtension; + } + return null; + } + + public static BuildingExtension GetBuildingExtension(this Def def) + { + var modExtensions = def.modExtensions; + if (modExtensions == null) + return null; + for (int i = 0, count = modExtensions.Count; i < count; i++) + { + if (modExtensions[i] is BuildingExtension modExtension) + return modExtension; + } + return null; + } + + public static ApparelExtension GetApparelExtension(this Def def) + { + var modExtensions = def.modExtensions; + if (modExtensions == null) + return null; + for (int i = 0, count = modExtensions.Count; i < count; i++) + { + if (modExtensions[i] is ApparelExtension modExtension) + return modExtension; + } + return null; + } + } +} diff --git a/Source/AllModdingComponents/JecsTools/Utility/FirelessTrashUtility.cs b/Source/AllModdingComponents/JecsTools/Utility/FirelessTrashUtility.cs new file mode 100644 index 00000000..1bae9aa8 --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/Utility/FirelessTrashUtility.cs @@ -0,0 +1,77 @@ +using RimWorld; +using Verse; +using Verse.AI; + +namespace JecsTools +{ + public static class FirelessTrashUtility + { + // RimWorld.TrashUtility + private static readonly IntRange TrashJobCheckOverrideInterval = new IntRange(450, 500); + + // RimWorld.TrashUtility + public static Job TrashJob(Pawn pawn, Thing t) + { + if (t is Plant) + { + var job = JobMaker.MakeJob(JobDefOf.AttackMelee, t); + FinalizeTrashJob(job); + return job; + } + if (pawn.equipment != null && Rand.Value < 0.7f) + foreach (var current in pawn.equipment.AllEquipmentVerbs) + if (current.verbProps.ai_IsBuildingDestroyer) + { + var job2 = JobMaker.MakeJob(JobDefOf.UseVerbOnThing, t); + job2.verbToUse = current; + FinalizeTrashJob(job2); + return job2; + } + var job3 = JobMaker.MakeJob(JobDefOf.AttackMelee, t); + FinalizeTrashJob(job3); + return job3; + } + + // RimWorld.TrashUtility + private static void FinalizeTrashJob(Job job) + { + job.expiryInterval = TrashJobCheckOverrideInterval.RandomInRange; + job.checkOverrideOnExpire = true; + job.expireRequiresEnemiesNearby = true; + } + + // RimWorld.TrashUtility + public static bool ShouldTrashBuilding(Pawn pawn, Building b) + { + if (!b.def.useHitPoints) + return false; + if (b.def.building.isInert || b.def.building.isTrap) + { + var num = GenLocalDate.HourOfDay(pawn) / 3; + var specialSeed = (b.GetHashCode() * 612361) ^ (pawn.GetHashCode() * 391) ^ (num * 734273247); + if (!Rand.ChanceSeeded(0.008f, specialSeed)) + return false; + } + return (!b.def.building.isTrap && pawn.HostileTo(b)); + } + + // RimWorld.TrashUtility + public static bool ShouldTrashPlant(Pawn pawn, Plant p) + { + if (!p.sown || p.def.plant.IsTree || !p.FlammableNow || !CanTrash(pawn, p)) + return false; + foreach (var current in CellRect.CenteredOn(p.Position, 2).ClipInsideMap(p.Map)) + { + if (current.InBounds(p.Map) && current.ContainsStaticFire(p.Map)) + return false; + } + return p.Position.Roofed(p.Map) || p.Map.weatherManager.RainRate <= 0.25f; + } + + // RimWorld.TrashUtility + private static bool CanTrash(Pawn pawn, Thing t) + { + return pawn.CanReach(t, PathEndMode.Touch, Danger.Some) && !t.IsBurning(); + } + } +} diff --git a/Source/AllModdingComponents/JecsTools/Utility/HarmonyExtensions.cs b/Source/AllModdingComponents/JecsTools/Utility/HarmonyExtensions.cs new file mode 100644 index 00000000..5fd88f7e --- /dev/null +++ b/Source/AllModdingComponents/JecsTools/Utility/HarmonyExtensions.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using HarmonyLib; + +namespace JecsTools +{ + // Code copied between JecsTools and PawnShields - keep them in sync! + public static class HarmonyExtensions + { + public static void SafeInsertRange(this List instructions, int insertionIndex, IEnumerable newInstructions, + IEnumerable public List shieldTags; + + public override IEnumerable ConfigErrors() + { + if (shieldTags.NullOrEmpty()) + yield return nameof(shieldTags) + " cannot be null or empty"; + } } } diff --git a/Source/AllModdingComponents/PawnShields/PawnShields.csproj b/Source/AllModdingComponents/PawnShields/PawnShields.csproj index f767d2c4..89133410 100644 --- a/Source/AllModdingComponents/PawnShields/PawnShields.csproj +++ b/Source/AllModdingComponents/PawnShields/PawnShields.csproj @@ -1,66 +1,7 @@  - - + + - Debug - AnyCPU - {9A3BF1D4-6693-481F-BBF1-3D66AFD8BE6C} - Library - Properties - PawnShields PawnShields - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - TRACE - prompt - 4 - false - - - - False - ..\..\..\Assemblies\AbilityUser.dll - False - - - - - - - - - - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - \ No newline at end of file diff --git a/Source/AllModdingComponents/PawnShields/Shields.cs b/Source/AllModdingComponents/PawnShields/Shields.cs index d88be879..9bfaa3b7 100644 --- a/Source/AllModdingComponents/PawnShields/Shields.cs +++ b/Source/AllModdingComponents/PawnShields/Shields.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Verse; +using Verse; namespace PawnShields { diff --git a/Source/AllModdingComponents/PawnShields/ThingComps/CompShield.cs b/Source/AllModdingComponents/PawnShields/ThingComps/CompShield.cs index f80adede..66da81d3 100644 --- a/Source/AllModdingComponents/PawnShields/ThingComps/CompShield.cs +++ b/Source/AllModdingComponents/PawnShields/ThingComps/CompShield.cs @@ -1,5 +1,6 @@ -using RimWorld; -using System.Linq; +using System; +using HarmonyLib; +using RimWorld; using UnityEngine; using Verse; @@ -13,13 +14,7 @@ public class CompShield : ThingComp /// /// Shield properties. /// - public CompProperties_Shield ShieldProps - { - get - { - return props as CompProperties_Shield; - } - } + public CompProperties_Shield ShieldProps => props as CompProperties_Shield; /// /// Determines whether the shield is broken or not. @@ -30,8 +25,7 @@ public virtual bool IsBroken { if (!ShieldProps.canBeAutoDiscarded) return false; - - return ((float)parent.HitPoints / (float)parent.MaxHitPoints) <= ShieldProps.healthAutoDiscardThreshold; + return (parent.HitPoints / (float)parent.MaxHitPoints) <= ShieldProps.healthAutoDiscardThreshold; } } @@ -42,11 +36,15 @@ public virtual SoundDef BlockSound { get { - if (ShieldProps?.stuffedSounds != null && ShieldProps?.stuffedSounds?.Count > 0 && parent.Stuff?.stuffProps?.categories != null && ShieldProps.stuffedSounds.Count > 0 && - ShieldProps.stuffedSounds.ContainsKey(parent.Stuff?.stuffProps?.categories.FirstOrDefault())) + var categories = parent.Stuff?.stuffProps?.categories; + if (!categories.NullOrEmpty()) { - if (ShieldProps.stuffedSounds[parent.Stuff.stuffProps.categories.First()] is SoundDef def) - return def; + var stuffedSounds = ShieldProps?.stuffedSounds; + if (stuffedSounds != null) + { + if (stuffedSounds.TryGetValue(categories[0], out var soundDef)) + return soundDef; + } } //Default sound @@ -63,24 +61,19 @@ public virtual SoundDef BlockSound /// True if it absorbed damage successfully. public virtual bool AbsorbDamage(Pawn defender, DamageInfo dinfo, bool ranged) { - bool absorbedDamage = false; + var absorbedDamage = false; //Check if we blocked the attack at all. - if(ShieldProps.canBlockMelee && !ranged) + if (ShieldProps.canBlockMelee && !ranged) { - //Melee - float baseStat = defender.GetStatValue(ShieldStatsDefOf.MeleeShieldBlockChance, true); - float chance = baseStat * parent.GetStatValue(ShieldStatsDefOf.Shield_BaseMeleeBlockChance); - + var chance = defender.GetStatValue(ShieldStatsDefOf.MeleeShieldBlockChance, true); //Log.Message("Melee block chance: " + chance.ToStringPercent()); if (Rand.Chance(chance)) absorbedDamage = true; - } else if (ShieldProps.canBlockRanged && ranged) + } + else if (ShieldProps.canBlockRanged && ranged) { - //Ranged - float baseStat = defender.GetStatValue(ShieldStatsDefOf.RangedShieldBlockChance, true); - float chance = baseStat * parent.GetStatValue(ShieldStatsDefOf.Shield_BaseRangedBlockChance); - + var chance = defender.GetStatValue(ShieldStatsDefOf.RangedShieldBlockChance, true); //Log.Message("Ranged block chance: " + chance.ToStringPercent()); if (Rand.Chance(chance)) absorbedDamage = true; @@ -90,24 +83,24 @@ public virtual bool AbsorbDamage(Pawn defender, DamageInfo dinfo, bool ranged) return false; //Fatigue damage. - if(absorbedDamage && ShieldProps.useFatigue) + if (absorbedDamage && ShieldProps.useFatigue) { - float finalDamage = (float)dinfo.Amount * ShieldProps.damageToFatigueFactor; + var finalDamage = (float)dinfo.Amount * ShieldProps.damageToFatigueFactor; HealthUtility.AdjustSeverity(defender, ShieldHediffDefOf.ShieldFatigue, finalDamage); } //Take damage from attack. if (ShieldProps.shieldTakeDamage) { - int finalDamage = Mathf.CeilToInt((float)dinfo.Amount * parent.GetStatValue(ShieldStatsDefOf.Shield_DamageAbsorbed)); - DamageInfo shieldDamage = new DamageInfo(dinfo); + var finalDamage = Mathf.CeilToInt((float)dinfo.Amount * parent.GetStatValue(ShieldStatsDefOf.Shield_DamageAbsorbed)); + var shieldDamage = new DamageInfo(dinfo); shieldDamage.SetAmount(finalDamage); parent.TakeDamage(shieldDamage); } //Absorb damage if shield is still intact. - if(parent.HitPoints > 0) + if (parent.HitPoints > 0) { MakeBlockEffect(defender, dinfo, ranged); return true; @@ -124,7 +117,7 @@ public virtual bool AbsorbDamage(Pawn defender, DamageInfo dinfo, bool ranged) /// Is this attack ranged or melee? public virtual void MakeBlockEffect(Pawn defender, DamageInfo dinfo, bool ranged) { - MoteMaker.ThrowMicroSparks(defender.Position.ToVector3(), defender.Map); + FleckMaker.ThrowMicroSparks(defender.Position.ToVector3(), defender.Map); } /// @@ -136,30 +129,25 @@ public virtual void MakeBlockEffect(Pawn defender, DamageInfo dinfo, bool ranged /// Shield bearer. public virtual void RenderShield(Vector3 loc, Rot4 rot, Pawn pawn, Thing thing) { - bool carryShieldOpenly = - (pawn.carryTracker == null || pawn.carryTracker.CarriedThing == null) && - (pawn.Drafted || (pawn.CurJob != null && pawn.CurJob.def.alwaysShowWeapon) || - (pawn.mindState.duty != null && pawn.mindState.duty.def.alwaysShowWeapon)); - - if (!ShieldProps.renderProperties.renderWhenPeaceful && !carryShieldOpenly) + if (!ShieldProps.renderProperties.renderWhenPeaceful && !pawnRendererCarryWeaponOpenly(pawn.Drawer.renderer)) return; if (ShieldProps.wieldedGraphic != null && ShieldProps.wieldedGraphic.Graphic.MatSingle != null) { - if(rot == Rot4.North) + if (rot == Rot4.North) { - float angle = -thing.def.equippedAngleOffset; + var angle = -thing.def.equippedAngleOffset; if (ShieldProps.renderProperties.flipRotation) angle = -angle; - if(ShieldProps.useColoredVersion) + if (ShieldProps.useColoredVersion) ShieldProps.wieldedGraphic.GraphicColoredFor(thing).Draw(loc, rot, thing, angle); else ShieldProps.wieldedGraphic.Graphic.Draw(loc, rot, thing, angle); } else if (rot == Rot4.South) { - float angle = thing.def.equippedAngleOffset; + var angle = thing.def.equippedAngleOffset; if (ShieldProps.renderProperties.flipRotation) angle = -angle; @@ -183,11 +171,9 @@ public virtual void RenderShield(Vector3 loc, Rot4 rot, Pawn pawn, Thing thing) } } - /*public override void CompTick() - { - base.CompTick(); - - Log.Message("Shield tick!"); - }*/ + // Note: This is an open instance delegate where the first argument is the instance. + private static readonly Func pawnRendererCarryWeaponOpenly = + (Func)AccessTools.Method(typeof(PawnRenderer), "CarryWeaponOpenly") + .CreateDelegate(typeof(Func)); } } diff --git a/Source/AllModdingComponents/PawnShields/ThingComps/Properties/CompProperties_Shield.cs b/Source/AllModdingComponents/PawnShields/ThingComps/Properties/CompProperties_Shield.cs index 471ac3fa..1f93b3d4 100644 --- a/Source/AllModdingComponents/PawnShields/ThingComps/Properties/CompProperties_Shield.cs +++ b/Source/AllModdingComponents/PawnShields/ThingComps/Properties/CompProperties_Shield.cs @@ -1,8 +1,7 @@ -using RimWorld; -using System; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using RimWorld; +using UnityEngine; using Verse; namespace PawnShields @@ -28,14 +27,11 @@ public class CompProperties_Shield : CompProperties public ShieldRenderProperties renderProperties = new ShieldRenderProperties(); /// - /// Do the shield take damage when blocking? + /// Does the shield take damage when blocking? /// public bool shieldTakeDamage = true; - /// - /// How much of the damage the shield absorbs upon successful block. - /// - [Obsolete] + [Obsolete("use the Shield_DamageAbsorbed stat")] public float shieldTakeDamageFactor = 0.8f; /// @@ -48,35 +44,29 @@ public class CompProperties_Shield : CompProperties /// public bool canBlockMelee = true; - /// - /// Melee block chance factor the shield provides which is multiplied by the relevant statistic. 1.0 is equivalent to unchanged. - /// - [Obsolete] + [Obsolete("use the Shield_BaseMeleeBlockChance stat")] public float meleeBlockChanceFactor = 1.0f; - /// - /// Ranged block chance factor the shield provides which is multiplied by the relevant statistic. 1.0 is equivalent to unchanged. - /// - [Obsolete] + [Obsolete("use the Shield_BaseRangedBlockChance stat")] public float rangedBlockChanceFactor = 0.5f; /// - /// Determines whether the shield can be automatically discarded by a pawn or not. + /// Determines whether the shield can be automatically discarded by the shield wielder or not. /// public bool canBeAutoDiscarded = true; /// - /// The % threshold when the shield is automatically discarded by the pawn. + /// The hit points percentage threshold when the shield is automatically discarded by the shield wielder. /// public float healthAutoDiscardThreshold = 0.19f; /// - /// If true the shield user gets fatigued when blocking with the shield. + /// If true the shield wielder gets fatigued from a blocked attack. /// public bool useFatigue = false; /// - /// How much damage is converted to fatigue damage on successful block. + /// How much percent of the damage is converted to fatigue damage on a blocked attack. /// public float damageToFatigueFactor = 0.05f; @@ -89,7 +79,7 @@ public class CompProperties_Shield : CompProperties /// Default blocking sound if no sounds are defined. /// public SoundDef defaultSound = null; -//SoundDefOf.MetalHitImportant; + //SoundDefOf.MetalHitImportant; /// /// Helps fetching sounds easier. @@ -97,25 +87,50 @@ public class CompProperties_Shield : CompProperties [Unsaved] public Dictionary stuffedSounds = new Dictionary(); - /*public override IEnumerable SpecialDisplayStats() + public override IEnumerable SpecialDisplayStats(StatRequest req) + { + yield return GetStatDrawEntry("ShieldHitPointAutoDiscardThreshold", canBeAutoDiscarded, healthAutoDiscardThreshold, 2); + yield return GetStatDrawEntry("ShieldDamageToFatigueFactor", useFatigue, damageToFatigueFactor, 1); + } + + private static StatDrawEntry GetStatDrawEntry(string baseKey, bool enabled, float value, int displayPriorityWithinCategory) { - yield return new StatDrawEntry(ShieldStatsDefOf.Shield, ShieldStatsDefOf.Shield_BaseMeleeBlockChance); - yield return new StatDrawEntry(ShieldStatsDefOf.Shield, ShieldStatsDefOf.Shield_BaseRangedBlockChance); - yield return new StatDrawEntry(ShieldStatsDefOf.Shield, ShieldStatsDefOf.Shield_DamageAbsorbed); - }*/ + var valueString = (enabled ? value : 0f).ToStringPercent(); + var reportText = $"{(baseKey + "Ex").Translate()}\n\n{"StatsReport_FinalValue".Translate()}: {valueString}"; + if (!enabled) + reportText += $" ({(baseKey + "Never").Translate()})"; + return new StatDrawEntry(ShieldStatsDefOf.Shield, baseKey.Translate(), valueString, reportText, displayPriorityWithinCategory); + } public override void ResolveReferences(ThingDef parentDef) { base.ResolveReferences(parentDef); - //Setup dictionary. - if(sounds != null) + // Setup stuffed sounds dictionary. + if (sounds != null) { - foreach(StuffedSound stuffedSound in sounds) + foreach (var stuffedSound in sounds) { stuffedSounds[stuffedSound.stuffCategory] = stuffedSound.sound; } } + + // Default missing stat bases to obsolete field values. +#pragma warning disable CS0618 // Type or member is obsolete + SetDefaultStatBaseValue(parentDef, ShieldStatsDefOf.Shield_DamageAbsorbed, shieldTakeDamageFactor); + // Note: Some existing mods use erroneous numbers like 10.0 or treat it like a percentage (0-100 rather than 0-1), + // and never noticed any issues because the melee/rangedBlockChanceFactor fields never actually worked + // (Shield_BaseMeleeBlockChance defaulted to 1 (100%) and Shield_BaseRangedBlockChance defaulted to 0.5 (50%), + // so to prevent a sudden buff in block chance for pawns with poor melee skills, cap melee/RangedBlockChanceFactor values at 1 (100%). + SetDefaultStatBaseValue(parentDef, ShieldStatsDefOf.Shield_BaseMeleeBlockChance, Mathf.Min(meleeBlockChanceFactor, 1.0f)); + SetDefaultStatBaseValue(parentDef, ShieldStatsDefOf.Shield_BaseRangedBlockChance, Mathf.Min(rangedBlockChanceFactor, 1.0f)); +#pragma warning restore CS0618 // Type or member is obsolete + } + + private static void SetDefaultStatBaseValue(ThingDef parentDef, StatDef statDef, float defaultBaseValue) + { + if (!parentDef.StatBaseDefined(statDef)) + parentDef.SetStatBaseValue(statDef, defaultBaseValue); } public CompProperties_Shield() diff --git a/Source/AllModdingComponents/PawnShields/ThingComps/Properties/ShieldRenderProperties.cs b/Source/AllModdingComponents/PawnShields/ThingComps/Properties/ShieldRenderProperties.cs index edcebf44..8847ac72 100644 --- a/Source/AllModdingComponents/PawnShields/ThingComps/Properties/ShieldRenderProperties.cs +++ b/Source/AllModdingComponents/PawnShields/ThingComps/Properties/ShieldRenderProperties.cs @@ -43,7 +43,7 @@ public class ShieldRenderProperties /// /// Rotation to give for. /// Appropiate offset. - public Vector3 Rot4ToVector3(Rot4 rot) + public Vector3 OffsetFromRotation(Rot4 rot) { if (rot == Rot4.North) return northOffset; diff --git a/Source/AllModdingComponents/PawnShields/ThingComps/Properties/StuffedSound.cs b/Source/AllModdingComponents/PawnShields/ThingComps/Properties/StuffedSound.cs index 84cadb39..72322b58 100644 --- a/Source/AllModdingComponents/PawnShields/ThingComps/Properties/StuffedSound.cs +++ b/Source/AllModdingComponents/PawnShields/ThingComps/Properties/StuffedSound.cs @@ -1,9 +1,5 @@ -using RimWorld; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; +using System.Xml; +using RimWorld; using Verse; namespace PawnShields diff --git a/Source/AllModdingComponents/PawnShields/Utility/HarmonyExtensions.cs b/Source/AllModdingComponents/PawnShields/Utility/HarmonyExtensions.cs new file mode 100644 index 00000000..27d59060 --- /dev/null +++ b/Source/AllModdingComponents/PawnShields/Utility/HarmonyExtensions.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using HarmonyLib; + +namespace PawnShields +{ + // Code copied between JecsTools and PawnShields - keep them in sync! + public static class HarmonyExtensions + { + public static void SafeInsertRange(this List instructions, int insertionIndex, IEnumerable newInstructions, + IEnumerable public static HediffDef ShieldFatigue; + + static ShieldHediffDefOf() => DefOfHelper.EnsureInitializedInCtor(typeof(ShieldHediffDefOf)); } } diff --git a/Source/AllModdingComponents/PawnShields/Utility/ShieldStatsDefOf.cs b/Source/AllModdingComponents/PawnShields/Utility/ShieldStatsDefOf.cs index 44ca98ab..1cb75413 100644 --- a/Source/AllModdingComponents/PawnShields/Utility/ShieldStatsDefOf.cs +++ b/Source/AllModdingComponents/PawnShields/Utility/ShieldStatsDefOf.cs @@ -1,8 +1,4 @@ using RimWorld; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace PawnShields { @@ -41,5 +37,7 @@ public static class ShieldStatsDefOf /// Ranged shield block chance base from pawn. /// public static StatDef RangedShieldBlockChance; + + static ShieldStatsDefOf() => DefOfHelper.EnsureInitializedInCtor(typeof(ShieldStatsDefOf)); } } diff --git a/Source/AllModdingComponents/PawnShields/Utility/ShieldUtility.cs b/Source/AllModdingComponents/PawnShields/Utility/ShieldUtility.cs index 21717c58..9bc78232 100644 --- a/Source/AllModdingComponents/PawnShields/Utility/ShieldUtility.cs +++ b/Source/AllModdingComponents/PawnShields/Utility/ShieldUtility.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Verse; +using Verse; namespace PawnShields { @@ -11,6 +7,48 @@ namespace PawnShields /// public static class ShieldUtility { + // Avoiding ThingWithComps.GetComp and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast (~6x as fast for me). + public static CompShield GetCompShield(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompShield comp) + return comp; + } + return null; + } + + // Slightly faster than `thing.GetCompShield() != null` + public static bool HasCompShield(this ThingWithComps thing) + { + var comps = thing.AllComps; + for (int i = 0, count = comps.Count; i < count; i++) + { + if (comps[i] is CompShield) + return true; + } + return false; + } + + // Avoiding Def.GetModExtension and implementing a specific non-generic version of it here. + // That method is slow because the `isinst` instruction with generic type arg operands is very slow, + // while `isinst` instruction against non-generic type operand like used below is fast. + public static ShieldPawnGeneratorProperties GetShieldPawnGeneratorProperties(this Def def) + { + var modExtensions = def.modExtensions; + if (modExtensions == null) + return null; + for (int i = 0, count = modExtensions.Count; i < count; i++) + { + if (modExtensions[i] is ShieldPawnGeneratorProperties modExtension) + return modExtension; + } + return null; + } + /// /// Attempts to get the first shield from the pawn. /// @@ -20,8 +58,7 @@ public static ThingWithComps GetShield(this Pawn pawn) { if (pawn.equipment == null) return null; - - return pawn.equipment.AllEquipmentListForReading.FirstOrDefault(thing => thing.TryGetComp() != null); + return pawn.equipment.GetShield(); } /// @@ -31,7 +68,15 @@ public static ThingWithComps GetShield(this Pawn pawn) /// Shield if tracker has any or null if there is no shield. public static ThingWithComps GetShield(this Pawn_EquipmentTracker eqTracker) { - return eqTracker.AllEquipmentListForReading.FirstOrDefault(thing => thing.TryGetComp() != null); + // Note: Not using LINQ or List foreach since they're slower than index-based for loop (~5x or ~2x, respectively, for me). + var allEquipment = eqTracker.AllEquipmentListForReading; + for (int i = 0, count = allEquipment.Count; i < count; i++) + { + var equipment = allEquipment[i]; + if (equipment.HasCompShield()) + return equipment; + } + return null; } } } diff --git a/Source/AllModdingComponents/PawnShields/Workers/StatPart_ShieldStatFactor.cs b/Source/AllModdingComponents/PawnShields/Workers/StatPart_ShieldStatFactor.cs new file mode 100644 index 00000000..5259eb3d --- /dev/null +++ b/Source/AllModdingComponents/PawnShields/Workers/StatPart_ShieldStatFactor.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using RimWorld; +using Verse; + +namespace PawnShields +{ + public class StatPart_ShieldStatFactor : StatPart + { + public StatDef shieldStat; + + public override void TransformValue(StatRequest req, ref float val) + { + var shield = GetShield(req); + if (shield != null) + val *= shield.GetStatValue(shieldStat); + else + val = 0; + } + + public override string ExplanationPart(StatRequest req) + { + var shield = GetShield(req); + var value = shield?.GetStatValue(shieldStat) ?? 0f; + var text = $" {shieldStat.LabelCap}: {value.ToStringByStyle(shieldStat.toStringStyle, ToStringNumberSense.Factor)}"; + if (shield == null) + text += $" ({"ShieldNotEquipped".Translate()})"; + return text; + } + + public override IEnumerable GetInfoCardHyperlinks(StatRequest req) + { + var shield = GetShield(req); + if (shield != null) + yield return new Dialog_InfoCard.Hyperlink(shield); + } + + private static ThingWithComps GetShield(StatRequest req) + { + if (req.Thing is Pawn pawn) + return pawn.GetShield(); + return null; + } + } +} diff --git a/Source/AllModdingComponents/PawnShields/Workers/StatWorker_Shield.cs b/Source/AllModdingComponents/PawnShields/Workers/StatWorker_Shield.cs index bbbd957d..759296c5 100644 --- a/Source/AllModdingComponents/PawnShields/Workers/StatWorker_Shield.cs +++ b/Source/AllModdingComponents/PawnShields/Workers/StatWorker_Shield.cs @@ -1,24 +1,81 @@ using RimWorld; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using Verse; namespace PawnShields { - /// - /// Worker class specifically made to show off the snazzy stats for shields. - /// + // XXX: This should be an abstract class. It's only non-abstract for compatibility with stale bundled versions of PawnShields + // in other mods, and those stale versions have StatDefs that directly reference StatWorker_Shield. + // RimWorld as of version 1.1 has earlier loaded assemblies and later loaded XMLs have higher precedence, leading to a situation + // where a user can end up loading this version of PawnShields.dll and an outdated version of the StatDefs that still directly + // references StatWorker_Shield. So StatWorker_Shield must be a concrete class rather than an abstract one. public class StatWorker_Shield : StatWorker { + public override void FinalizeValue(StatRequest req, ref float val, bool applyPostProcess) + { + if (IsDisabledForShield(req)) + val = 0f; + else + base.FinalizeValue(req, ref val, applyPostProcess); + } + + public override string GetExplanationFinalizePart(StatRequest req, ToStringNumberSense numberSense, float finalVal) + { + var text = base.GetExplanationFinalizePart(req, numberSense, finalVal); + if (IsDisabledForShield(req)) + text += $" ({GetDisabledExplanation()})"; + return text; + } + + // This is needed to prevent "base value" from being shown for disabled stats. + public override string GetExplanationUnfinalized(StatRequest req, ToStringNumberSense numberSense) + { + if (IsDisabledForShield(req)) + return ""; + else + return base.GetExplanationUnfinalized(req, numberSense); + } + public override bool ShouldShowFor(StatRequest req) { - var def = req.Def as ThingDef; - if (def != null && def.HasComp(typeof(CompShield))) + if (req.Def is ThingDef def && def.HasComp(typeof(CompShield))) return true; return false; } - + + private bool IsDisabledForShield(StatRequest req) + { + if (req.Def is ThingDef def) + { + var shieldProps = def.GetCompProperties(); + if (shieldProps != null && IsDisabledForShield(shieldProps)) + return true; + } + return false; + } + + protected virtual bool IsDisabledForShield(CompProperties_Shield shieldProps) => false; + + protected virtual string GetDisabledExplanation() => ""; + } + + public class StatWorker_Shield_BaseMeleeBlockChance : StatWorker_Shield + { + protected override bool IsDisabledForShield(CompProperties_Shield shieldProps) => !shieldProps.canBlockMelee; + + protected override string GetDisabledExplanation() => "ShieldBlockMeleeNever".Translate(); + } + + public class StatWorker_Shield_BaseRangedBlockChance : StatWorker_Shield + { + protected override bool IsDisabledForShield(CompProperties_Shield shieldProps) => !shieldProps.canBlockRanged; + + protected override string GetDisabledExplanation() => "ShieldBlockRangedNever".Translate(); + } + + public class StatWorker_Shield_DamageAbsorbed : StatWorker_Shield + { + protected override bool IsDisabledForShield(CompProperties_Shield shieldProps) => !shieldProps.shieldTakeDamage; + + protected override string GetDisabledExplanation() => "ShieldAbsorbDamageNever".Translate(); } } diff --git a/Source/AllModdingComponents/ThinkNodes/JobGiver_Capture.cs b/Source/AllModdingComponents/ThinkNodes/JobGiver_Capture.cs index a77ee2f4..e3610d80 100644 --- a/Source/AllModdingComponents/ThinkNodes/JobGiver_Capture.cs +++ b/Source/AllModdingComponents/ThinkNodes/JobGiver_Capture.cs @@ -6,36 +6,38 @@ namespace ThinkNodes { public class JobGiver_Capture : ThinkNode_JobGiver { - private float targetAcquireRadius; + private float targetAcquireRadius; // set via reflection protected override Job TryGiveJob(Pawn pawn) { bool Validator(Thing t) { - Pawn pawn3 = (Pawn) t; - if (pawn3 == null) return false; - var hostileTo = pawn3.Faction == null || pawn3.Faction.HostileTo(Faction.OfPlayer) || pawn3.Faction.def.hidden; - return pawn3.Downed && hostileTo && !pawn3.InBed() && pawn.CanReserve(pawn3) && !pawn3.IsForbidden(pawn); + if (t == null) + return false; + var p = (Pawn)t; + var hostileTo = p.Faction == null || p.Faction.HostileTo(Faction.OfPlayer) || p.Faction.def.hidden; + return p.Downed && hostileTo && !p.InBed() && pawn.CanReserve(p) && !p.IsForbidden(pawn); } - Pawn victim = (Pawn)GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, + var victim = (Pawn)GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.OnCell, TraverseParms.For(pawn), targetAcquireRadius, Validator); if (victim == null) { return null; } - - Building_Bed buildingBed = RestUtility.FindBedFor(victim, pawn, true, false) ?? - RestUtility.FindBedFor(victim, pawn, true, false, true); + + var buildingBed = + RestUtility.FindBedFor(victim, pawn, checkSocialProperness: false, ignoreOtherReservations: false, GuestStatus.Prisoner) ?? + RestUtility.FindBedFor(victim, pawn, checkSocialProperness: false, ignoreOtherReservations: true, GuestStatus.Prisoner); if (buildingBed == null) { return null; } - var job = new Job(JobDefOf.Capture, victim, buildingBed) {count = 1}; - + var job = JobMaker.MakeJob(JobDefOf.Capture, victim, buildingBed); + job.count = 1; return job; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/ThinkNodes/JobGiver_GoToClosestThingDef.cs b/Source/AllModdingComponents/ThinkNodes/JobGiver_GoToClosestThingDef.cs index ec0d7038..977d34d6 100644 --- a/Source/AllModdingComponents/ThinkNodes/JobGiver_GoToClosestThingDef.cs +++ b/Source/AllModdingComponents/ThinkNodes/JobGiver_GoToClosestThingDef.cs @@ -6,31 +6,31 @@ namespace ThinkNodes { public class JobGiver_GoToClosestThingDef : ThinkNode_JobGiver { - Danger maxDanger = Verse.Danger.Some; - ThingDef thingDef = ThingDefOf.PartySpot; + // Set via reflection + private Danger maxDanger = Verse.Danger.Some; + private ThingDef thingDef = ThingDefOf.PartySpot; protected override Job TryGiveJob(Pawn pawn) { var thing = ThingToDo(pawn); - + if (thing != null) { if (!thing.Position.IsValid) - return (Job) null; - if (!pawn.CanReach((LocalTargetInfo) thing.Position, PathEndMode.ClosestTouch, maxDanger)) + return null; + if (!pawn.CanReach(thing.Position, PathEndMode.ClosestTouch, maxDanger)) { - return (Job) null; + return null; } if (IntVec3Utility.DistanceTo(thing.Position, pawn.Position) < 10f) { return null; } - - return new Job(JobDefOf.Goto, (LocalTargetInfo) thing.Position) - { - locomotionUrgency = LocomotionUrgency.Sprint - }; + + var job = JobMaker.MakeJob(JobDefOf.Goto, thing.Position); + job.locomotionUrgency = LocomotionUrgency.Sprint; + return job; } else return null; @@ -38,10 +38,10 @@ protected override Job TryGiveJob(Pawn pawn) private Thing ThingToDo(Pawn pawn) { - ThingDef singleDef = WhatDef(); + var singleDef = WhatDef(); var thingRequest = ThingRequest.ForDef(singleDef); - Thing closestPosition = ClosestPosition(pawn, thingRequest); + var closestPosition = ClosestPosition(pawn, thingRequest); return closestPosition; } @@ -63,4 +63,4 @@ protected virtual ThingDef WhatDef() return thingDef; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalDelay.cs b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalDelay.cs index 8c68654f..3f3f5462 100644 --- a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalDelay.cs +++ b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalDelay.cs @@ -6,9 +6,10 @@ namespace ThinkNodes { public class ThinkNode_ConditionalDelay : ThinkNode_Conditional { - public int min = 1000, max= 2000; - + // Set via reflection + public int min = 1000, max = 2000; private Dictionary delays = new Dictionary(); + protected override bool Satisfied(Pawn pawn) { var key = GetKey(pawn); @@ -39,4 +40,4 @@ public virtual void AddDelay(string key) delays[key] = Find.TickManager.TicksGame + Rand.Range(min, max); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalHediff.cs b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalHediff.cs index 6007c3f1..10e5ac46 100644 --- a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalHediff.cs +++ b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalHediff.cs @@ -1,5 +1,4 @@ -using System.Linq; -using Verse; +using Verse; using Verse.AI; namespace ThinkNodes @@ -10,13 +9,14 @@ public class ThinkNode_ConditionalHediff : ThinkNode_Conditional protected override bool Satisfied(Pawn pawn) { - if (pawn.Drafted) return false; - foreach (var unused in pawn.health.hediffSet.hediffs.Where(x => x.def.defName.EqualsIgnoreCase(hediffDef))) + if (pawn.Drafted) + return false; + foreach (var hediff in pawn.health.hediffSet.hediffs) { - return true; + if (hediff.def.defName.EqualsIgnoreCase(hediffDef)) + return true; } - return false; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalHunter.cs b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalHunter.cs index ec48e858..fd4966c8 100644 --- a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalHunter.cs +++ b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalHunter.cs @@ -7,7 +7,7 @@ namespace ThinkNodes public class ThinkNode_ConditionalHunter : ThinkNode_Conditional { public bool allowBrawlers = false; - + protected override bool Satisfied(Pawn pawn) { return AmHunter(pawn) && (allowBrawlers || !pawn.story.traits.HasTrait(TraitDefOf.Brawler)); @@ -18,4 +18,4 @@ public static bool AmHunter(Pawn pawn) return pawn.workSettings.WorkIsActive(WorkTypeDefOf.Hunting); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalMissingWeapon.cs b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalMissingWeapon.cs index f46e1ab5..5a6486eb 100644 --- a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalMissingWeapon.cs +++ b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalMissingWeapon.cs @@ -11,4 +11,4 @@ protected override bool Satisfied(Pawn pawn) return !WorkGiver_HunterHunt.HasHuntingWeapon(pawn); } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalWorkTypesDef.cs b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalWorkTypesDef.cs index 7038270c..c036d5cb 100644 --- a/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalWorkTypesDef.cs +++ b/Source/AllModdingComponents/ThinkNodes/ThinkNode_ConditionalWorkTypesDef.cs @@ -6,18 +6,16 @@ namespace ThinkNodes { public class ThinkNodeConditionalWorkTypes : ThinkNode_Conditional { - private List workTypeDefs = new List(); + private List workTypeDefs = new List(); // set via reflection protected override bool Satisfied(Pawn pawn) { foreach (var _def in workTypeDefs) { - if (pawn.IsColonist && (pawn?.workSettings?.WorkIsActive(_def) ?? false)) + if (pawn.IsColonist && (pawn.workSettings?.WorkIsActive(_def) ?? false)) return true; } - - return false; } } -} \ No newline at end of file +} diff --git a/Source/AllModdingComponents/ThinkNodes/ThinkNodes.csproj b/Source/AllModdingComponents/ThinkNodes/ThinkNodes.csproj index 7956932b..d3648296 100644 --- a/Source/AllModdingComponents/ThinkNodes/ThinkNodes.csproj +++ b/Source/AllModdingComponents/ThinkNodes/ThinkNodes.csproj @@ -1,82 +1,7 @@  - - + + - Debug - AnyCPU - {D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA} - Library - Properties - ThinkNodes ThinkNodes - v4.7.2 - 512 - - - false - none - false - ..\..\..\Assemblies\ - - - prompt - 4 - false - - - none - true - ..\..\..\Assemblies\ - - - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - 1.1.2566 - - - 2.0.0.8 - - - - - - - - - Program - $(SolutionDir)..\..\RimWorldWin.exe - - - :: Commented out to allow for building in VS2017 by Jec -:: echo F|xcopy "$(ProjectDir)..\About\About-$(ConfigurationName).xml" "$(TargetDir)..\About\About.xml" /C /Y /K /Q /D -:: IF /I "$(ConfigurationName)" == "Release"; echo F|xcopy "$(ProjectDir)..\About\Preview.png" "$(TargetDir)..\About\Preview.png" /S /C /Y /K /Q /D -:: IF /I "$(ConfigurationName)" == "Release"; xcopy "$(ProjectDir)..\Assemblies" "$(TargetDir)..\Assemblies" /S /C /Y /K /I /Q /D -:: IF /I "$(ConfigurationName)" == "Release"; xcopy "$(ProjectDir)..\Defs" "$(TargetDir)..\Defs" /S /C /Y /K /I /Q /D -:: IF /I "$(ConfigurationName)" == "Release"; xcopy "$(ProjectDir)..\Patches" "$(TargetDir)..\Patches" /S /C /Y /K /I /Q /D -:: IF /I "$(ConfigurationName)" == "Release"; xcopy "$(ProjectDir)..\Languages" "$(TargetDir)..\Languages" /S /C /Y /K /I /Q /D -:: IF /I "$(ConfigurationName)" == "Release"; xcopy "$(ProjectDir)..\Sounds" "$(TargetDir)..\Sounds" /S /C /Y /K /I /Q /D -:: IF /I "$(ConfigurationName)" == "Release"; xcopy "$(ProjectDir)..\Textures" "$(TargetDir)..\Textures" /S /C /Y /K /I /Q /D -:: IF /I "$(ConfigurationName)" == "Release"; IF EXIST "$(ProjectDir)..\LICENSE"; copy "$(ProjectDir)..\LICENSE" "$(TargetDir)..\LICENSE" /Y - - \ No newline at end of file + diff --git a/Source/JecsTools.sln b/Source/JecsTools.sln index 5dec093b..1b508d86 100755 --- a/Source/JecsTools.sln +++ b/Source/JecsTools.sln @@ -1,135 +1,57 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -<<<<<<< Updated upstream -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.12 -======= # Visual Studio Version 17 VisualStudioVersion = 17.1.32210.238 ->>>>>>> Stashed changes MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompAbilityUser", "AllModdingComponents\CompAbilityUser\CompAbilityUser.csproj", "{417B8649-7A66-4580-8C75-473E46DA9C7A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompAbilityUser", "AllModdingComponents\CompAbilityUser\CompAbilityUser.csproj", "{417B8649-7A66-4580-8C75-473E46DA9C7A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompActivatableEffect", "AllModdingComponents\CompActivatableEffect\CompActivatableEffect.csproj", "{EC1AEA45-45FE-4A6A-A835-81B289E03BC9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompActivatableEffect", "AllModdingComponents\CompActivatableEffect\CompActivatableEffect.csproj", "{EC1AEA45-45FE-4A6A-A835-81B289E03BC9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompDeflector", "AllModdingComponents\CompDeflector\CompDeflector.csproj", "{4A2FA470-0CA5-442B-B04D-2C4A62859CA7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompDeflector", "AllModdingComponents\CompDeflector\CompDeflector.csproj", "{4A2FA470-0CA5-442B-B04D-2C4A62859CA7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompExtraSounds", "AllModdingComponents\CompExtraSounds\CompExtraSounds.csproj", "{05E24FAB-C6BF-43B5-BF69-B92AA38338CA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompExtraSounds", "AllModdingComponents\CompExtraSounds\CompExtraSounds.csproj", "{05E24FAB-C6BF-43B5-BF69-B92AA38338CA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompLumbering", "AllModdingComponents\CompLumbering\CompLumbering.csproj", "{CF56EA3A-AEC6-4817-BF46-A886FBEAA49B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompLumbering", "AllModdingComponents\CompLumbering\CompLumbering.csproj", "{CF56EA3A-AEC6-4817-BF46-A886FBEAA49B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompOversizedWeapon", "AllModdingComponents\CompOversizedWeapon\CompOversizedWeapon.csproj", "{08E20D0E-4493-4DFE-9212-DEC323F26E89}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompOversizedWeapon", "AllModdingComponents\CompOversizedWeapon\CompOversizedWeapon.csproj", "{08E20D0E-4493-4DFE-9212-DEC323F26E89}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompSlotLoadable", "AllModdingComponents\CompSlotLoadable\CompSlotLoadable.csproj", "{6EC26D07-B5A0-4075-8919-3B05AF74CE87}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompSlotLoadable", "AllModdingComponents\CompSlotLoadable\CompSlotLoadable.csproj", "{6EC26D07-B5A0-4075-8919-3B05AF74CE87}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompVehicle", "AllModdingComponents\CompVehicle\CompVehicle.csproj", "{6E907669-2299-47E1-B144-8BC7488DF5C4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompInstalledPart", "AllModdingComponents\CompInstalledPart\CompInstalledPart.csproj", "{6ADE9377-5108-4C79-A3E8-034A7EBCC37F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompInstalledPart", "AllModdingComponents\CompInstalledPart\CompInstalledPart.csproj", "{6ADE9377-5108-4C79-A3E8-034A7EBCC37F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompToggleDef", "AllModdingComponents\CompToggleDef\CompToggleDef.csproj", "{9BECA870-0C2F-4F40-BEA1-6E99D68F9EDF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompToggleDef", "AllModdingComponents\CompToggleDef\CompToggleDef.csproj", "{9BECA870-0C2F-4F40-BEA1-6E99D68F9EDF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JecsTools", "AllModdingComponents\JecsTools\JecsTools.csproj", "{106BF102-0379-41CF-9C5D-E21AAC5F051B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JecsTools", "AllModdingComponents\JecsTools\JecsTools.csproj", "{106BF102-0379-41CF-9C5D-E21AAC5F051B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompDelayedSpawner", "AllModdingComponents\CompDelayedSpawner\CompDelayedSpawner.csproj", "{4074F652-2FDA-41D0-A631-F6C83A2351F1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompDelayedSpawner", "AllModdingComponents\CompDelayedSpawner\CompDelayedSpawner.csproj", "{4074F652-2FDA-41D0-A631-F6C83A2351F1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AbilityUserAI", "AllModdingComponents\AbilityUserAI\AbilityUserAI.csproj", "{4FC16277-5CB6-4A78-90FB-27F09888708A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbilityUserAI", "AllModdingComponents\AbilityUserAI\AbilityUserAI.csproj", "{4FC16277-5CB6-4A78-90FB-27F09888708A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompOverlays", "AllModdingComponents\CompOverlays\CompOverlays.csproj", "{947FF025-5DE9-4475-8779-4E9B02D06FB7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompOverlays", "AllModdingComponents\CompOverlays\CompOverlays.csproj", "{947FF025-5DE9-4475-8779-4E9B02D06FB7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompAnimated", "AllModdingComponents\CompAnimated\CompAnimated.csproj", "{29E2AEA4-3154-42DF-87CF-AEAFF042F2E0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompAnimated", "AllModdingComponents\CompAnimated\CompAnimated.csproj", "{29E2AEA4-3154-42DF-87CF-AEAFF042F2E0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PawnShields", "AllModdingComponents\PawnShields\PawnShields.csproj", "{9A3BF1D4-6693-481F-BBF1-3D66AFD8BE6C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PawnShields", "AllModdingComponents\PawnShields\PawnShields.csproj", "{9A3BF1D4-6693-481F-BBF1-3D66AFD8BE6C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompBalloon", "AllModdingComponents\CompBalloon\CompBalloon.csproj", "{CE293DBE-D76A-4F24-A086-42051996698D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompBalloon", "AllModdingComponents\CompBalloon\CompBalloon.csproj", "{CE293DBE-D76A-4F24-A086-42051996698D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThinkNodes", "AllModdingComponents\ThinkNodes\ThinkNodes.csproj", "{D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThinkNodes", "AllModdingComponents\ThinkNodes\ThinkNodes.csproj", "{D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DefModExtension_BigBox", "AllModdingComponents\CompBigBox\DefModExtension_BigBox.csproj", "{CB5B70DA-38FB-4C54-A816-7112CA045235}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DefModExtension_BigBox", "AllModdingComponents\CompBigBox\DefModExtension_BigBox.csproj", "{CB5B70DA-38FB-4C54-A816-7112CA045235}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{866CC95E-EC26-49B1-8E5C-2D312BE4BDC3}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + AllModdingComponents\Directory.Build.props = AllModdingComponents\Directory.Build.props + EndProjectSection +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "!Shared", "Shared\!Shared.shproj", "{C30579D1-0532-46B4-98CE-FA5CEFA87A43}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution -<<<<<<< Updated upstream - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU + GlobalSection(SharedMSBuildProjectFiles) = preSolution + Shared\!Shared.projitems*{c30579d1-0532-46b4-98ce-fa5cefa87a43}*SharedItemsImports = 13 EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {417B8649-7A66-4580-8C75-473E46DA9C7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {417B8649-7A66-4580-8C75-473E46DA9C7A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {417B8649-7A66-4580-8C75-473E46DA9C7A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {417B8649-7A66-4580-8C75-473E46DA9C7A}.Release|Any CPU.Build.0 = Release|Any CPU - {EC1AEA45-45FE-4A6A-A835-81B289E03BC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EC1AEA45-45FE-4A6A-A835-81B289E03BC9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EC1AEA45-45FE-4A6A-A835-81B289E03BC9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EC1AEA45-45FE-4A6A-A835-81B289E03BC9}.Release|Any CPU.Build.0 = Release|Any CPU - {4A2FA470-0CA5-442B-B04D-2C4A62859CA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A2FA470-0CA5-442B-B04D-2C4A62859CA7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A2FA470-0CA5-442B-B04D-2C4A62859CA7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A2FA470-0CA5-442B-B04D-2C4A62859CA7}.Release|Any CPU.Build.0 = Release|Any CPU - {05E24FAB-C6BF-43B5-BF69-B92AA38338CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {05E24FAB-C6BF-43B5-BF69-B92AA38338CA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {05E24FAB-C6BF-43B5-BF69-B92AA38338CA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {05E24FAB-C6BF-43B5-BF69-B92AA38338CA}.Release|Any CPU.Build.0 = Release|Any CPU - {CF56EA3A-AEC6-4817-BF46-A886FBEAA49B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CF56EA3A-AEC6-4817-BF46-A886FBEAA49B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CF56EA3A-AEC6-4817-BF46-A886FBEAA49B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CF56EA3A-AEC6-4817-BF46-A886FBEAA49B}.Release|Any CPU.Build.0 = Release|Any CPU - {08E20D0E-4493-4DFE-9212-DEC323F26E89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {08E20D0E-4493-4DFE-9212-DEC323F26E89}.Debug|Any CPU.Build.0 = Debug|Any CPU - {08E20D0E-4493-4DFE-9212-DEC323F26E89}.Release|Any CPU.ActiveCfg = Release|Any CPU - {08E20D0E-4493-4DFE-9212-DEC323F26E89}.Release|Any CPU.Build.0 = Release|Any CPU - {6EC26D07-B5A0-4075-8919-3B05AF74CE87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6EC26D07-B5A0-4075-8919-3B05AF74CE87}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6EC26D07-B5A0-4075-8919-3B05AF74CE87}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6EC26D07-B5A0-4075-8919-3B05AF74CE87}.Release|Any CPU.Build.0 = Release|Any CPU - {6E907669-2299-47E1-B144-8BC7488DF5C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6E907669-2299-47E1-B144-8BC7488DF5C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6E907669-2299-47E1-B144-8BC7488DF5C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6E907669-2299-47E1-B144-8BC7488DF5C4}.Release|Any CPU.Build.0 = Release|Any CPU - {6ADE9377-5108-4C79-A3E8-034A7EBCC37F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6ADE9377-5108-4C79-A3E8-034A7EBCC37F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6ADE9377-5108-4C79-A3E8-034A7EBCC37F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6ADE9377-5108-4C79-A3E8-034A7EBCC37F}.Release|Any CPU.Build.0 = Release|Any CPU - {9BECA870-0C2F-4F40-BEA1-6E99D68F9EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9BECA870-0C2F-4F40-BEA1-6E99D68F9EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9BECA870-0C2F-4F40-BEA1-6E99D68F9EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9BECA870-0C2F-4F40-BEA1-6E99D68F9EDF}.Release|Any CPU.Build.0 = Release|Any CPU - {106BF102-0379-41CF-9C5D-E21AAC5F051B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {106BF102-0379-41CF-9C5D-E21AAC5F051B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {106BF102-0379-41CF-9C5D-E21AAC5F051B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {106BF102-0379-41CF-9C5D-E21AAC5F051B}.Release|Any CPU.Build.0 = Release|Any CPU - {4074F652-2FDA-41D0-A631-F6C83A2351F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4074F652-2FDA-41D0-A631-F6C83A2351F1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4074F652-2FDA-41D0-A631-F6C83A2351F1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4074F652-2FDA-41D0-A631-F6C83A2351F1}.Release|Any CPU.Build.0 = Release|Any CPU - {4FC16277-5CB6-4A78-90FB-27F09888708A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4FC16277-5CB6-4A78-90FB-27F09888708A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4FC16277-5CB6-4A78-90FB-27F09888708A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4FC16277-5CB6-4A78-90FB-27F09888708A}.Release|Any CPU.Build.0 = Release|Any CPU - {947FF025-5DE9-4475-8779-4E9B02D06FB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {947FF025-5DE9-4475-8779-4E9B02D06FB7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {947FF025-5DE9-4475-8779-4E9B02D06FB7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {947FF025-5DE9-4475-8779-4E9B02D06FB7}.Release|Any CPU.Build.0 = Release|Any CPU - {29E2AEA4-3154-42DF-87CF-AEAFF042F2E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {29E2AEA4-3154-42DF-87CF-AEAFF042F2E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29E2AEA4-3154-42DF-87CF-AEAFF042F2E0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {29E2AEA4-3154-42DF-87CF-AEAFF042F2E0}.Release|Any CPU.Build.0 = Release|Any CPU - {9A3BF1D4-6693-481F-BBF1-3D66AFD8BE6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9A3BF1D4-6693-481F-BBF1-3D66AFD8BE6C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9A3BF1D4-6693-481F-BBF1-3D66AFD8BE6C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9A3BF1D4-6693-481F-BBF1-3D66AFD8BE6C}.Release|Any CPU.Build.0 = Release|Any CPU - {CE293DBE-D76A-4F24-A086-42051996698D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE293DBE-D76A-4F24-A086-42051996698D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE293DBE-D76A-4F24-A086-42051996698D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE293DBE-D76A-4F24-A086-42051996698D}.Release|Any CPU.Build.0 = Release|Any CPU - {D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}.Release|Any CPU.Build.0 = Release|Any CPU - {CB5B70DA-38FB-4C54-A816-7112CA045235}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CB5B70DA-38FB-4C54-A816-7112CA045235}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CB5B70DA-38FB-4C54-A816-7112CA045235}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CB5B70DA-38FB-4C54-A816-7112CA045235}.Release|Any CPU.Build.0 = Release|Any CPU -======= + GlobalSection(SolutionConfigurationPlatforms) = preSolution RW1.3|Any CPU = RW1.3|Any CPU RW1.3Unstable|Any CPU = RW1.3Unstable|Any CPU RW1.4|Any CPU = RW1.4|Any CPU @@ -280,7 +202,6 @@ Global {CB5B70DA-38FB-4C54-A816-7112CA045235}.RW1.4|Any CPU.Build.0 = RW1.3Unstable|Any CPU {CB5B70DA-38FB-4C54-A816-7112CA045235}.RW1.4Unstable|Any CPU.ActiveCfg = RW1.4Unstable|Any CPU {CB5B70DA-38FB-4C54-A816-7112CA045235}.RW1.4Unstable|Any CPU.Build.0 = RW1.4Unstable|Any CPU ->>>>>>> Stashed changes EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Shared/!Shared.projitems b/Source/Shared/!Shared.projitems new file mode 100644 index 00000000..fe69f5e4 --- /dev/null +++ b/Source/Shared/!Shared.projitems @@ -0,0 +1,17 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + c30579d1-0532-46b4-98ce-fa5cefa87a43 + + + Shared + + + + ModFolder\%(RecursiveDir)%(Filename)%(Extension) + Never + + + diff --git a/Source/Shared/!Shared.shproj b/Source/Shared/!Shared.shproj new file mode 100644 index 00000000..43c93fbb --- /dev/null +++ b/Source/Shared/!Shared.shproj @@ -0,0 +1,13 @@ + + + + c30579d1-0532-46b4-98ce-fa5cefa87a43 + 14.0 + + + + + + + + diff --git a/_PublisherPlus.xml b/_PublisherPlus.xml new file mode 100644 index 00000000..53dccf9f --- /dev/null +++ b/_PublisherPlus.xml @@ -0,0 +1,25 @@ + + + + .git + Source\.vs + Source\AllModdingComponents\AbilityUserAI\obj + Source\AllModdingComponents\CompAbilityUser\obj + Source\AllModdingComponents\CompActivatableEffect\obj + Source\AllModdingComponents\CompAnimated\obj + Source\AllModdingComponents\CompBalloon\obj + Source\AllModdingComponents\CompBigBox\obj + Source\AllModdingComponents\CompDeflector\obj + Source\AllModdingComponents\CompDelayedSpawner\obj + Source\AllModdingComponents\CompExtraSounds\obj + Source\AllModdingComponents\CompInstalledPart\obj + Source\AllModdingComponents\CompLumbering\obj + Source\AllModdingComponents\CompOverlays\obj + Source\AllModdingComponents\CompOversizedWeapon\obj + Source\AllModdingComponents\CompSlotLoadable\obj + Source\AllModdingComponents\CompToggleDef\obj + Source\AllModdingComponents\JecsTools\obj + Source\AllModdingComponents\PawnShields\obj + Source\AllModdingComponents\ThinkNodes\obj + + diff --git a/updateinfo b/updateinfo index 67a9686f..f3cbf58a 100644 --- a/updateinfo +++ b/updateinfo @@ -3,14 +3,14 @@ ============================== JecsTools Update -v1.1.1.0 (03-15-2020) +v1.3.0.4 (07-31-2021) ==================== -AbilityUser should now report when line of sight failure takes place for abilities. Extra damages no longer gives errors in combat logs. +Workaround for mod lists that contain other mods with an outdated copy of CompOversizedWeapon that's loaded before ours -lbmaian -------------------- Download now on... -- Patreon: https://www.patreon.com/posts/34452021 +- Patreon: https://www.patreon.com/posts/54071148 - GitHub: https://github.com/jecrell/JecsTools - Steam: https://steamcommunity.com/sharedfiles/filedetails/?id=932008009 Discuss the mod on... @@ -25,12 +25,12 @@ Discuss the mod on... [img width=260]https://raw.githubusercontent.com/jecrell/JecsTools/master/About/Preview.png[/img] [hr] [b]JecsTools -Version: 1.1.1.0 -Updated: 03-15-2020 -Description: [color=orange]AbilityUser should now report when line of sight failure takes place for abilities. Extra damages no longer gives errors in combat logs.[/color] +Version: 1.3.0.4 +Updated: 07-31-2021 +Description: [color=orange]Workaround for mod lists that contain other mods with an outdated copy of CompOversizedWeapon that's loaded before ours -lbmaian[/color] [hr] [b]Download now on...[/b] -[url=https://www.patreon.com/posts/34452021]Patreon[/url] +[url=https://www.patreon.com/posts/54071148]Patreon[/url] [url=https://github.com/jecrell/JecsTools]GitHub[/url] [url=https://steamcommunity.com/sharedfiles/filedetails/?id=932008009]Steam[/url] [b]Discuss the mod on...[/b]

    - v1.0.9.1 + Version Documentation @@ -15,48 +15,48 @@