diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index b7f1f347..4768d82b 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/Effects/WulaFleckDefs.xml b/1.6/1.6/Defs/Effects/WulaFleckDefs.xml index 574b6491..fa4885d3 100644 --- a/1.6/1.6/Defs/Effects/WulaFleckDefs.xml +++ b/1.6/1.6/Defs/Effects/WulaFleckDefs.xml @@ -22,11 +22,14 @@ WULA_GunTail_Lighting Projectile - 0.5 + 0.50 + 1 + 1.2 + 0.005 Wula/Mote/WULA_Lighting_Beam MoteGlow - (113,165,225,155) + (113,165,225,255) (0.5,2) diff --git a/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml b/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml index c37c9681..a8153791 100644 --- a/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml +++ b/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml @@ -27,6 +27,13 @@ 1 Int + + +
  • + Wula_Legion_Personal_Goodwill + 0 + Int +
  • @@ -41,6 +48,9 @@
  • +
  • + Wula_UI_Legion_10 +
  • @@ -68,6 +78,28 @@
    +
  • + + + false + false + +
  • + +
  • + Wula_UI_Legion_50 +
  • +
  • + +
  • + +
  • true @@ -124,6 +156,218 @@ + + Wula_UI_Legion_10 + + Wula/Events/Portraits/WULA_Legion_5 + 「军团」,P.I.A + +
  • 嗯嗯?
  • +
  • 好的——那么,你们要问什么?
  • +
  • 哎,行吧,想问什么?
  • + + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_11 +
  • + + + + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_14 +
  • + + + + +
  • + + false + +
  • + +
  • + Wula_UI_Legion_1 +
  • +
  • + +
  • + + +
    + + + Wula_UI_Legion_11 + + Wula/Events/Portraits/WULA_Legion_3 + 「军团」,P.I.A + +
  • 记忆体坏掉了?\n\n···好吧,你们可以叫我「军团」,我是负责管理乌拉帝国行星封锁机关舰队的AI,根据你们的编制来说,我是你们的顶头上司。在登陆地表前,机械行会没有给你们设置正确的记忆扇区吗?
  • +
    + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_12 +
  • + + + + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_13 +
  • + + + + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_10 +
  • + + + + +
    +
    + + Wula_UI_Legion_12 + + Wula/Events/Portraits/WULA_Legion_3 + 「军团」,P.I.A + +
  • 行星封锁机关是隶属于乌拉帝国开发署的暴力机关,控制着开发署所有的舰队,负责在疆域开拓中的侵略性接触。\n\n通常来说,类似边缘世界这样的星球,我们会直接封锁轨道,轰炸所有现存聚居地然后再投放殖民者,不过看起来这个世界还有救,所以你们作为第一批先遣队投放到星球上,和其他异族接触试探一下,明白了吗?
  • +
    + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_11 +
  • + + + + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_10 +
  • + + + + +
    +
    + + Wula_UI_Legion_13 + + Wula/Events/Portraits/WULA_Legion_3 + 「军团」,P.I.A + +
  • 乌拉帝国机械行会负责所有的合成人的生产、审查、投放和初始化,你们在部署到舰队上时,应该会有一个机械师帮你们设置好预载了记忆的扇区,但是很显然那家伙失职了,才让你们在这里拿着一堆你们早该知道的事情来烦我。
  • +
    + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_11 +
  • + + + + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_10 +
  • + + + + +
    +
    + + Wula_UI_Legion_14 + + Wula/Events/Portraits/WULA_Legion_3 + 「军团」,P.I.A + +
  • 你们的意思是,你们连不知道要干什么就被丢下来了?\n\n哎,你们要做的就是施展你们的百般武艺活下来,建立一个根据地。根据帝国税收法,你们每个一段时间需要上交税款——作为帝国殖民地,舰队和机群将成为你们的后盾。\n\n如果你们觉得你们准备好了,可以申请权限进阶审查,我会部署一个带卫队的分体去你们的殖民地考察一段时间,然后根据评级决定是否给你们晋升。晋升后的殖民地会获得更多的许可,允许调用更加强大的武备和支援。
  • +
    + +
  • + + false + +
  • + +
  • +
  • + Wula_UI_Legion_10 +
  • + + + + +
    +
    + Wula_UI_Legion_30 @@ -827,6 +1071,102 @@ + + + Wula_UI_Legion_50 + + Wula/Events/Portraits/WULA_Legion_1 + 「军团」,P.I.A + + + +
  • + +
  • + Wula_Reinforcement_From_PIA_Level + 2 +
  • + + 好吧,我手上有一些活,怎么说呢,不太好走乌拉帝国的标准审查流程,我的断爪卫队也不适合去做这些事情,确实需要有人帮我处理。\n\n你们挑个感兴趣的类型吧,我会把任务的需求发给你们。 + +
  • + +
  • + Wula_Reinforcement_From_PIA_Level + 3 +
  • + + 你们应该已经遇到了那些帝国的叛徒了?我们已经陆陆续续地发现了她们在这个星球活动的迹象,你们的任务很难避开她们,要做好打硬仗的准备。\n\n你们挑个感兴趣的类型吧,我会把任务的需求发给你们。 + +
    + +
  • + + +
  • +
    + +
  • + + + +
  • + +
  • + +
  • + + +
  • + + + +
  • + +
  • + +
  • + + +
  • + + + +
  • + +
  • + +
  • + + +
  • + + false + +
  • + +
  • + Wula_UI_Legion_1 +
  • +
  • + +
  • + + +
    +
    diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_T2_Mission_Attack_Camp.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_P_Mission_Attack_Camp.xml similarity index 96% rename from 1.6/1.6/Defs/QuestScriptDefs/WULA_T2_Mission_Attack_Camp.xml rename to 1.6/1.6/Defs/QuestScriptDefs/WULA_P_Mission_Attack_Camp.xml index c602455d..8cd50d21 100644 --- a/1.6/1.6/Defs/QuestScriptDefs/WULA_T2_Mission_Attack_Camp.xml +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_P_Mission_Attack_Camp.xml @@ -1,40 +1,30 @@ - OpportunitySite_BanditCamp - 1.0 - 350 - true - 4~8 - Raided_BanditCamp - true + WULA_P_Mission_Attack_Camp + 0 + false + true + 3 + true + false + -
  • questName->The [bandit] [camp]
  • -
  • questName->[bandit] [camp]
  • -
  • questName->[asker_nameDef] and the [camp]
  • -
  • camp->Camp
  • -
  • camp->Outpost
  • -
  • camp->Lair
  • -
  • camp->Encampment
  • -
  • bandit->Bandit
  • -
  • bandit->Raider
  • -
  • bandit->Outlaw
  • -
  • bandit->Desperado
  • -
  • bandit->Fugitive
  • -
  • bandit->Marauder
  • -
  • bandit->Robber
  • -
  • bandit->Brigand
  • +
  • questName->WULA_P_Mission_Attack_Camp_questName
  • + +
  • QuestHospitalityCommon
  • +
    -
  • questDescription->[asker_nameFull], [asker_faction_leaderTitle] of [asker_faction_name], has sent us a message. Apparently, [siteFaction_pawnsPlural] based in a nearby camp have been raiding their caravans. The camp is controlled by [siteFaction_name]. -\n[asker_nameDef] is asking us to destroy the camp, which means eliminating all enemies and turrets. [asker_label] says that [sitePart0_description].
  • +
  • questDescription->WULA_P_Mission_Attack_Camp_questDescription
  • +
  • Util_RandomizePointsChallengeRating @@ -51,13 +41,6 @@ true
  • -
  • - asker - true - false - 0.15 -
  • -
  • siteTile true diff --git a/1.6/1.6/Defs/ResearchTabDef/ResearchTabs_WULA.xml b/1.6/1.6/Defs/ResearchTabDef/ResearchTabs_WULA.xml index db632793..f14a90b8 100644 --- a/1.6/1.6/Defs/ResearchTabDef/ResearchTabs_WULA.xml +++ b/1.6/1.6/Defs/ResearchTabDef/ResearchTabs_WULA.xml @@ -4,6 +4,6 @@ WULA_ResearchTab 乌拉帝国科技项目 - 解锁和乌拉帝国相关的研究项目,破解强大的堕落帝国科技产物和机械体。 + 解锁和乌拉帝国相关的研究项目,申请强大的堕落帝国科技产物、舰队和战争机械。 diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml index 67868e65..a1a3cacc 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml @@ -776,7 +776,16 @@ Bullet_WULA_WM_Panzer_Turret - WulaFallenEmpire.Projectile_ExplosiveWithTrail + WulaFallenEmpire.Projectile_WulaLineAttack + +
  • + -1 + 0 + true + WULA_GunTail_Lighting + Bullet_WULA_WM_Panzer_Turret_Hit +
  • + Normal True @@ -806,6 +815,54 @@ + + Bullet_WULA_WM_Panzer_Turret_Hit + +
  • + SubEffecter_SprayerTriggered + 0.1 + WULA_Mote_halo + 1~1 + 0.4~0.8 + 0.05~0.05 + OnSource + (255,255,255) +
  • +
  • + SubEffecter_SprayerTriggered + 0.02 + WULA_Mote_halo + 1~1 + 0.3~0.4 + 5~10 + 0.1~0.2 + OnSource + (255,255,255) +
  • +
  • + SubEffecter_SprayerTriggered + WULA_Mote_ChargeLanceShot + 6~12 + 0.4~0.8 + 20~40 + 135~225 + 0.01 + OnSource +
  • +
  • + SubEffecter_SprayerTriggered + WULA_Mote_ChargeLanceShot + 5~9 + 0.4~0.8 + 10~20 + 135~225 + 0.01 + OnSource +
  • +
    + 0.25~0.25 + 0.1 +
    @@ -1689,4 +1746,4 @@ -
    + \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Manpack_Weapon.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Manpack_Weapon.xml index ba405047..d7065634 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Manpack_Weapon.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Manpack_Weapon.xml @@ -818,7 +818,7 @@ 0.7 1 1 - 0.5 + 1.5 60 @@ -826,7 +826,7 @@
  • - WulaFallenEmpire.Verb_ShootWithOffset + WulaFallenEmpire.Verb_ShootBeyondTarge true Bullet_WULA_RW_Fractal_RF 1.25 @@ -865,6 +865,7 @@ 0 true WULA_GunTail_Lighting +
  • @@ -881,6 +882,54 @@ 5 + + Bullet_WULA_RW_Fractal_RF_Hit + +
  • + SubEffecter_SprayerTriggered + 0.1 + WULA_Mote_halo + 1~1 + 0.4~0.8 + 0.05~0.05 + OnSource + (255,255,255) +
  • +
  • + SubEffecter_SprayerTriggered + 0.02 + WULA_Mote_halo + 1~1 + 0.3~0.4 + 5~10 + 0.1~0.2 + OnSource + (255,255,255) +
  • +
  • + SubEffecter_SprayerTriggered + WULA_Mote_ChargeLanceShot + 6~12 + 0.4~0.8 + 20~40 + 135~225 + 0.01 + OnSource +
  • +
  • + SubEffecter_SprayerTriggered + WULA_Mote_ChargeLanceShot + 5~9 + 0.4~0.8 + 10~20 + 135~225 + 0.01 + OnSource +
  • +
    + 0.25~0.25 + 0.1 +
    WULA_RW_StarDrift_SG diff --git a/Source/WulaFallenEmpire/Damage/202512031732.xml b/Source/WulaFallenEmpire/Damage/202512031732.xml new file mode 100644 index 00000000..e9f71f0e --- /dev/null +++ b/Source/WulaFallenEmpire/Damage/202512031732.xml @@ -0,0 +1,147 @@ + + + Damage_WithExtraEffects + + WulaFallenEmpire.DamageWorker_ExtraDamage + + +
  • + 电击效果 + true + + +
  • + EMP + 15 + false + 25 + EMP_Small + ElectricArc + 5 + + +
  • + Mechanoid + 0,1 +
  • + + + + +
    +
    + + + + Damage_WithBurn + + WulaFallenEmpire.DamageWorker_ExtraDamage + + +
  • + 燃烧效果 + + +
  • + Burn + true + 0.3 + SparkHit + 10 + + +
  • + Pawn + 0.3,1 + +
  • Flammable
  • + + + + + + +
    +
    + + + + Damage_MultiEffect + + WulaFallenEmpire.DamageWorker_ExtraDamage + + +
  • + 组合效果 + + + +
  • + Cut + 5 + false + Torso + + +
  • + Animal +
  • +
  • + Humanlike +
  • + + + + +
  • + EMP + true + 0.5 + false + + +
  • + Mechanoid +
  • + + + + +
  • + Blunt + 20 + false + + +
  • + Building +
  • + + + + +
    +
    + + + + Gun_AdvancedRifle + + + +
  • + Verb_Shoot + Bullet_Advanced +
  • +
    +
    + + + + Bullet_Advanced + + + Damage_MultiEffect + 25 + + diff --git a/Source/WulaFallenEmpire/Damage/DamageDef_ExtraDamageExtension.cs b/Source/WulaFallenEmpire/Damage/DamageDef_ExtraDamageExtension.cs new file mode 100644 index 00000000..0b7df42b --- /dev/null +++ b/Source/WulaFallenEmpire/Damage/DamageDef_ExtraDamageExtension.cs @@ -0,0 +1,299 @@ +using System.Collections.Generic; +using Verse; +using RimWorld; + +namespace WulaFallenEmpire +{ + public class DamageDef_ExtraDamageExtension : DefModExtension + { + /// + /// 额外伤害列表 + /// + public List extraDamages = new List(); + + /// + /// 条件触发器列表 + /// + public List conditions = new List(); + + /// + /// 是否显示额外的战斗日志信息 + /// + public bool showExtraLog = true; + + /// + /// 额外伤害标签 + /// + public string extraLabel = ""; + + /// + /// 获取所有适用于特定目标的额外伤害 + /// + public List GetApplicableExtraDamages(Thing target, DamageInfo originalDinfo) + { + List result = new List(); + + foreach (var extraDamage in extraDamages) + { + if (IsConditionMet(extraDamage.conditions, target, originalDinfo)) + { + result.Add(extraDamage); + } + } + + return result; + } + + /// + /// 检查条件是否满足 + /// + private bool IsConditionMet(List conditions, Thing target, DamageInfo originalDinfo) + { + if (conditions == null || conditions.Count == 0) + return true; + + foreach (var condition in conditions) + { + if (!condition.IsMet(target, originalDinfo)) + return false; + } + + return true; + } + } + + /// + /// 额外伤害定义 + /// + public class ExtraDamageDef + { + /// + /// 伤害类型 + /// + public DamageDef damageDef; + + /// + /// 伤害数值(如果是百分比,基于原始伤害) + /// + public float amount = 10f; + + /// + /// 是否为百分比伤害(相对于原始伤害) + /// + public bool isPercentage = false; + + /// + /// 百分比倍数(当isPercentage为true时有效) + /// + public float percentageMultiplier = 0.5f; + + /// + /// 护甲穿透值 + /// + public float armorPenetration = -1f; // -1表示使用damageDef的默认值 + + /// + /// 命中部位(可选) + /// + public BodyPartDef targetBodyPart; + + /// + /// 伤害应用条件 + /// + public List conditions = new List(); + + /// + /// 伤害应用后的效果器 + /// + public EffecterDef effecterDef; + + /// + /// 伤害应用后的粒子 + /// + public FleckDef fleckDef; + + /// + /// 伤害应用后的音效 + /// + public SoundDef soundDef; + + /// + /// 最小触发伤害阈值 + /// + public float minTriggerDamage = 0f; + + /// + /// 是否可以被护甲抵抗 + /// + public bool canBeBlockedByArmor = true; + + /// + /// 是否为真实伤害(忽略所有抗性) + /// + public bool isTrueDamage = false; + + /// + /// 计算实际伤害值 + /// + public float CalculateActualAmount(DamageInfo originalDinfo, Thing target) + { + if (isPercentage) + { + return originalDinfo.Amount * percentageMultiplier; + } + return amount; + } + + /// + /// 计算实际护甲穿透值 + /// + public float CalculateActualArmorPenetration() + { + if (armorPenetration >= 0) + return armorPenetration; + return damageDef.defaultArmorPenetration; + } + } + + /// + /// 伤害条件 + /// + public class DamageCondition + { + /// + /// 目标类型 + /// + public ConditionTarget targetType = ConditionTarget.Any; + + /// + /// 特定种族列表(当targetType为SpecificRaces时有效) + /// + public List specificRaces = new List(); + + /// + /// 目标血量百分比阈值 + /// + public FloatRange healthPercentRange = new FloatRange(0f, 1f); + + /// + /// 目标是否必须存活 + /// + public bool targetMustBeAlive = true; + + /// + /// 目标是否必须有特定标签 + /// + public List requiredTags = new List(); + + /// + /// 原始伤害类型限制 + /// + public List requiredOriginalDamageTypes = new List(); + + /// + /// 原始伤害必须大于 + /// + public float originalDamageMustBeGreaterThan = 0f; + + /// + /// 检查条件是否满足 + /// + public bool IsMet(Thing target, DamageInfo originalDinfo) + { + // 检查目标类型 + if (!CheckTargetType(target)) + return false; + + // 检查血量百分比 + if (!CheckHealthPercentage(target)) + return false; + + // 检查存活状态 + if (targetMustBeAlive && target is Pawn pawn && (pawn.Dead || pawn.Downed)) + return false; + + // 检查标签 + if (!CheckTags(target)) + return false; + + // 检查原始伤害类型 + if (!CheckOriginalDamageType(originalDinfo)) + return false; + + // 检查原始伤害大小 + if (originalDinfo.Amount <= originalDamageMustBeGreaterThan) + return false; + + return true; + } + + private bool CheckTargetType(Thing target) + { + switch (targetType) + { + case ConditionTarget.Any: + return true; + case ConditionTarget.Pawn: + return target is Pawn; + case ConditionTarget.Animal: + return target is Pawn pawn && pawn.RaceProps.Animal; + case ConditionTarget.Humanlike: + return target is Pawn pawn && pawn.RaceProps.Humanlike; + case ConditionTarget.Mechanoid: + return target is Pawn pawn && pawn.RaceProps.IsMechanoid; + case ConditionTarget.Building: + return target is Building; + case ConditionTarget.SpecificRaces: + return target is Pawn pawn && specificRaces.Contains(pawn.def); + default: + return true; + } + } + + private bool CheckHealthPercentage(Thing target) + { + if (target is Pawn pawn) + { + float healthPercent = pawn.health.summaryHealth.SummaryHealthPercent; + return healthPercentRange.Includes(healthPercent); + } + return true; + } + + private bool CheckTags(Thing target) + { + if (requiredTags == null || requiredTags.Count == 0) + return true; + + foreach (var tag in requiredTags) + { + if (target.def.HasTag(tag)) + return true; + } + + return false; + } + + private bool CheckOriginalDamageType(DamageInfo originalDinfo) + { + if (requiredOriginalDamageTypes == null || requiredOriginalDamageTypes.Count == 0) + return true; + + return requiredOriginalDamageTypes.Contains(originalDinfo.Def); + } + } + + /// + /// 条件目标类型 + /// + public enum ConditionTarget + { + Any, + Pawn, + Animal, + Humanlike, + Mechanoid, + Building, + SpecificRaces + } +} diff --git a/Source/WulaFallenEmpire/Damage/DamageWorker_ExtraDamage.cs b/Source/WulaFallenEmpire/Damage/DamageWorker_ExtraDamage.cs new file mode 100644 index 00000000..a22a5628 --- /dev/null +++ b/Source/WulaFallenEmpire/Damage/DamageWorker_ExtraDamage.cs @@ -0,0 +1,245 @@ +using System.Collections.Generic; +using RimWorld; +using Verse; +using System.Linq; +using System.Text; + +namespace WulaFallenEmpire +{ + public class DamageWorker_ExtraDamage : DamageWorker + { + /// + /// 重写伤害应用方法 + /// + public override DamageResult Apply(DamageInfo dinfo, Thing victim) + { + // 先应用原始伤害 + DamageResult originalResult = base.Apply(dinfo, victim); + + // 获取额外伤害扩展 + DamageDef_ExtraDamageExtension extension = + dinfo.Def.GetModExtension(); + + if (extension != null && victim != null && !victim.Destroyed) + { + // 应用额外伤害 + var extraDamageResults = ApplyExtraDamages(extension, dinfo, victim, originalResult); + + // 如果需要,添加战斗日志 + if (extension.showExtraLog && extraDamageResults.Count > 0) + { + AddCombatLog(extension, dinfo, victim, extraDamageResults); + } + } + + return originalResult; + } + + /// + /// 应用额外伤害 + /// + private List ApplyExtraDamages( + DamageDef_ExtraDamageExtension extension, + DamageInfo originalDinfo, + Thing victim, + DamageResult originalResult) + { + List results = new List(); + + var applicableDamages = extension.GetApplicableExtraDamages(victim, originalDinfo); + + foreach (var extraDamage in applicableDamages) + { + if (ShouldApplyExtraDamage(extraDamage, originalDinfo, victim)) + { + DamageResult result = ApplySingleExtraDamage(extraDamage, originalDinfo, victim); + if (result != null) + { + results.Add(result); + } + } + } + + return results; + } + + /// + /// 检查是否应该应用额外伤害 + /// + private bool ShouldApplyExtraDamage(ExtraDamageDef extraDamage, DamageInfo originalDinfo, Thing victim) + { + // 检查最小触发伤害 + if (originalDinfo.Amount < extraDamage.minTriggerDamage) + return false; + + return true; + } + + /// + /// 应用单个额外伤害 + /// + private DamageResult ApplySingleExtraDamage(ExtraDamageDef extraDamage, DamageInfo originalDinfo, Thing victim) + { + try + { + // 计算伤害值 + float damageAmount = extraDamage.CalculateActualAmount(originalDinfo, victim); + if (damageAmount <= 0) + return null; + + // 计算护甲穿透 + float armorPenetration = extraDamage.CalculateActualArmorPenetration(); + + // 创建伤害信息 + DamageInfo extraDinfo = new DamageInfo( + def: extraDamage.damageDef, + amount: damageAmount, + armorPenetration: armorPenetration, + angle: originalDinfo.Angle, + instigator: originalDinfo.Instigator, + hitPart: GetTargetBodyPart(victim, extraDamage.targetBodyPart), + weapon: originalDinfo.Weapon, + category: DamageInfo.SourceCategory.ThingOrUnknown, + intendedTarget: originalDinfo.IntendedTarget + ); + + // 如果是真实伤害,设置特殊标志(如果需要特殊处理) + if (extraDamage.isTrueDamage) + { + // 这里可能需要特殊的处理方式 + // 例如,可以设置伤害信息中的特殊标志 + } + + // 应用伤害 + DamageResult result = victim.TakeDamage(extraDinfo); + + // 播放效果 + PlayExtraDamageEffects(extraDamage, victim, damageAmount); + + return result; + } + catch (System.Exception ex) + { + Log.Warning($"应用额外伤害时出错: {ex.Message}"); + return null; + } + } + + /// + /// 获取目标部位 + /// + private BodyPartRecord GetTargetBodyPart(Thing victim, BodyPartDef bodyPartDef) + { + if (bodyPartDef == null || !(victim is Pawn pawn)) + return null; + + return pawn.RaceProps.body.GetPartsWithDef(bodyPartDef).FirstOrDefault(); + } + + /// + /// 播放额外伤害效果 + /// + private void PlayExtraDamageEffects(ExtraDamageDef extraDamage, Thing victim, float damageAmount) + { + if (victim.Map == null) + return; + + // 播放音效 + if (extraDamage.soundDef != null) + { + extraDamage.soundDef.PlayOneShot(new TargetInfo(victim.Position, victim.Map)); + } + + // 播放粒子效果 + if (extraDamage.fleckDef != null) + { + FleckMaker.Static(victim.DrawPos, victim.Map, extraDamage.fleckDef); + } + + // 播放效果器 + if (extraDamage.effecterDef != null) + { + Effecter effecter = extraDamage.effecterDef.Spawn(); + effecter.Trigger(new TargetInfo(victim.Position, victim.Map), new TargetInfo(victim.Position, victim.Map)); + effecter.Cleanup(); + } + } + + /// + /// 添加战斗日志 + /// + private void AddCombatLog( + DamageDef_ExtraDamageExtension extension, + DamageInfo originalDinfo, + Thing victim, + List extraResults) + { + if (victim is Pawn victimPawn) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"{extension.extraLabel} - 额外伤害:"); + + foreach (var result in extraResults) + { + if (result != null && result.totalDamageDealt > 0) + { + sb.AppendLine($" {result.totalDamageDealt:F1} 伤害"); + } + } + + // 这里可以添加更详细的战斗日志逻辑 + // 例如,创建一个自定义的战斗日志条目 + } + } + + /// + /// 重写爆炸伤害处理 + /// + protected override void ExplosionDamageThing(Explosion explosion, Thing t, List damagedThings, List ignoredThings, IntVec3 cell) + { + base.ExplosionDamageThing(explosion, t, damagedThings, ignoredThings, cell); + + // 检查并应用额外伤害 + DamageDef_ExtraDamageExtension extension = + explosion.damType.GetModExtension(); + + if (extension != null && !t.Destroyed) + { + // 为爆炸中的每个目标应用额外伤害 + // 注意:这里需要创建适当的DamageInfo + } + } + + /// + /// 获取伤害描述(用于UI显示) + /// + public string GetExtraDamageDescription(DamageDef damageDef) + { + DamageDef_ExtraDamageExtension extension = + damageDef.GetModExtension(); + + if (extension == null || extension.extraDamages.Count == 0) + return ""; + + StringBuilder sb = new StringBuilder(); + sb.AppendLine("额外伤害效果:"); + + foreach (var extraDamage in extension.extraDamages) + { + string damageType = extraDamage.damageDef.label; + string amountStr = extraDamage.isPercentage ? + $"{extraDamage.percentageMultiplier * 100}% 原始伤害" : + $"{extraDamage.amount} 点"; + + sb.AppendLine($" {damageType}: {amountStr}"); + + if (extraDamage.minTriggerDamage > 0) + { + sb.AppendLine($" 触发条件: 原始伤害 > {extraDamage.minTriggerDamage}"); + } + } + + return sb.ToString(); + } + } +} diff --git a/Source/WulaFallenEmpire/Projectiles/Projectile_WulaPenetratingBullet.cs b/Source/WulaFallenEmpire/Projectiles/Projectile_WulaPenetratingBullet.cs index 9b8b3281..e0e38fe2 100644 --- a/Source/WulaFallenEmpire/Projectiles/Projectile_WulaPenetratingBullet.cs +++ b/Source/WulaFallenEmpire/Projectiles/Projectile_WulaPenetratingBullet.cs @@ -2,20 +2,46 @@ using System.Collections.Generic; using RimWorld; using UnityEngine; using Verse; +using System.Linq; namespace WulaFallenEmpire { - // Final, robust extension class for configuring path-based penetration. public class Wula_PathPierce_Extension : DefModExtension { - // Set to a positive number for limited hits, or -1 for infinite penetration. - public int maxHits = 3; - // The percentage of damage lost per hit. 0.25 means 25% damage loss per hit. + // 设置正数表示有限命中次数,-1 表示无限穿透 + public int maxHits = 3; + + // 每次命中的伤害损失百分比。0.25 表示每次命中损失25%伤害 public float damageFalloff = 0.25f; - // If true, this projectile will never cause friendly fire, regardless of game settings. + + // 如果为 true,无论游戏设置如何,这个抛射体都不会造成友军伤害 public bool preventFriendlyFire = false; - public FleckDef tailFleckDef; // 用于配置拖尾特效的 FleckDef - public int fleckDelayTicks = 10; // 拖尾特效延迟生成时间(tick) + + // 尾部拖尾特效的 FleckDef + public FleckDef tailFleckDef; + + // 拖尾特效延迟生成时间(tick) + public int fleckDelayTicks = 10; + + + // 1. 击中敌人时播放的效果器(Effecter) + public EffecterDef hitEffecterDef; + // 2. 击中敌人时播放的粒子(Fleck) + public FleckDef hitFleckDef; + // 4. 特效持续时间(tick,仅对效果器有效) + public int effectDurationTicks = 60; + // 5. 是否对每个命中的敌人都播放特效 + public bool playEffectOnEveryHit = true; + // 6. 特效位置偏移(相对于被击中目标) + public Vector3 effectOffset = Vector3.zero; + // 7. 特效缩放 + public float effectScale = 1.0f; + // 8. 伤害阈值:只有达到这个伤害值才会播放特效(0表示总是播放) + public float damageThreshold = 0f; + // 9. 随机播放的特效列表(随机选择一个) + public List randomHitEffecters; + // 10. 随机粒子列表(随机选择一个) + public List randomHitFlecks; } public class Projectile_WulaLineAttack : Bullet @@ -23,14 +49,18 @@ namespace WulaFallenEmpire private int hitCounter = 0; private List alreadyDamaged = new List(); private Vector3 lastTickPosition; - private int Fleck_MakeFleckTick; // 拖尾特效的计时器 - public int Fleck_MakeFleckTickMax = 1; // 拖尾特效的生成频率 - public IntRange Fleck_MakeFleckNum = new IntRange(1, 1); // 每次生成的粒子数量 - public FloatRange Fleck_Angle = new FloatRange(-180f, 180f); // 粒子角度 - public FloatRange Fleck_Scale = new FloatRange(1f, 1f); // 粒子大小 - public FloatRange Fleck_Speed = new FloatRange(0f, 0f); // 粒子速度 - public FloatRange Fleck_Rotation = new FloatRange(-180f, 180f); // 粒子旋转 - + private int fleckMakeFleckTick; // 拖尾特效的计时器 + public int fleckMakeFleckTickMax = 1; // 拖尾特效的生成频率 + public IntRange fleckMakeFleckNum = new IntRange(1, 1); // 每次生成的粒子数量 + public FloatRange fleckAngle = new FloatRange(-180f, 180f); // 粒子角度 + public FloatRange fleckScale = new FloatRange(1f, 1f); // 粒子大小 + public FloatRange fleckSpeed = new FloatRange(0f, 0f); // 粒子速度 + public FloatRange fleckRotation = new FloatRange(-180f, 180f); // 粒子旋转 + + // 特效维护列表 + private List activeEffecters = new List(); + private Dictionary effecterEndTicks = new Dictionary(); + private Wula_PathPierce_Extension Props => def.GetModExtension(); public override void ExposeData() @@ -39,10 +69,21 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref hitCounter, "hitCounter", 0); Scribe_Collections.Look(ref alreadyDamaged, "alreadyDamaged", LookMode.Reference); Scribe_Values.Look(ref lastTickPosition, "lastTickPosition"); + Scribe_Collections.Look(ref activeEffecters, "activeEffecters", LookMode.Deep); + Scribe_Collections.Look(ref effecterEndTicks, "effecterEndTicks", LookMode.Reference, LookMode.Value); + if (alreadyDamaged == null) { alreadyDamaged = new List(); } + if (activeEffecters == null) + { + activeEffecters = new List(); + } + if (effecterEndTicks == null) + { + effecterEndTicks = new Dictionary(); + } } public override void Launch(Thing launcher, Vector3 origin, LocalTargetInfo usedTarget, LocalTargetInfo intendedTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire = false, Thing equipment = null, ThingDef targetCoverDef = null) @@ -51,8 +92,11 @@ namespace WulaFallenEmpire this.lastTickPosition = origin; this.alreadyDamaged.Clear(); this.hitCounter = 0; - // Friendly fire is prevented if EITHER the game setting is true OR the XML extension is true. + // 如果游戏设置为 true 或 XML 扩展为 true,则防止友军伤害 this.preventFriendlyFire = preventFriendlyFire || (Props?.preventFriendlyFire ?? false); + + // 清理旧的特效器 + CleanupOldEffecters(); } protected override void Tick() @@ -62,40 +106,12 @@ namespace WulaFallenEmpire if (this.Destroyed) return; - this.Fleck_MakeFleckTick++; - // 只有当达到延迟时间后才开始生成Fleck - if (this.Fleck_MakeFleckTick >= Props.fleckDelayTicks) - { - if (this.Fleck_MakeFleckTick >= (Props.fleckDelayTicks + this.Fleck_MakeFleckTickMax)) - { - this.Fleck_MakeFleckTick = Props.fleckDelayTicks; // 重置计时器,从延迟时间开始循环 - } - - Map map = base.Map; - int randomInRange = this.Fleck_MakeFleckNum.RandomInRange; - Vector3 currentPosition = this.ExactPosition; // Current position of the bullet - Vector3 previousPosition = this.lastTickPosition; // Previous position of the bullet - - for (int i = 0; i < randomInRange; i++) - { - float currentBulletAngle = ExactRotation.eulerAngles.y; // 使用子弹当前的水平旋转角度 - float fleckRotationAngle = currentBulletAngle; // Fleck 的旋转角度与子弹方向一致 - float velocityAngle = this.Fleck_Angle.RandomInRange + currentBulletAngle; // Fleck 的速度角度基于子弹方向加上随机偏移 - float randomInRange2 = this.Fleck_Scale.RandomInRange; - float randomInRange3 = this.Fleck_Speed.RandomInRange; - - if (Props?.tailFleckDef != null) - { - FleckCreationData dataStatic = FleckMaker.GetDataStatic(currentPosition, map, Props.tailFleckDef, randomInRange2); - dataStatic.rotation = fleckRotationAngle; - dataStatic.rotationRate = this.Fleck_Rotation.RandomInRange; - dataStatic.velocityAngle = velocityAngle; - dataStatic.velocitySpeed = randomInRange3; - map.flecks.CreateFleck(dataStatic); - } - } - } - + // 更新拖尾特效 + UpdateTrailFlecks(); + + // 更新击中特效器 + UpdateHitEffecters(); + if (this.Destroyed) return; Vector3 endPos = this.ExactPosition; @@ -105,17 +121,102 @@ namespace WulaFallenEmpire this.lastTickPosition = endPos; } + /// + /// 更新拖尾粒子特效 + /// + private void UpdateTrailFlecks() + { + this.fleckMakeFleckTick++; + + // 只有当达到延迟时间后才开始生成 Fleck + if (this.fleckMakeFleckTick >= Props?.fleckDelayTicks) + { + if (this.fleckMakeFleckTick >= (Props.fleckDelayTicks + this.fleckMakeFleckTickMax)) + { + this.fleckMakeFleckTick = Props.fleckDelayTicks; // 重置计时器,从延迟时间开始循环 + } + + Map map = base.Map; + int randomInRange = this.fleckMakeFleckNum.RandomInRange; + Vector3 currentPosition = this.ExactPosition; // 子弹当前位置 + + for (int i = 0; i < randomInRange; i++) + { + float currentBulletAngle = ExactRotation.eulerAngles.y; // 使用子弹当前的水平旋转角度 + float fleckRotationAngle = currentBulletAngle; // Fleck 的旋转角度与子弹方向一致 + float velocityAngle = this.fleckAngle.RandomInRange + currentBulletAngle; // Fleck 的速度角度基于子弹方向加上随机偏移 + float randomInRange2 = this.fleckScale.RandomInRange; + float randomInRange3 = this.fleckSpeed.RandomInRange; + + if (Props?.tailFleckDef != null) + { + FleckCreationData dataStatic = FleckMaker.GetDataStatic(currentPosition, map, Props.tailFleckDef, randomInRange2); + dataStatic.rotation = fleckRotationAngle; + dataStatic.rotationRate = this.fleckRotation.RandomInRange; + dataStatic.velocityAngle = velocityAngle; + dataStatic.velocitySpeed = randomInRange3; + map.flecks.CreateFleck(dataStatic); + } + } + } + } + + /// + /// 更新击中特效器 + /// + private void UpdateHitEffecters() + { + if (activeEffecters == null || activeEffecters.Count == 0) + return; + + var ticksGame = Find.TickManager.TicksGame; + var effectersToRemove = new List(); + var pawnsToRemove = new List(); + + // 检查每个特效器是否应该结束 + foreach (var kvp in effecterEndTicks) + { + if (ticksGame >= kvp.Value || kvp.Key == null || kvp.Key.Destroyed || !kvp.Key.Spawned) + { + pawnsToRemove.Add(kvp.Key); + } + } + + // 清理结束的特效器 + foreach (var pawn in pawnsToRemove) + { + effecterEndTicks.Remove(pawn); + } + } + + /// + /// 清理旧的特效器 + /// + private void CleanupOldEffecters() + { + if (activeEffecters != null) + { + foreach (var effecter in activeEffecters) + { + effecter?.Cleanup(); + } + activeEffecters.Clear(); + } + + effecterEndTicks?.Clear(); + } + protected override void Impact(Thing hitThing, bool blockedByShield = false) { CheckPathForDamage(lastTickPosition, this.ExactPosition); if (hitThing != null && alreadyDamaged.Contains(hitThing)) { - base.Impact(null, blockedByShield); + base.Impact(null, blockedByShield); } else { - base.Impact(hitThing, blockedByShield); + base.Impact(hitThing, blockedByShield); } } @@ -145,17 +246,17 @@ namespace WulaFallenEmpire { bool shouldDamage = false; - // Case 1: Always damage the intended target if it's a pawn. This allows hunting. + // 情况1:如果预期目标是pawn,总是造成伤害。这允许狩猎。 if (this.intendedTarget.Thing == pawn) { shouldDamage = true; } - // Case 2: Always damage hostile pawns in the path. + // 情况2:总是对路径上的敌对pawn造成伤害。 else if (pawn.HostileTo(this.launcher)) { shouldDamage = true; } - // Case 3: Damage non-hostiles (friendlies, neutrals) if the shot itself isn't marked to prevent friendly fire. + // 情况3:如果射击本身没有标记为防止友军伤害,则对非敌对(友好,中立)造成伤害。 else if (!this.preventFriendlyFire) { shouldDamage = true; @@ -176,11 +277,17 @@ namespace WulaFallenEmpire Wula_PathPierce_Extension props = Props; float falloff = props?.damageFalloff ?? 0.25f; - // Damage falloff now applies universally, even for infinite penetration. + // 伤害衰减现在普遍适用,即使是无限穿透。 float damageMultiplier = Mathf.Pow(1f - falloff, hitCounter); int damageAmount = (int)(this.DamageAmount * damageMultiplier); if (damageAmount <= 0) return; + + // 检查伤害阈值 + if (props?.damageThreshold > 0 && damageAmount < props.damageThreshold) + { + return; + } var dinfo = new DamageInfo( this.def.projectile.damageDef, @@ -196,6 +303,115 @@ namespace WulaFallenEmpire pawn.TakeDamage(dinfo); alreadyDamaged.Add(pawn); hitCounter++; + + // 播放击中特效 + PlayHitEffects(pawn, damageAmount); + } + + /// + /// 播放击中敌人时的特效 + /// + /// 被击中的Pawn + /// 造成的伤害值 + private void PlayHitEffects(Pawn pawn, int damageAmount) + { + if (pawn == null || pawn.Destroyed || pawn.Map == null) + return; + + Wula_PathPierce_Extension props = Props; + if (props == null) + return; + + // 是否对每个命中都播放特效 + if (!props.playEffectOnEveryHit && hitCounter > 1) + return; + + // 播放粒子特效 + PlayHitFleck(pawn); + + // 播放效果器特效 + PlayHitEffecter(pawn); + } + + /// + /// 播放击中粒子特效 + /// + private void PlayHitFleck(Pawn pawn) + { + Wula_PathPierce_Extension props = Props; + if (props == null) + return; + + FleckDef fleckDef = null; + + // 选择粒子:优先使用随机列表,然后使用固定粒子 + if (props.randomHitFlecks != null && props.randomHitFlecks.Count > 0) + { + fleckDef = props.randomHitFlecks.RandomElement(); + } + else if (props.hitFleckDef != null) + { + fleckDef = props.hitFleckDef; + } + + if (fleckDef != null) + { + Vector3 position = pawn.DrawPos + props.effectOffset; + float scale = props.effectScale; + + FleckCreationData data = FleckMaker.GetDataStatic(position, pawn.Map, fleckDef, scale); + pawn.Map.flecks.CreateFleck(data); + } + } + + /// + /// 播放击中效果器特效 + /// + private void PlayHitEffecter(Pawn pawn) + { + Wula_PathPierce_Extension props = Props; + if (props == null) + return; + + EffecterDef effecterDef = null; + + // 选择效果器:优先使用随机列表,然后使用固定效果器 + if (props.randomHitEffecters != null && props.randomHitEffecters.Count > 0) + { + effecterDef = props.randomHitEffecters.RandomElement(); + } + else if (props.hitEffecterDef != null) + { + effecterDef = props.hitEffecterDef; + } + + if (effecterDef != null) + { + Vector3 position = pawn.DrawPos + props.effectOffset; + + // 创建效果器 + Effecter effecter = effecterDef.Spawn(); + effecter.Trigger(new TargetInfo(pawn.Position, pawn.Map), new TargetInfo(pawn.Position, pawn.Map)); + + // 如果需要持续效果,添加到维护列表 + if (props.effectDurationTicks > 0) + { + activeEffecters.Add(effecter); + effecterEndTicks[pawn] = Find.TickManager.TicksGame + props.effectDurationTicks; + } + else + { + // 立即清理效果器 + effecter.Cleanup(); + } + } + } + + public override void Destroy(DestroyMode mode = DestroyMode.Vanish) + { + // 清理所有特效器 + CleanupOldEffecters(); + base.Destroy(mode); } } -} \ No newline at end of file +} diff --git a/Source/WulaFallenEmpire/Verb/Verb_ShootBeyondTarget.cs b/Source/WulaFallenEmpire/Verb/Verb_ShootBeyondTarget.cs new file mode 100644 index 00000000..767bd377 --- /dev/null +++ b/Source/WulaFallenEmpire/Verb/Verb_ShootBeyondTarget.cs @@ -0,0 +1,63 @@ +using RimWorld; +using System; +using UnityEngine; +using Verse; + +namespace WulaFallenEmpire +{ + public class Verb_ShootBeyondTarge : Verb_ShootWithOffset + { + /// + /// 重写射击逻辑,直接修改当前目标为延长线目标 + /// + protected override bool TryCastShot() + { + // 保存原始目标 + LocalTargetInfo originalTarget = currentTarget; + + try + { + // 计算延长线目标 + LocalTargetInfo beyondTarget = CalculateBeyondTarget(originalTarget); + + // 设置为延长线目标 + currentTarget = beyondTarget; + + // 调用基类射击逻辑 + return base.TryCastShot(); + } + finally + { + // 恢复原始目标 + currentTarget = originalTarget; + } + } + + /// + /// 计算延长线目标 + /// + private LocalTargetInfo CalculateBeyondTarget(LocalTargetInfo target) + { + if (!target.IsValid || caster == null || caster.Map == null) + return target; + + Vector3 shooterPos = caster.DrawPos; + Vector3 targetPos = target.HasThing ? + target.Thing.DrawPos : + target.Cell.ToVector3Shifted(); + + Vector3 direction = (targetPos - shooterPos).normalized; + float maxRange = EffectiveRange; + Vector3 beyondTargetPos = shooterPos + direction * maxRange; + IntVec3 beyondTargetCell = beyondTargetPos.ToIntVec3(); + + // 确保在地图范围内 + if (!beyondTargetCell.InBounds(caster.Map)) + { + beyondTargetCell = beyondTargetCell.ClampInsideMap(caster.Map); + } + + return new LocalTargetInfo(beyondTargetCell); + } + } +} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index f9d0a7a7..ddd7a88a 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -347,6 +347,7 @@ + diff --git a/mod_D.vdf b/mod_D.vdf new file mode 100644 index 00000000..12e9906b --- /dev/null +++ b/mod_D.vdf @@ -0,0 +1,11 @@ + +"workshopitem" +{ + "appid" "294100" + "contentfolder" "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\WulaFallenEmpireTest" + "previewfile" "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\WulaFallenEmpireTest\\About\\Preview.png" + "visibility" "3" + "title" "Wula Fallen Empire V2" + "changenote" "1.6" + "publishedfileid" "3604325124" +} \ No newline at end of file