feat(radar): 人机识别标记(同队装备分数相同且 < 8000)
- hornet_lib:新增 GetGearScore(BattleGearScoreCC.score → 组件 cjf_1)、ScanBots(按队伍分组,同分且低于阈值判为人机)、GetBotSet/IsBot - hornet_radar:约每 0.3 秒扫一次;人机画「灰方块 + 黄框」,真人仍「实心圆 + 白边」;顶部统计加 Bot 计数 - 重新生成 hornet_bundle.js 并同步到 unpacked
This commit is contained in:
1 parent
92b5ca6e9b
commit
2b64211173
4 files changed
+231
-30
No files matched your search
@@ -322,6 +322,49 @@
|
||||
return { current: cur, max: max, percent: cur / max };
|
||||
}
|
||||
|
||||
// ===== 装备分数(战斗 GS:BattleGearScoreCC.score 落在组件的 cjf_1 上) =====
|
||||
// 来源:module_85183 的 BattleGearScoreCC(score = cjf_1);战斗内每辆坦克各有一份
|
||||
function GetGearScore(tank) {
|
||||
var c = FindComponentByField(tank, 'cjf_1');
|
||||
if (!c || typeof c.cjf_1 !== 'number') return null;
|
||||
return c.cjf_1;
|
||||
}
|
||||
|
||||
// ===== 人机识别 =====
|
||||
// 规则:**同一队伍**内,**装备分数相同**的坦克(且分数 < maxScore,默认 8000)判为人机。
|
||||
// 组内唯一的分数不算(真人装备各不相同,机器人往往整队同款)。
|
||||
// 用法:工具定期调用 ScanBots()(约每 0.3 秒一次即可),再用 IsBot(tank) 查询。
|
||||
var BotSet = new Set();
|
||||
function ScanBots(opt) {
|
||||
opt = opt || {};
|
||||
var MaxScore = typeof opt.maxScore === 'number' ? opt.maxScore : 8000;
|
||||
BotSet = new Set();
|
||||
var gm = window.__gameMode__;
|
||||
if (!gm || !gm.q100_1) return BotSet;
|
||||
var playerTank = GetPlayerTank(gm);
|
||||
var list, n;
|
||||
try { list = gm.q100_1.r11l(); n = list.e1(); } catch (e) { return BotSet; }
|
||||
var Groups = { ally: {}, enemy: {} }; // 组 → { 分数 → [坦克...] }
|
||||
for (var i = 0; i < n; i++) {
|
||||
var tank = list.g1(i);
|
||||
if (!tank) continue;
|
||||
var gs = GetGearScore(tank);
|
||||
if (gs === null || gs >= MaxScore) continue; // 只统计低于阈值的
|
||||
var g = IsFriendly(tank, playerTank, gm) ? 'ally' : 'enemy';
|
||||
(Groups[g][gs] = Groups[g][gs] || []).push(tank);
|
||||
}
|
||||
['ally', 'enemy'].forEach(function (g) {
|
||||
var Bag = Groups[g];
|
||||
Object.keys(Bag).forEach(function (gs) {
|
||||
var Arr = Bag[gs];
|
||||
if (Arr.length >= 2) Arr.forEach(function (t) { BotSet.add(t); }); // 同队同分 → 人机
|
||||
});
|
||||
});
|
||||
return BotSet;
|
||||
}
|
||||
function GetBotSet() { return BotSet; }
|
||||
function IsBot(tank) { return BotSet.has(tank); }
|
||||
|
||||
// ===== 获取玩家坦克 =====
|
||||
// 优先 ezr_1(当前观察坦克),备用 fzr_1(本地控制坦克),再备用坦克列表第一个
|
||||
// checkPosition: 是否检查位置有效性(默认true;测试脚本传false以在死亡状态控制)
|
||||
@@ -649,6 +692,10 @@
|
||||
IsTankAlive: IsTankAlive,
|
||||
GetTankName: GetTankName,
|
||||
GetTankHealth: GetTankHealth,
|
||||
GetGearScore: GetGearScore,
|
||||
ScanBots: ScanBots,
|
||||
GetBotSet: GetBotSet,
|
||||
IsBot: IsBot,
|
||||
GetPlayerTank: GetPlayerTank,
|
||||
IsFriendly: IsFriendly,
|
||||
GetCameraInfo: GetCameraInfo,
|
||||
@@ -689,6 +736,8 @@
|
||||
}
|
||||
var teamFns = lib.LoadTeamFunctions();
|
||||
var ZCt = teamFns.ZCt, m2Fn = teamFns.m2Fn;
|
||||
// 人机标记:ScanBots 定期扫描(同队内装备分数相同且 < 8000)→ IsBot 查询
|
||||
var ScanBots = lib.ScanBots, IsBot = lib.IsBot;
|
||||
|
||||
// 组件查找:使用公共库(已修复 falsy 值漏判 bug)
|
||||
var FindComponentByField = lib.FindComponentByField;
|
||||
@@ -1228,6 +1277,12 @@
|
||||
}
|
||||
radar.tankCount = count;
|
||||
|
||||
// 人机扫描:装备分数不会每帧变,节流到约每 0.3 秒一次
|
||||
if (Ready && ScanBots && (Date.now() - (radar._lastBotScan || 0) > 300)) {
|
||||
radar._lastBotScan = Date.now();
|
||||
ScanBots();
|
||||
}
|
||||
|
||||
// 获取玩家坦克(带备用方案)
|
||||
var playerTank = Ready ? GetPlayerTank() : null;
|
||||
radar.playerFound = (playerTank !== null && playerTank !== undefined);
|
||||
@@ -1307,7 +1362,7 @@
|
||||
if (playerPos) drawTerrain(ctx, playerPos, playerAngle);
|
||||
|
||||
// 绘制所有坦克
|
||||
var friendlyCount = 0, enemyCount = 0, deadCount = 0;
|
||||
var friendlyCount = 0, enemyCount = 0, deadCount = 0, botCount = 0;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var tank = tankList.g1(i);
|
||||
if (!tank) continue;
|
||||
@@ -1351,14 +1406,26 @@
|
||||
var color = friendly ? '#4488ff' : '#ff4444';
|
||||
if (friendly) friendlyCount++; else enemyCount++;
|
||||
|
||||
// 画坦克点
|
||||
ctx.beginPath();
|
||||
ctx.arc(radarX, radarY, 5, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
// 画坦克点:人机用「灰方块 + 黄框」,真人用「实心圆 + 白边」
|
||||
var bot = (typeof IsBot === 'function') && IsBot(tank);
|
||||
if (bot) botCount++;
|
||||
if (bot) {
|
||||
ctx.beginPath();
|
||||
ctx.rect(radarX - 5, radarY - 5, 10, 10);
|
||||
ctx.fillStyle = 'rgba(170,170,170,0.55)';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffd24a';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
} else {
|
||||
ctx.beginPath();
|
||||
ctx.arc(radarX, radarY, 5, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// 画玩家(中心,三角形朝上)
|
||||
@@ -1391,7 +1458,7 @@
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
|
||||
ctx.font = '9px Arial';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ')', 5, 12);
|
||||
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ' Bot:' + botCount + ')', 5, 12);
|
||||
if (radar.playerFound) {
|
||||
ctx.fillText('Player: ' + (playerTank ? playerTank.hyt_1 : '?'), 5, 24);
|
||||
} else {
|
||||
|
||||
+77
-10
@@ -322,6 +322,49 @@
|
||||
return { current: cur, max: max, percent: cur / max };
|
||||
}
|
||||
|
||||
// ===== 装备分数(战斗 GS:BattleGearScoreCC.score 落在组件的 cjf_1 上) =====
|
||||
// 来源:module_85183 的 BattleGearScoreCC(score = cjf_1);战斗内每辆坦克各有一份
|
||||
function GetGearScore(tank) {
|
||||
var c = FindComponentByField(tank, 'cjf_1');
|
||||
if (!c || typeof c.cjf_1 !== 'number') return null;
|
||||
return c.cjf_1;
|
||||
}
|
||||
|
||||
// ===== 人机识别 =====
|
||||
// 规则:**同一队伍**内,**装备分数相同**的坦克(且分数 < maxScore,默认 8000)判为人机。
|
||||
// 组内唯一的分数不算(真人装备各不相同,机器人往往整队同款)。
|
||||
// 用法:工具定期调用 ScanBots()(约每 0.3 秒一次即可),再用 IsBot(tank) 查询。
|
||||
var BotSet = new Set();
|
||||
function ScanBots(opt) {
|
||||
opt = opt || {};
|
||||
var MaxScore = typeof opt.maxScore === 'number' ? opt.maxScore : 8000;
|
||||
BotSet = new Set();
|
||||
var gm = window.__gameMode__;
|
||||
if (!gm || !gm.q100_1) return BotSet;
|
||||
var playerTank = GetPlayerTank(gm);
|
||||
var list, n;
|
||||
try { list = gm.q100_1.r11l(); n = list.e1(); } catch (e) { return BotSet; }
|
||||
var Groups = { ally: {}, enemy: {} }; // 组 → { 分数 → [坦克...] }
|
||||
for (var i = 0; i < n; i++) {
|
||||
var tank = list.g1(i);
|
||||
if (!tank) continue;
|
||||
var gs = GetGearScore(tank);
|
||||
if (gs === null || gs >= MaxScore) continue; // 只统计低于阈值的
|
||||
var g = IsFriendly(tank, playerTank, gm) ? 'ally' : 'enemy';
|
||||
(Groups[g][gs] = Groups[g][gs] || []).push(tank);
|
||||
}
|
||||
['ally', 'enemy'].forEach(function (g) {
|
||||
var Bag = Groups[g];
|
||||
Object.keys(Bag).forEach(function (gs) {
|
||||
var Arr = Bag[gs];
|
||||
if (Arr.length >= 2) Arr.forEach(function (t) { BotSet.add(t); }); // 同队同分 → 人机
|
||||
});
|
||||
});
|
||||
return BotSet;
|
||||
}
|
||||
function GetBotSet() { return BotSet; }
|
||||
function IsBot(tank) { return BotSet.has(tank); }
|
||||
|
||||
// ===== 获取玩家坦克 =====
|
||||
// 优先 ezr_1(当前观察坦克),备用 fzr_1(本地控制坦克),再备用坦克列表第一个
|
||||
// checkPosition: 是否检查位置有效性(默认true;测试脚本传false以在死亡状态控制)
|
||||
@@ -649,6 +692,10 @@
|
||||
IsTankAlive: IsTankAlive,
|
||||
GetTankName: GetTankName,
|
||||
GetTankHealth: GetTankHealth,
|
||||
GetGearScore: GetGearScore,
|
||||
ScanBots: ScanBots,
|
||||
GetBotSet: GetBotSet,
|
||||
IsBot: IsBot,
|
||||
GetPlayerTank: GetPlayerTank,
|
||||
IsFriendly: IsFriendly,
|
||||
GetCameraInfo: GetCameraInfo,
|
||||
@@ -689,6 +736,8 @@
|
||||
}
|
||||
var teamFns = lib.LoadTeamFunctions();
|
||||
var ZCt = teamFns.ZCt, m2Fn = teamFns.m2Fn;
|
||||
// 人机标记:ScanBots 定期扫描(同队内装备分数相同且 < 8000)→ IsBot 查询
|
||||
var ScanBots = lib.ScanBots, IsBot = lib.IsBot;
|
||||
|
||||
// 组件查找:使用公共库(已修复 falsy 值漏判 bug)
|
||||
var FindComponentByField = lib.FindComponentByField;
|
||||
@@ -1228,6 +1277,12 @@
|
||||
}
|
||||
radar.tankCount = count;
|
||||
|
||||
// 人机扫描:装备分数不会每帧变,节流到约每 0.3 秒一次
|
||||
if (Ready && ScanBots && (Date.now() - (radar._lastBotScan || 0) > 300)) {
|
||||
radar._lastBotScan = Date.now();
|
||||
ScanBots();
|
||||
}
|
||||
|
||||
// 获取玩家坦克(带备用方案)
|
||||
var playerTank = Ready ? GetPlayerTank() : null;
|
||||
radar.playerFound = (playerTank !== null && playerTank !== undefined);
|
||||
@@ -1307,7 +1362,7 @@
|
||||
if (playerPos) drawTerrain(ctx, playerPos, playerAngle);
|
||||
|
||||
// 绘制所有坦克
|
||||
var friendlyCount = 0, enemyCount = 0, deadCount = 0;
|
||||
var friendlyCount = 0, enemyCount = 0, deadCount = 0, botCount = 0;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var tank = tankList.g1(i);
|
||||
if (!tank) continue;
|
||||
@@ -1351,14 +1406,26 @@
|
||||
var color = friendly ? '#4488ff' : '#ff4444';
|
||||
if (friendly) friendlyCount++; else enemyCount++;
|
||||
|
||||
// 画坦克点
|
||||
ctx.beginPath();
|
||||
ctx.arc(radarX, radarY, 5, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
// 画坦克点:人机用「灰方块 + 黄框」,真人用「实心圆 + 白边」
|
||||
var bot = (typeof IsBot === 'function') && IsBot(tank);
|
||||
if (bot) botCount++;
|
||||
if (bot) {
|
||||
ctx.beginPath();
|
||||
ctx.rect(radarX - 5, radarY - 5, 10, 10);
|
||||
ctx.fillStyle = 'rgba(170,170,170,0.55)';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffd24a';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
} else {
|
||||
ctx.beginPath();
|
||||
ctx.arc(radarX, radarY, 5, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// 画玩家(中心,三角形朝上)
|
||||
@@ -1391,7 +1458,7 @@
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
|
||||
ctx.font = '9px Arial';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ')', 5, 12);
|
||||
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ' Bot:' + botCount + ')', 5, 12);
|
||||
if (radar.playerFound) {
|
||||
ctx.fillText('Player: ' + (playerTank ? playerTank.hyt_1 : '?'), 5, 24);
|
||||
} else {
|
||||
|
||||
@@ -107,6 +107,49 @@
|
||||
return { current: cur, max: max, percent: cur / max };
|
||||
}
|
||||
|
||||
// ===== 装备分数(战斗 GS:BattleGearScoreCC.score 落在组件的 cjf_1 上) =====
|
||||
// 来源:module_85183 的 BattleGearScoreCC(score = cjf_1);战斗内每辆坦克各有一份
|
||||
function GetGearScore(tank) {
|
||||
var c = FindComponentByField(tank, 'cjf_1');
|
||||
if (!c || typeof c.cjf_1 !== 'number') return null;
|
||||
return c.cjf_1;
|
||||
}
|
||||
|
||||
// ===== 人机识别 =====
|
||||
// 规则:**同一队伍**内,**装备分数相同**的坦克(且分数 < maxScore,默认 8000)判为人机。
|
||||
// 组内唯一的分数不算(真人装备各不相同,机器人往往整队同款)。
|
||||
// 用法:工具定期调用 ScanBots()(约每 0.3 秒一次即可),再用 IsBot(tank) 查询。
|
||||
var BotSet = new Set();
|
||||
function ScanBots(opt) {
|
||||
opt = opt || {};
|
||||
var MaxScore = typeof opt.maxScore === 'number' ? opt.maxScore : 8000;
|
||||
BotSet = new Set();
|
||||
var gm = window.__gameMode__;
|
||||
if (!gm || !gm.q100_1) return BotSet;
|
||||
var playerTank = GetPlayerTank(gm);
|
||||
var list, n;
|
||||
try { list = gm.q100_1.r11l(); n = list.e1(); } catch (e) { return BotSet; }
|
||||
var Groups = { ally: {}, enemy: {} }; // 组 → { 分数 → [坦克...] }
|
||||
for (var i = 0; i < n; i++) {
|
||||
var tank = list.g1(i);
|
||||
if (!tank) continue;
|
||||
var gs = GetGearScore(tank);
|
||||
if (gs === null || gs >= MaxScore) continue; // 只统计低于阈值的
|
||||
var g = IsFriendly(tank, playerTank, gm) ? 'ally' : 'enemy';
|
||||
(Groups[g][gs] = Groups[g][gs] || []).push(tank);
|
||||
}
|
||||
['ally', 'enemy'].forEach(function (g) {
|
||||
var Bag = Groups[g];
|
||||
Object.keys(Bag).forEach(function (gs) {
|
||||
var Arr = Bag[gs];
|
||||
if (Arr.length >= 2) Arr.forEach(function (t) { BotSet.add(t); }); // 同队同分 → 人机
|
||||
});
|
||||
});
|
||||
return BotSet;
|
||||
}
|
||||
function GetBotSet() { return BotSet; }
|
||||
function IsBot(tank) { return BotSet.has(tank); }
|
||||
|
||||
// ===== 获取玩家坦克 =====
|
||||
// 优先 ezr_1(当前观察坦克),备用 fzr_1(本地控制坦克),再备用坦克列表第一个
|
||||
// checkPosition: 是否检查位置有效性(默认true;测试脚本传false以在死亡状态控制)
|
||||
@@ -434,6 +477,10 @@
|
||||
IsTankAlive: IsTankAlive,
|
||||
GetTankName: GetTankName,
|
||||
GetTankHealth: GetTankHealth,
|
||||
GetGearScore: GetGearScore,
|
||||
ScanBots: ScanBots,
|
||||
GetBotSet: GetBotSet,
|
||||
IsBot: IsBot,
|
||||
GetPlayerTank: GetPlayerTank,
|
||||
IsFriendly: IsFriendly,
|
||||
GetCameraInfo: GetCameraInfo,
|
||||
|
||||
+30
-10
@@ -22,6 +22,8 @@
|
||||
}
|
||||
var teamFns = lib.LoadTeamFunctions();
|
||||
var ZCt = teamFns.ZCt, m2Fn = teamFns.m2Fn;
|
||||
// 人机标记:ScanBots 定期扫描(同队内装备分数相同且 < 8000)→ IsBot 查询
|
||||
var ScanBots = lib.ScanBots, IsBot = lib.IsBot;
|
||||
|
||||
// 组件查找:使用公共库(已修复 falsy 值漏判 bug)
|
||||
var FindComponentByField = lib.FindComponentByField;
|
||||
@@ -561,6 +563,12 @@
|
||||
}
|
||||
radar.tankCount = count;
|
||||
|
||||
// 人机扫描:装备分数不会每帧变,节流到约每 0.3 秒一次
|
||||
if (Ready && ScanBots && (Date.now() - (radar._lastBotScan || 0) > 300)) {
|
||||
radar._lastBotScan = Date.now();
|
||||
ScanBots();
|
||||
}
|
||||
|
||||
// 获取玩家坦克(带备用方案)
|
||||
var playerTank = Ready ? GetPlayerTank() : null;
|
||||
radar.playerFound = (playerTank !== null && playerTank !== undefined);
|
||||
@@ -640,7 +648,7 @@
|
||||
if (playerPos) drawTerrain(ctx, playerPos, playerAngle);
|
||||
|
||||
// 绘制所有坦克
|
||||
var friendlyCount = 0, enemyCount = 0, deadCount = 0;
|
||||
var friendlyCount = 0, enemyCount = 0, deadCount = 0, botCount = 0;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var tank = tankList.g1(i);
|
||||
if (!tank) continue;
|
||||
@@ -684,14 +692,26 @@
|
||||
var color = friendly ? '#4488ff' : '#ff4444';
|
||||
if (friendly) friendlyCount++; else enemyCount++;
|
||||
|
||||
// 画坦克点
|
||||
ctx.beginPath();
|
||||
ctx.arc(radarX, radarY, 5, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
// 画坦克点:人机用「灰方块 + 黄框」,真人用「实心圆 + 白边」
|
||||
var bot = (typeof IsBot === 'function') && IsBot(tank);
|
||||
if (bot) botCount++;
|
||||
if (bot) {
|
||||
ctx.beginPath();
|
||||
ctx.rect(radarX - 5, radarY - 5, 10, 10);
|
||||
ctx.fillStyle = 'rgba(170,170,170,0.55)';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffd24a';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
} else {
|
||||
ctx.beginPath();
|
||||
ctx.arc(radarX, radarY, 5, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// 画玩家(中心,三角形朝上)
|
||||
@@ -724,7 +744,7 @@
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
|
||||
ctx.font = '9px Arial';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ')', 5, 12);
|
||||
ctx.fillText('Tanks: ' + count + ' (B:' + friendlyCount + ' R:' + enemyCount + ' X:' + deadCount + ' Bot:' + botCount + ')', 5, 12);
|
||||
if (radar.playerFound) {
|
||||
ctx.fillText('Player: ' + (playerTank ? playerTank.hyt_1 : '?'), 5, 24);
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user