Repository navigation
Expand file tree
/
Copy pathOneHitKillModule.cs
More file actions
149 lines (134 loc) · 5.46 KB
/
Copy pathOneHitKillModule.cs
File metadata and controls
149 lines (134 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using System;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.InputSystem;
namespace HTFToolkit
{
/// <summary>
/// 一击必杀(秒杀生物)。
/// 主机/单人:Harmony 前缀改写 Creature.ServerChangeHp 的 damage → 任意攻击命中都致命
/// (游戏内所有伤害最终都走这个扣血入口:_hp.Value -= damage)。
/// 客户端:伤害在主机结算,本机 patch 无效 → 走官方零校验 ServerRpc
/// Server.HitCreature(creature, player, damage, hitPoint, dir),左键攻击时对
/// 准星目标补发一次致命伤害。
/// ⚠️ Boss 无敌阶段(BossManager.IsImmortal)游戏本身禁止扣血,此时秒杀无效(属游戏机制)。
/// </summary>
internal static class OneHitKillModule
{
public static bool Enabled;
/// <summary>致命伤害值(游戏血量远小于此)。</summary>
private const int LethalDamage = 99999;
/// <summary>客户端:准星判定最大角度(度)。</summary>
private static ConfigEntry<float> _aimAngle;
private static ConfigEntry<float> _maxDistance;
public static void BindConfig(ConfigFile cfg)
{
_aimAngle = cfg.Bind("一击必杀", "准星判定角度", 25f, "客户端模式:准星与生物的最大夹角(度)");
_maxDistance = cfg.Bind("一击必杀", "最大距离", 120f, "客户端模式:超过该距离不生效");
}
public static void ApplyPatches(Harmony harmony)
{
try
{
var m = AccessTools.Method(typeof(Creature), "ServerChangeHp");
if (m != null)
{
harmony.Patch(m,
prefix: new HarmonyMethod(AccessTools.Method(typeof(OneHitKillModule), nameof(PrefixLethal))));
}
}
catch (Exception e)
{
Plugin.Log?.LogWarning($"OneHitKill patch failed: {e.Message}");
}
}
/// <summary>主机/单人:把扣血量放大为致命值(只对正伤害生效,避免把治疗也放大)。</summary>
private static void PrefixLethal(ref int damage)
{
if (Enabled && damage > 0)
damage = LethalDamage;
}
/// <summary>
/// 客户端:左键攻击时对准星目标补发一次致命伤害。
/// 由 Plugin.Update 调用(内部自行分流,主机/单人直接短路返回)。
/// </summary>
public static void Update()
{
if (!Enabled)
return;
try
{
if (Compat.IsHost || !Compat.ClientRpcReady)
return;
// 游戏用新 Input System(旧 UnityEngine.Input 在本项目不可用)
Mouse mouse = Mouse.current;
if (mouse == null || !mouse.leftButton.wasPressedThisFrame)
return;
Creature target = FindAimedCreature();
if (target == null)
return;
Player p = Player.LocalPlayer;
if (p == null)
return;
Vector3 hitPoint = target.transform.position;
Vector3 dir = (hitPoint - p.transform.position).normalized;
Server.Instance.HitCreature(target, p, LethalDamage, hitPoint, dir);
}
catch (Exception e)
{
Plugin.Log?.LogWarning($"OneHitKill client: {e.Message}");
}
}
/// <summary>找准星指向的最近活体生物(客户端模式用)。</summary>
private static Creature FindAimedCreature()
{
Camera cam = null;
try
{
cam = GameInfo.CurCamera;
}
catch
{
cam = null;
}
if (cam == null)
cam = Camera.main;
if (cam == null)
return null;
Player p = Player.LocalPlayer;
if (p == null)
return null;
Vector3 camPos = cam.transform.position;
Vector3 camFwd = cam.transform.forward;
float minAlign = Mathf.Cos((_aimAngle?.Value ?? 25f) * Mathf.Deg2Rad);
float maxSqr = (_maxDistance?.Value ?? 120f);
maxSqr *= maxSqr;
Creature best = null;
float bestScore = float.MaxValue;
foreach (System.Collections.Generic.KeyValuePair<Transform, Item> kv in ItemManager.Items)
{
Item item = kv.Value;
Creature c = item as Creature;
if (c == null && item != null)
c = item.Creature;
if (!Compat.CreatureAlive(c))
continue;
Vector3 pos = c.Rig ? c.Rig.worldCenterOfMass : c.transform.position;
Vector3 to = pos - camPos;
float sqr = to.sqrMagnitude;
if (sqr < Mathf.Epsilon || sqr > maxSqr)
continue;
float align = Vector3.Dot(camFwd, to) / Mathf.Sqrt(sqr);
if (align < minAlign)
continue;
if (sqr < bestScore)
{
bestScore = sqr;
best = c;
}
}
return best;
}
}
}