Files
TankIC/tools/hornet_noknockback.js
T
TermiNexus bea22bb5f9 feat(noknockback): 新增拒绝击退开关,中弹不再被推开
在本地坦克实体的 kz7 事件派发处丢弃外力事件(ODt:作用点/方向/强度),坦克物理收不到就不产生位移与旋转;悬挂与行驶仍走 m9k 直调,不受影响。面板新增「拒绝击退」开关。字段名走 hornet_schema。
2026-10-20 20:35:19 +08:00

148 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// hornet_noknockback.js — 拒绝击退(中弹不再被推着走)
// 放在控制面板「拒绝击退」开关里,只作用于**本地坦克**。
//
// 引擎里「被打中弹开」的完整链路(module_87072 / module_55088):
// 碰撞/武器命中 → 目标坦克实体派发 ODt 事件(外力事件):
// ODt.o13i_1 = 作用点,ODt.p13i_1 = 方向,ODt.q13i_1 = 强度
// → 坦克物理组件 ejt 在 oz4() 里订阅它(callableName = "applyForce"):
// t.pbk().m9k(点, 方向, 强度) // m9k = 在点处施加力,直接进速度/角速度
// → 车体被推开 / 被弹得转圈
//
// 为什么在「事件派发」这一层拦:
// m9k 同时被悬挂/弹簧(Gbt.s151)和自身开炮后座使用,直接封 m9k 会把悬挂也废掉;
// 而 ODt 只承载外力(炮弹/地雷/撞击),拦掉它 → 只失去被推动,悬挂与驾驶完全不受影响。
//
// 拦法:给本地坦克实体实例的 kz7(事件派发方法)套一层,遇到外力事件直接丢弃。
// 只影响本客户端本地坦克;自己的开炮后座走的是直接 m9k 调用,不受影响。
(function () {
'use strict';
var Lib = window.__hornetLib__;
if (!Lib) {
console.error('[拒绝击退] 请先加载 hornet_lib.js');
return;
}
// ===== 字段抽象层(语义名 → 匿名字段,总表在 hornet_schema.js)=====
var Schema = window.__hornetSchema__ || null;
function Fld(Key, Fallback) {
var N = Schema ? Schema.FieldName(Key) : null;
return N || Fallback;
}
function Mth(Key, Fallback) {
var N = Schema ? Schema.MethodName(Key) : null;
return N || Fallback;
}
var FPushPoint = Fld('Event.PushPoint', 'o13i_1'); // 外力作用点
var FPushDir = Fld('Event.PushDir', 'p13i_1'); // 外力方向
var FPushStrength = Fld('Event.PushStrength', 'q13i_1'); // 外力强度
var MDispatch = Mth('Entity.Dispatch', 'kz7'); // 实体事件派发
var Stat = {
running: false,
blocked: 0, // 累计拦下的外力事件数
tankId: -1
};
var PatchedTank = null; // 当前已接管的坦克实体
var OrigDispatch = null; // 该实体原来的派发方法
// 外力事件识别(ODt):作用点 + 方向 + 强度 + r13i 写入方法
// ⚠ 不能用 instanceof:ODt 类没有对外导出,且每版类对象都会重建
function IsPushEvent(Event) {
if (!Event || typeof Event !== 'object') return false;
if (typeof Event[FPushStrength] !== 'number') return false;
var Point = Event[FPushPoint];
var Dir = Event[FPushDir];
if (!Point || !Dir) return false;
if (typeof Point.f20_1 !== 'number' || typeof Dir.f20_1 !== 'number') return false;
return true;
}
// 本地坦克:拥有中的优先;死亡时退回观察目标(此时不参与战斗,影响可忽略)
function GetLocalTank() {
var Gm = window.__gameMode__;
if (!Gm) return null;
try { if (Gm.u10b_1) return Gm.u10b_1; } catch (e) {}
try { if (Gm.t10b_1) return Gm.t10b_1; } catch (e) {}
return null;
}
function Unpatch() {
if (PatchedTank && OrigDispatch) {
try { PatchedTank[MDispatch] = OrigDispatch; } catch (e) {}
}
PatchedTank = null;
OrigDispatch = null;
Stat.tankId = -1;
}
function Patch(Tank) {
if (!Tank) return;
if (PatchedTank === Tank) return;
Unpatch();
var Orig = Tank[MDispatch];
if (typeof Orig !== 'function') return;
OrigDispatch = Orig;
Tank[MDispatch] = function (Event) {
// 外力事件:直接吞掉(坦克物理收不到 → 不产生位移/旋转)
if (Stat.running && IsPushEvent(Event)) {
Stat.blocked++;
return undefined;
}
return OrigDispatch.apply(this, arguments);
};
PatchedTank = Tank;
Stat.tankId = (Tank.iz1_1 !== undefined) ? Tank.iz1_1 : -1;
console.log('[拒绝击退] 已接管本地坦克事件派发 id=' + Stat.tankId);
}
function Loop() {
if (!Stat.running) return;
requestAnimationFrame(Loop);
try {
var Tank = GetLocalTank();
if (Tank && Tank !== PatchedTank) Patch(Tank); // 换车/重生:实体换了要重新套
if (!Tank && PatchedTank) Unpatch(); // 离开战局:还原
} catch (e) {}
}
function _start() {
if (Stat.running) return;
Stat.running = true;
Stat.blocked = 0;
Patch(GetLocalTank());
requestAnimationFrame(Loop);
console.log('[拒绝击退] 已启动(中弹/撞击不再推动本地坦克;悬挂、行驶、自身后座不受影响)');
}
function _stop() {
if (!Stat.running) return;
Stat.running = false;
Unpatch();
console.log('[拒绝击退] 已停止,事件派发已还原');
}
var Tool = {
Start: function () { _start(); },
Stop: function () { _stop(); },
GetRunning: function () { return Stat.running; },
Status: function () {
if (!Stat.running) return '已停止';
return PatchedTank ? ('拦截 ' + Stat.blocked + ' 次') : '等待坦克';
}
};
window.__hornetTools__ = window.__hornetTools__ || {};
window.__hornetTools__.NoKnockback = Tool;
window.__hornetNoKnockback__ = {
IsPushEvent: IsPushEvent,
GetStat: function () {
return { running: Stat.running, blocked: Stat.blocked, tankId: Stat.tankId };
}
};
console.log('[3DTank] 拒绝击退模块已加载');
})();