您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Final version: All features, restored Aimbot ESP visuals, and a new separate GUI for ESP color customization.
当前为
// ==UserScript== // @name Gats.io // @namespace // @version 10.34 // @description Final version: All features, restored Aimbot ESP visuals, and a new separate GUI for ESP color customization. // @author Discord @zeroarcop // @match https://gats.io/ // @grant GM_addStyle // @run-at document-start // @license MIT // ==/UserScript== (function() { 'use strict'; const SETTINGS_KEY = 'gats_mod_settings_v10_33'; // ESPカラーカスタマイザー用のGUIクラス class ColorCustomizerGUI { constructor() { this.container = document.createElement('div'); this.container.id = 'gemini-gats-color-gui-v10-33'; this.container.style.display = 'none'; // 初期状態は非表示 document.body.appendChild(this.container); this.applyStyles(); const head = document.createElement('h4'); head.innerText = 'ESP Color Customizer'; this.container.appendChild(head); this.makeDraggable(head, this.container); this.addColorPicker('Enemy ESP Color', 'enemyEspColor'); this.addColorPicker('Low HP Enemy Color', 'lowHpEnemyEspColor'); this.addColorPicker('Teammate ESP Color', 'teammateEspColor'); this.addColorPicker('Cloaked Enemy Text Color', 'cloakedTextColor'); // Cloaked ESPの文字色用 this.addColorPicker('Enemy Name Color', 'enemyNameColor'); this.addColorPicker('Teammate Name Color', 'teammateNameColor'); this.addColorPicker('HP Bar (High)', 'hpBarHighColor'); this.addColorPicker('HP Bar (Medium)', 'hpBarMediumColor'); this.addColorPicker('HP Bar (Low)', 'hpBarLowColor'); this.addColorPicker('Facing Line Color', 'facingLineColor'); this.addColorPicker('Bullet Dot Color', 'bulletDotColor'); const closeBtn = document.createElement('button'); closeBtn.innerText = 'Close Color Customizer (0)'; closeBtn.className = 'custom-btn'; // メインGUIと同じスタイルを流用 closeBtn.style.marginTop = '15px'; closeBtn.onclick = () => { this.container.style.display = 'none'; }; this.container.appendChild(closeBtn); } applyStyles() { GM_addStyle(` #${this.container.id} { position: fixed; left: calc(900px + 40px); top: 70px; /* メインGUIの右隣に配置 */ background-color: rgba(35, 35, 40, 0.95); color: #e0e0e0; padding: 10px; border-radius: 6px; font-family: "Segoe UI", Arial, sans-serif; font-size: 12px; z-index: 100001; border: 1px solid #555; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5); width: 250px; max-height: calc(100vh - 120px); overflow-y: auto; user-select: none; } #${this.container.id} h4 { text-align: center; color: #f0f0f0; font-weight: bold; margin-bottom: 10px; padding-bottom: 5px; border-bottom: 1px solid #666; cursor: move; } #${this.container.id} .color-picker-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } #${this.container.id} .color-picker-row label { color: #ccc; font-size: 11.5px; } #${this.container.id} input[type="color"] { border: 1px solid #555; border-radius: 3px; width: 60px; height: 25px; cursor: pointer; background-color: #2d3748; } #${this.container.id} button.custom-btn { /* メインGUIのスタイルを一部借用 */ display: block; width: calc(100% - 0px); margin: 10px 0px 0px 0px; padding: 6px 10px; background-color: #3182ce; color: white; border: 1px solid #2c5282; border-radius: 3px; cursor: pointer; font-weight: 500; font-size: 12px; } #${this.container.id} button.custom-btn:hover { background-color: #2c5282; filter: brightness(130%); } #${this.container.id}::-webkit-scrollbar { width: 8px; } #${this.container.id}::-webkit-scrollbar-track { background: #2d3748; border-radius: 4px; } #${this.container.id}::-webkit-scrollbar-thumb { background: #4a5568; border-radius: 4px; } `); } makeDraggable(dragHandle, draggableElement) { let offsetX, offsetY, isDragging = false; dragHandle.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - draggableElement.offsetLeft; offsetY = e.clientY - draggableElement.offsetTop; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); function onMouseMove(e) { if (!isDragging) return; draggableElement.style.left = (e.clientX - offsetX) + 'px'; draggableElement.style.top = (e.clientY - offsetY) + 'px';} function onMouseUp() { isDragging = false; document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); }} addColorPicker(label, settingKey, parent = this.container) { const row = document.createElement('div'); row.className = 'color-picker-row'; const lbl = document.createElement('label'); lbl.innerText = label + ":"; row.appendChild(lbl); const picker = document.createElement('input'); picker.type = 'color'; picker.id = settingKey + '-color-v1033'; picker.value = GatsModCore.SETTINGS[settingKey].startsWith('#') ? GatsModCore.SETTINGS[settingKey] : this.rgbaToHex(GatsModCore.SETTINGS[settingKey]); // rgbaも考慮 picker.oninput = () => { // リアルタイム更新 GatsModCore.SETTINGS[settingKey] = picker.value; // GatsModCore.saveSettings(); // 頻繁な保存を避けるなら onchange で }; picker.onchange = () => { // 最終的な色選択後 GatsModCore.SETTINGS[settingKey] = picker.value; GatsModCore.saveSettings(); }; row.appendChild(picker); parent.appendChild(row); } rgbaToHex(rgba) { // 簡単なrgbaからHexへの変換 (アルファは無視) if (rgba.startsWith('#')) return rgba; const parts = rgba.substring(rgba.indexOf('(') + 1, rgba.lastIndexOf(')')).split(/,\s*/); if (parts.length < 3) return '#000000'; // Default or error const r = parseInt(parts[0]).toString(16).padStart(2, '0'); const g = parseInt(parts[1]).toString(16).padStart(2, '0'); const b = parseInt(parts[2]).toString(16).padStart(2, '0'); return `#${r}${g}${b}`; } } class SimpleGUI { // (v10.25からIDのみ変更) constructor() { this.isChatInputActive = false; this.currentScrollingTextDisplay = null; this.presetEditButtons = []; this.container = document.createElement('div'); this.container.id = 'gemini-gats-gui-v10-33'; document.body.appendChild(this.container); this.applyStyles(); const mainContentWrapper = document.createElement('div'); mainContentWrapper.id = 'gui-main-content-wrapper'; this.container.appendChild(mainContentWrapper); const guiHead = document.createElement('h3'); guiHead.innerText = 'Gats.io Mod v10.33'; mainContentWrapper.appendChild(guiHead); this.makeDraggable(guiHead, this.container); const hotkeyInfo = document.createElement('p'); hotkeyInfo.innerHTML = `F: ESP | G: Aimbot | 0: Toggle GUIs | 1-9: Preset Chat`; mainContentWrapper.appendChild(hotkeyInfo); this.addCheckbox('ESP Enabled', 'espEnabled', mainContentWrapper); this.addCheckbox('Aimbot Enabled', 'aimbotEnabled', mainContentWrapper); const columnsWrapper = document.createElement('div'); columnsWrapper.id = 'gui-columns-wrapper'; mainContentWrapper.appendChild(columnsWrapper); const column1 = document.createElement('div'); column1.className = 'gui-column'; columnsWrapper.appendChild(column1); const column2 = document.createElement('div'); column2.className = 'gui-column'; columnsWrapper.appendChild(column2); const column3 = document.createElement('div'); column3.className = 'gui-column'; columnsWrapper.appendChild(column3); const espConfigSection = this.addCollapsibleSection('ESP Configuration', column1); const visualEspOptions = this.addCollapsibleSection('Visual Display (Player ESP)', espConfigSection); this.addCheckbox('Show Enemy HP', 'espShowHP', visualEspOptions); this.addCheckbox('Highlight Low HP Enemies', 'espHighlightLowHP', visualEspOptions); this.addSliderInput('Low HP Threshold (%)', 'lowHPThreshold', {min: 1, max: 99, step: 1}, GatsModCore.SETTINGS, visualEspOptions); this.addCheckbox('Show Enemy Facing Line', 'espShowFacingLine', visualEspOptions); this.addCheckbox('Highlight Cloaked Enemies', 'espHighlightCloaked', visualEspOptions); this.addCheckbox('Show Teammates', 'espShowTeammates', visualEspOptions); const espPositioningSection = this.addCollapsibleSection('Positioning & Scale (Global)', espConfigSection); this.addSliderInput('X Offset (Global)', 'espOffsetX', {min: -200, max: 200, step: 1}, GatsModCore.SETTINGS, espPositioningSection); this.addSliderInput('Y Offset (Global)', 'espOffsetY', {min: -200, max: 200, step: 1}, GatsModCore.SETTINGS, espPositioningSection); this.addSliderInput('ESP Scale', 'espScale', {min: 0.01, max: 5.0, step: 0.01}, GatsModCore.SETTINGS, espPositioningSection); const otherEspOptions = this.addCollapsibleSection('Other ESP Options', column1); this.addCheckbox('Change Landmine Color to Black', 'changeLandmineColorToBlack', otherEspOptions); this.addCheckbox('Show Enemy Bullet Dots', 'espShowBulletDots', otherEspOptions); this.addSliderInput('Bullet Dot Radius', 'bulletEspDotRadius', {min:1, max:10, step:1}, GatsModCore.SETTINGS, otherEspOptions); const aimbotConfigSection = this.addCollapsibleSection('Aimbot Configuration', column2); const generalAimbotOptions = this.addCollapsibleSection('General Targeting', aimbotConfigSection); this.addCheckbox('Always Aim', 'alwaysAim', generalAimbotOptions); this.addCheckbox('Activate Aimbot Only On Mouse Press', 'aimbotOnMousePress', generalAimbotOptions); this.addCheckbox('Target Closest to Mouse', 'aimAtMouseClosest', generalAimbotOptions); this.addSliderInput('Aimbot FOV', 'aimbotFov', {min: 10, max: 5000, step: 10}, GatsModCore.SETTINGS, generalAimbotOptions); const shieldBlockOptions = this.addCollapsibleSection('Shield Block Mode (Experimental)', generalAimbotOptions); this.addCheckbox('Enable Shield Block Aimbot', 'shieldBlockModeEnabled', shieldBlockOptions); this.addSliderInput('Shield Block FOV (Deg)', 'shieldBlockFov', {min: 10, max: 180, step: 5}, GatsModCore.SETTINGS, shieldBlockOptions); this.addSliderInput('Shield Aim Lead (px)', 'shieldBlockPredictionAmount', {min: -50, max: 50, step: 1}, GatsModCore.SETTINGS, shieldBlockOptions); this.addSliderInput('Shield Deadzone (px)', 'shieldBlockDeadzone', {min: 0, max: 200, step: 5}, GatsModCore.SETTINGS, shieldBlockOptions); const predictionSettings = this.addCollapsibleSection('Prediction Settings', aimbotConfigSection); this.addCheckbox('Prediction Enabled', 'predictionEnabled', predictionSettings); this.addSliderInput('Max Prediction Factor', 'predictionFactor', {min: 0.0, max: 5.0, step: 0.1}, GatsModCore.SETTINGS, predictionSettings); this.addCheckbox('Dynamic Prediction Scaling', 'enableDynamicPredictionFactor', predictionSettings); this.addSliderInput('Min Prediction Dist', 'minPredictionDistance', {min: 0, max: 1000, step: 10}, GatsModCore.SETTINGS, predictionSettings); this.addSliderInput('Max Prediction Dist', 'maxPredictionDistance', {min: 50, max: 2000, step: 10}, GatsModCore.SETTINGS, predictionSettings); this.addSliderInput('Factor at Min Dist', 'predictionFactorAtMinDistance', {min: 0.0, max: 2.0, step: 0.1}, GatsModCore.SETTINGS, predictionSettings); const originTuning = this.addCollapsibleSection('Bullet Origin Point', aimbotConfigSection); this.addCheckbox('Use Custom Bullet Origin', 'useCustomAimbotOrigin', originTuning); this.addSliderInput('Gun Offset Forward', 'aimbotOriginForwardOffset', {min: -50, max: 100, step: 1}, GatsModCore.SETTINGS, originTuning); this.addSliderInput('Gun Offset Sideways', 'aimbotOriginSidewaysOffset', {min: -50, max: 50, step: 1}, GatsModCore.SETTINGS, originTuning); const weaponSettingsSection = this.addCollapsibleSection('Weapon Settings', column3); const bulletSpeedSubSection = this.addCollapsibleSection('Bullet Speed Settings', weaponSettingsSection); if (GatsModCore.SETTINGS.weaponBulletSpeeds) { for (const weapon in GatsModCore.SETTINGS.weaponBulletSpeeds) { if (weapon === 'machine-gun' && GatsModCore.SETTINGS.weaponBulletSpeeds.hasOwnProperty('lmg')) continue; this.addSliderInput( weapon.charAt(0).toUpperCase() + weapon.slice(1), weapon, { min: 0.1, max: 100, step: 0.1, defaultVal: GatsModCore.SETTINGS.weaponBulletSpeeds[weapon] }, GatsModCore.SETTINGS.weaponBulletSpeeds, bulletSpeedSubSection );}} const shotgunSettings = this.addCollapsibleSection('Shotgun Auto-Reload', weaponSettingsSection); this.addCheckbox('Shotgun Auto-Reload', 'shotgunAutoReload', shotgunSettings); this.addSliderInput('Reload Delay (ms)', 'shotgunReloadDelay', {min: 0, max: 500, step: 10}, GatsModCore.SETTINGS, shotgunSettings); const chatScrollerSection = this.addCollapsibleSection('Chat Scroller', column3); this.addCheckbox('Enable Chat Scroller', 'chatScrollEnabled', chatScrollerSection); this.currentScrollingTextDisplay = document.createElement('div'); this.currentScrollingTextDisplay.style.cssText = 'margin: 5px 0; padding: 5px; background-color: #222; border: 1px solid #444; border-radius: 3px; font-style: italic; color: #bbb; word-break: break-all; min-height: 20px; font-size: 11px;'; this.updateScrollingTextDisplay(GatsModCore.SETTINGS.chatScrollText); chatScrollerSection.appendChild(this.currentScrollingTextDisplay); const scrollButtons = document.createElement('div'); scrollButtons.style.display = 'flex'; scrollButtons.style.justifyContent = 'space-around'; scrollButtons.style.marginTop = '5px'; this.addButton("Start Scroll", () => GatsModCore.startChatScroll(), scrollButtons, 'action-btn-half'); this.addButton("Stop Scroll", () => GatsModCore.stopChatScroll(), scrollButtons, 'action-btn-half'); chatScrollerSection.appendChild(scrollButtons); const customMsgSection = this.addCollapsibleSection('Custom Message & Presets', chatScrollerSection); this.addTextInput('Scroll Text', 'chatScrollText', GatsModCore.SETTINGS, customMsgSection, (newText) => { GatsModCore.SETTINGS.chatScrollText = newText; this.updateScrollingTextDisplay(newText); GatsModCore.saveSettings(); }); const presetLabel = document.createElement('p'); presetLabel.innerText = 'Presets (1-9 to use / Edit):'; presetLabel.style.textAlign = 'left'; presetLabel.style.marginTop = '10px'; customMsgSection.appendChild(presetLabel); const presetButtonContainer = document.createElement('div'); presetButtonContainer.style.cssText = 'display: grid; grid-template-columns: 1fr auto; gap: 5px; align-items: center;'; GatsModCore.SETTINGS.chatPresetMessages.forEach((msg, i) => { const presetDiv = document.createElement('div'); presetDiv.style.display = 'flex'; presetDiv.style.alignItems = 'center'; const useBtn = this.addButton(`${i+1}: ${msg.substring(0,12)}${msg.length > 12 ? '...' : ''}`, () => { GatsModCore.setScrollPreset(i); if(gatsModInstance && gatsModInstance.simpleGui) gatsModInstance.simpleGui.updateScrollingTextDisplay(GatsModCore.SETTINGS.chatScrollText); const textInput = document.getElementById('chatScrollText-text-v1033'); if(textInput) textInput.value = GatsModCore.SETTINGS.chatScrollText; }, presetDiv, 'preset-btn-item'); useBtn.title = `Use: ${msg}`; const editBtn = this.addButton("Edit", (e) => { e.stopPropagation(); GatsModCore.editScrollPreset(i); }, presetDiv, 'edit-preset-btn-item'); this.presetEditButtons[i] = {useBtn: useBtn, originalText: msg}; presetButtonContainer.appendChild(presetDiv);}); customMsgSection.appendChild(presetButtonContainer); const speedOptionsSection = this.addCollapsibleSection('Scroller Speed & Options', chatScrollerSection); this.addSliderInput('Scroll Speed (ms)', 'chatScrollSpeed', {min: 50, max: 2000, step: 10}, GatsModCore.SETTINGS, speedOptionsSection); this.addSliderInput('Max Chars Displayed', 'chatScrollMaxLength', {min: 5, max: 30, step: 1}, GatsModCore.SETTINGS, speedOptionsSection); this.addHideButton(mainContentWrapper); } applyStyles() { /* (v10.25と同じ) */ GM_addStyle(` #${this.container.id} { position: fixed; left: 20px; top: 70px; background-color: rgba(35, 35, 40, 0.95); color: #e0e0e0; padding: 10px; border-radius: 6px; font-family: "Segoe UI", Arial, sans-serif; font-size: 12.5px; z-index: 100002; border: 1px solid #555; box-shadow: 0 3px 15px rgba(0, 0, 0, 0.6); width: 900px; max-height: calc(100vh - 90px); overflow-y: auto; user-select: none;} #${this.container.id} #gui-main-content-wrapper { display: flex; flex-direction: column; } #${this.container.id} h3 { margin: 0 0 10px 0; text-align: center; border-bottom: 1px solid #666; padding-bottom: 8px; color: #f0f0f0; font-weight: bold; cursor: move; } #${this.container.id} p { font-size: 11px; text-align: center; margin: 2px 0 10px 0; color: #bbb; } #${this.container.id} #gui-columns-wrapper { display: flex; flex-direction: row; justify-content: space-between; gap: 10px; } #${this.container.id} .gui-column { width: calc(33.33% - 7px); display: flex; flex-direction: column; } #${this.container.id} label { color: #ddd; margin-left: 0px; flex-shrink: 0; display: inline-block; min-width: 100px; font-size: 12px; } #${this.container.id} input[type="checkbox"] { accent-color: #5a99c7; border: 1px solid #666; vertical-align: middle; margin-left: 5px;} #${this.container.id} input[type="number"].value-display { width: 45px; background-color: #1e1e1e; color: #e0e0e0; border: 1px solid #444; border-radius: 3px; padding: 3px 5px; text-align: right; font-family: "Segoe UI", Arial, sans-serif; margin: 0 4px; font-size:11.5px; } #${this.container.id} input[type="range"] { flex-grow: 1; margin: 0 4px; accent-color: #5a99c7; } #${this.container.id} button.slider-btn { background-color: #4a4a4a; color: #f0f0f0; border: 1px solid #666; border-radius: 3px; padding: 0px 6px; font-size: 14px; line-height: 20px; cursor: pointer; min-width: 22px; } #${this.container.id} button.slider-btn:hover { background-color: #666; } #${this.container.id} details { border: 1px solid #4a4a4a; border-radius: 4px; padding: 5px; margin: 10px 0; background-color: rgba(40, 40, 45, 0.7); } #${this.container.id} summary { cursor: pointer; outline: none; font-weight: 600; color: #e0e0e0; padding: 3px; font-size: 12.5px;} #${this.container.id} details[open] > summary { border-bottom: 1px solid #4a4a4a; margin-bottom: 8px; } #${this.container.id} details > div { padding: 8px 5px 0 5px; } #${this.container.id} button.custom-btn, #${this.container.id} button.action-btn { background-color: #3182ce; color: white; border: 1px solid #2c5282; margin-top: 8px; padding: 5px 8px; display: block; width: calc(100% - 0px); margin: 10px 0px 0px 0px; border-radius: 3px; cursor: pointer; font-weight: 500; font-size: 12px;} #${this.container.id} button.action-btn-half { width: 48%; display: inline-block; margin-left: 1%; margin-right: 1%; } #${this.container.id} button.preset-btn, #${this.container.id} button.edit-preset-btn, #${this.container.id} button.preset-btn-item, #${this.container.id} button.edit-preset-btn-item { min-width: auto; width: auto; margin: 2px; padding: 3px 6px; display: inline-block; background-color: #4A5568; color:#e2e8f0; font-size: 11px; line-height: 1.4; border: 1px solid #718096; border-radius: 3px;} #${this.container.id} button.edit-preset-btn, #${this.container.id} button.edit-preset-btn-item { padding: 2px 5px; font-size: 10px; margin-left: auto; background-color: #718096;} #${this.container.id} button:hover { filter: brightness(120%);} #${this.container.id} button.custom-btn:hover { background-color: #718096; } #${this.container.id} button.action-btn:hover, #${this.container.id} button.action-btn-half:hover { background-color: #2c5282; filter: brightness(130%);} #${this.container.id} button.preset-btn:hover, #${this.container.id} button.edit-preset-btn:hover, #${this.container.id} button.preset-btn-item:hover, #${this.container.id} button.edit-preset-btn-item:hover { background-color: #718096; filter: brightness(110%); } #${this.container.id} .gui-slider-container > div { margin-bottom: 4px; } #${this.container.id} input[type="text"].chat-scroll-input { width: calc(100% - 12px); background-color: #1a202c; color: #e2e8f0; border: 1px solid #2d3748; border-radius: 3px; padding: 4px 5px; margin-bottom: 5px;} #${this.container.id} div[style*="background-color: #222"] { background-color: #2d3748 !important; color: #a0aec0 !important; border: 1px solid #4a5568 !important; } #${this.container.id}::-webkit-scrollbar { width: 10px; } #${this.container.id}::-webkit-scrollbar-track { background: #2d3748; border-radius: 4px; } #${this.container.id}::-webkit-scrollbar-thumb { background: #4a5568; border-radius: 4px; } #${this.container.id}::-webkit-scrollbar-thumb:hover { background: #718096; } `);} makeDraggable(dragHandle, draggableElement) { /* (v10.25と同じ) */ let offsetX, offsetY, isDragging = false; dragHandle.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - draggableElement.offsetLeft; offsetY = e.clientY - draggableElement.offsetTop; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); function onMouseMove(e) { if (!isDragging) return; draggableElement.style.left = (e.clientX - offsetX) + 'px'; draggableElement.style.top = (e.clientY - offsetY) + 'px';} function onMouseUp() { isDragging = false; document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); }} addCheckbox(label, settingKey, parent = this.container) { /* (v10.25と同じ。IDのvナンバーのみ変更) */ const div = document.createElement('div'); div.style.cssText = 'display: flex; align-items: center; justify-content: space-between; padding: 2px 0;'; const lbl = document.createElement('label'); lbl.htmlFor = settingKey + '-v1033'; lbl.innerText = label; lbl.style.flexGrow = '1'; const cb = document.createElement('input'); cb.type = 'checkbox'; cb.id = settingKey + '-v1033'; cb.checked = GatsModCore.SETTINGS[settingKey]; cb.onchange = () => { GatsModCore.SETTINGS[settingKey] = cb.checked; GatsModCore.saveSettings(); if(settingKey === 'changeLandmineColorToBlack') GatsModCore.toggleLandmineColor(); }; div.appendChild(lbl); div.appendChild(cb); parent.appendChild(div); return div;} addCollapsibleSection(title, parent = this.container) { /* (v10.25と同じ) */ const det = document.createElement('details'); const sum = document.createElement('summary'); sum.innerText = title; det.appendChild(sum); const cont = document.createElement('div'); det.appendChild(cont); parent.appendChild(det); return cont; } addSliderInput(label, settingKey, opts, objToUpdate, parent) { /* (v10.25と同じ。IDのvナンバーのみ変更) */const itemContainer = document.createElement('div'); itemContainer.style.cssText = 'display: flex; flex-direction: column; margin-bottom: 5px;'; const labelElement = document.createElement('label'); labelElement.htmlFor = settingKey + '-slider-v1033'; labelElement.innerText = label; labelElement.style.marginBottom = '3px'; itemContainer.appendChild(labelElement); const controlsContainer = document.createElement('div'); controlsContainer.style.cssText = 'display: flex; align-items: center; width: 100%;'; const minusButton = document.createElement('button'); minusButton.innerText = '-'; minusButton.className = 'slider-btn'; controlsContainer.appendChild(minusButton); const slider = document.createElement('input'); slider.type = 'range'; slider.id = settingKey + '-slider-v1033'; slider.min = opts.min; slider.max = opts.max; slider.step = opts.step; slider.value = objToUpdate[settingKey] === undefined ? (opts.defaultVal !== undefined ? opts.defaultVal : opts.min) : objToUpdate[settingKey]; controlsContainer.appendChild(slider); const plusButton = document.createElement('button'); plusButton.innerText = '+'; plusButton.className = 'slider-btn'; controlsContainer.appendChild(plusButton); const valueDisplay = document.createElement('input'); valueDisplay.type = 'number'; valueDisplay.className = 'value-display'; valueDisplay.min = opts.min; valueDisplay.max = opts.max; valueDisplay.step = opts.step; valueDisplay.value = slider.value; controlsContainer.appendChild(valueDisplay); const updateFromInput = () => { let val = parseFloat(valueDisplay.value); if (isNaN(val)) val = opts.defaultVal !== undefined ? opts.defaultVal : opts.min; val = Math.max(parseFloat(opts.min), Math.min(parseFloat(opts.max), val)); const decimals = opts.step.toString().includes('.') ? opts.step.toString().split('.')[1].length : 0; valueDisplay.value = val.toFixed(decimals); slider.value = val; objToUpdate[settingKey] = val; GatsModCore.saveSettings(); }; const updateFromSlider = () => { const val = parseFloat(slider.value); const decimals = opts.step.toString().includes('.') ? opts.step.toString().split('.')[1].length : 0; valueDisplay.value = val.toFixed(decimals); objToUpdate[settingKey] = val; GatsModCore.saveSettings(); }; slider.oninput = updateFromSlider; valueDisplay.onchange = updateFromInput; valueDisplay.onblur = updateFromInput; minusButton.onclick = () => { let val = parseFloat(slider.value) - opts.step; val = Math.max(parseFloat(opts.min), val); slider.value = val; updateFromSlider(); }; plusButton.onclick = () => { let val = parseFloat(slider.value) + opts.step; val = Math.min(parseFloat(opts.max), val); slider.value = val; updateFromSlider(); }; itemContainer.appendChild(controlsContainer); parent.appendChild(itemContainer); return itemContainer;} addHideButton(parent = this.container) { /* (v10.25と同じ) */ const btn = document.createElement('button'); btn.innerText = 'Hide GUI (0)'; btn.className = 'custom-btn'; btn.onclick = () => { if (this.container && this.container.style) this.container.style.display = 'none'; if (gatsModInstance && gatsModInstance.colorGui && gatsModInstance.colorGui.container) gatsModInstance.colorGui.container.style.display = 'none';}; parent.appendChild(btn); } // カラーGUIも隠す addButton(label, onClickAction, parent = this.container, className = 'action-btn') { /* (v10.25と同じ) */ const button = document.createElement('button'); button.innerText = label; button.className = className; if(className === 'preset-btn-item') { button.style.cssText = 'flex-grow: 1; margin-right: 3px; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;';} else if(className === 'edit-preset-btn-item') { button.style.cssText = 'padding: 2px 5px; font-size: 10px; line-height: 1.2; margin-left: auto; flex-shrink: 0;'; className='action-btn'; button.className = className; } else if(className === 'preset-btn') { button.style.minWidth = '25px'; button.style.margin = '3px'; button.style.padding = '4px 7px'; } else if (className === 'action-btn-half') { button.style.width = '48%'; button.style.margin = '5px 1%'; } button.onclick = onClickAction; parent.appendChild(button); return button;} addTextInput(label, settingKey, objToUpdate, parent, onSaveCallback) { /* (v10.25と同じ。IDのvナンバー、フォーカスリスナー修正) */ const itemContainer = document.createElement('div'); itemContainer.style.cssText = 'display: flex; flex-direction: column; margin-bottom: 5px;'; const labelElement = document.createElement('label'); labelElement.htmlFor = settingKey + '-text-v1033'; labelElement.innerText = label; labelElement.style.marginBottom = '3px'; itemContainer.appendChild(labelElement); const input = document.createElement('input'); input.type = 'text'; input.id = settingKey + '-text-v1033'; input.value = objToUpdate[settingKey]; input.className = 'chat-scroll-input'; input.maxLength = 100; input.onfocus = () => { GatsModCore.isInputActive = true; }; input.onblur = () => { GatsModCore.isInputActive = false; }; itemContainer.appendChild(input); const saveButton = this.addButton("Save & Set Text", () => { objToUpdate[settingKey] = input.value; GatsModCore.saveSettings(); if (onSaveCallback) onSaveCallback(input.value); if(this.updateScrollingTextDisplay) this.updateScrollingTextDisplay(input.value); }, itemContainer, 'action-btn'); saveButton.style.width = 'auto'; saveButton.style.padding = '3px 8px'; saveButton.style.marginTop = '3px'; parent.appendChild(itemContainer); return itemContainer;} updateScrollingTextDisplay(newText) { /* (v10.25と同じ) */ if (this.currentScrollingTextDisplay) { this.currentScrollingTextDisplay.innerText = newText.length > 35 ? newText.substring(0, 32) + "..." : newText; }} updatePresetButtonLabel(index, newText) { /* (v10.25と同じ) */ if (this.presetEditButtons && this.presetEditButtons[index] && this.presetEditButtons[index].useBtn) { this.presetEditButtons[index].useBtn.innerText = `${index + 1}: ${newText.substring(0,12)}${newText.length > 12 ? '...' : ''}`; this.presetEditButtons[index].useBtn.title = `Use: ${newText}`; }} } // GatsModCore クラス (ESPカラー設定追加、描画ロジック変更) class GatsModCore { static SETTINGS = {}; static originalLandmineColors = null; static chatScrollIntervalId = null; static chatScrollCurrentIndex = 0; static isInputActive = false; isSpaceBarDown = false; colorGui = null; // カラーカスタマイザーGUIのインスタンス constructor() { this.initializeSettings(); this.gameCanvas = null; this.overlayCanvas = null; this.overlayCtx = null; this.simpleGui = null; this.aimTargetScreenCoords = null; this.isModInitialized = false; this.debugLogTimer = Date.now(); this.tickCounter = 0; this.originalDocumentOnMouseMove = document.onmousemove; this.realMouseButtons = 0; this.realMouseCanvasX = 0; this.realMouseCanvasY = 0; this.shotgunContinuousReloadInterval = null; console.log('[GatsModCore v10.33] Constructor...'); this.attemptToHookClearRect(); } static saveSettings() { try { localStorage.setItem(SETTINGS_KEY, JSON.stringify(GatsModCore.SETTINGS)); } catch (e) { console.error("[GatsMod v10.33] Error saving settings:", e); }} initializeSettings() { // ESPカラー設定を追加 let savedSettings = {}; try { const item = localStorage.getItem(SETTINGS_KEY); if (item) savedSettings = JSON.parse(item); } catch (e) { console.error("[GatsMod v10.33] Error loading settings, using defaults:", e); } GatsModCore.SETTINGS = { // Default settings from v10.31 changeLandmineColorToBlack: savedSettings.changeLandmineColorToBlack ?? true, espShowBulletDots: savedSettings.espShowBulletDots ?? false, alwaysAim: savedSettings.alwaysAim ?? false, aimbotOnMousePress: savedSettings.aimbotOnMousePress ?? true, aimAtMouseClosest: savedSettings.aimAtMouseClosest ?? true, predictionFactor: savedSettings.predictionFactor ?? 2.5, maxPredictionDistance: savedSettings.maxPredictionDistance ?? 200, useCustomAimbotOrigin: savedSettings.useCustomAimbotOrigin ?? true, aimbotOriginForwardOffset: savedSettings.aimbotOriginForwardOffset ?? -5, aimbotOriginSidewaysOffset: savedSettings.aimbotOriginSidewaysOffset ?? -18, shotgunAutoReload: savedSettings.shotgunAutoReload ?? false, chatScrollEnabled: savedSettings.chatScrollEnabled ?? true, shieldBlockDeadzone: savedSettings.shieldBlockDeadzone ?? 44, espShowTeammates: savedSettings.espShowTeammates ?? true, shieldBlockModeEnabled: savedSettings.shieldBlockModeEnabled ?? true, shieldBlockFov: savedSettings.shieldBlockFov ?? 140, shieldBlockPredictionAmount:savedSettings.shieldBlockPredictionAmount ?? 10, shotgunReloadDelay: savedSettings.shotgunReloadDelay ?? 100, espEnabled: savedSettings.espEnabled ?? true, aimbotEnabled: savedSettings.aimbotEnabled ?? true, predictionEnabled: savedSettings.predictionEnabled ?? true, enableDynamicPredictionFactor: savedSettings.enableDynamicPredictionFactor ?? true, minPredictionDistance: savedSettings.minPredictionDistance ?? 0, predictionFactorAtMinDistance: savedSettings.predictionFactorAtMinDistance ?? 0.0, espShowHP: savedSettings.espShowHP ?? true, espHighlightLowHP: savedSettings.espHighlightLowHP ?? true, lowHPThreshold: savedSettings.lowHPThreshold ?? 30, espShowFacingLine: savedSettings.espShowFacingLine ?? true, espHighlightCloaked: savedSettings.espHighlightCloaked ?? true, bulletEspDotRadius: savedSettings.bulletEspDotRadius ?? 2, chatScrollText: savedSettings.chatScrollText ?? "Gats.io Mod!", chatScrollSpeed: savedSettings.chatScrollSpeed ?? 200, chatScrollMaxLength: savedSettings.chatScrollMaxLength ?? 28, chatPresetMessages: Array.isArray(savedSettings.chatPresetMessages) && savedSettings.chatPresetMessages.length === 9 ? savedSettings.chatPresetMessages : [ "Hello!", "GL HF", "<3", "...", "Gats Mod", "GG", "Nice!", "OMG", "AFK" ], espOffsetX: savedSettings.espOffsetX ?? 0, espOffsetY: savedSettings.espOffsetY ?? 0, espScale: savedSettings.espScale ?? 0.89, aimbotFov: savedSettings.aimbotFov ?? 2250, weaponBulletSpeeds: savedSettings.weaponBulletSpeeds ?? { 'pistol': 7, 'smg': 4, 'shotgun': 16, 'assault': 5, 'sniper': 32, 'lmg': 8, 'machine-gun': 8 }, // New ESP Color Settings enemyEspColor: savedSettings.enemyEspColor ?? '#FF0000', // Red lowHpEnemyEspColor: savedSettings.lowHpEnemyEspColor ?? '#FFA500', // Orange teammateEspColor: savedSettings.teammateEspColor ?? '#0096FF', // Blue cloakedTextColor: savedSettings.cloakedTextColor ?? '#E0E0E0', // Light Grey / White for "透明" enemyNameColor: savedSettings.enemyNameColor ?? '#000000', // Black teammateNameColor: savedSettings.teammateNameColor ?? '#ADD8E6', // Light Blue hpBarHighColor: savedSettings.hpBarHighColor ?? '#00FF00', // Lime hpBarMediumColor: savedSettings.hpBarMediumColor ?? '#FFFF00', // Yellow hpBarLowColor: savedSettings.hpBarLowColor ?? '#FF0000', // Red facingLineColor: savedSettings.facingLineColor ?? '#00FFFF', // Cyan bulletDotColor: savedSettings.bulletDotColor ?? '#000000' // Black }; } areGameGlobalsReady() { /* (v10.31 と同じ) */ const selfIdReady = typeof selfId !== 'undefined' && selfId !== null; const playerPoolReady = typeof Player !== 'undefined' && Player.pool && typeof Player.pool === 'object'; const selfPlayerObject = (selfIdReady && playerPoolReady && Player.pool.hasOwnProperty(selfId)) ? Player.pool[selfId] : null; const selfPlayerValidAndActive = selfPlayerObject && typeof selfPlayerObject.activated === 'number' && selfPlayerObject.activated === 1 && typeof selfPlayerObject.hp === 'number' && selfPlayerObject.hp > 0 && typeof selfPlayerObject.x === 'number' && typeof selfPlayerObject.y === 'number'; const cameraReady = typeof camera !== 'undefined' && camera !== null; const inGameFlag = typeof inGame !== 'undefined' && inGame === true; const canvasElement = document.getElementById('canvas'); const updateMouseDataFuncReady = typeof updateMouseData === 'function'; const connectionReady = typeof Connection !== 'undefined' && Connection.list && Connection.list[0] && Connection.list[0].socket; if (this.tickCounter % 300 === 0) { console.log(`[DebugWait v10.33] Globals: selfId:${selfIdReady}, selfActive:${selfPlayerValidAndActive}, connection:${connectionReady}`);} return selfPlayerValidAndActive && cameraReady && inGameFlag && !!canvasElement && updateMouseDataFuncReady && connectionReady;} attemptToHookClearRect() { /* (v10.31 と同じ) */ const gameCanvas = document.getElementById('canvas'); if(gameCanvas){this.gameCanvas = gameCanvas; const ctx = gameCanvas.getContext('2d'); if(ctx && typeof ctx.clearRect === 'function' && !CanvasRenderingContext2D.prototype.clearRect._hookedByGatsMod){console.log(`[GatsModCore v10.33] Hooking clearRect.`); const oCR = CanvasRenderingContext2D.prototype.clearRect; const self = this; CanvasRenderingContext2D.prototype.clearRect = function(...args){oCR.apply(this,args); if(this.canvas === self.gameCanvas){if(!self.isModInitialized && self.areGameGlobalsReady()){self.initializeModVisualsAndLogic();} if(self.isModInitialized){self.mainGameTick();}}}; CanvasRenderingContext2D.prototype.clearRect._hookedByGatsMod = true; return;}} requestAnimationFrame(()=>this.attemptToHookClearRect());} initializeModVisualsAndLogic() { // カラーカスタマイザーGUIの初期化を追加 if (this.isModInitialized) return; console.log(`[GatsModCore v10.33] Initializing Visuals & Logic.`); this.overlayCanvas = document.createElement('canvas'); this.overlayCanvas.id = 'gemini-gats-mod-overlay'; this.overlayCanvas.style.position = 'absolute'; this.overlayCanvas.style.left = (this.gameCanvas ? this.gameCanvas.offsetLeft : 0) + 'px'; this.overlayCanvas.style.top = (this.gameCanvas ? this.gameCanvas.offsetTop : 0) + 'px'; this.overlayCanvas.width = this.gameCanvas ? this.gameCanvas.width : window.innerWidth; this.overlayCanvas.height = this.gameCanvas ? this.gameCanvas.height : window.innerHeight; this.overlayCanvas.style.zIndex = '100001'; this.overlayCanvas.style.pointerEvents = 'none'; document.body.appendChild(this.overlayCanvas); this.overlayCtx = this.overlayCanvas.getContext('2d'); if (typeof SimpleGUI !== 'undefined' && !document.getElementById('gemini-gats-gui-v10-33')) { gatsModInstance.simpleGui = new SimpleGUI(); } if (typeof ColorCustomizerGUI !== 'undefined' && !document.getElementById('gemini-gats-color-gui-v10-33')) { gatsModInstance.colorGui = new ColorCustomizerGUI(); } // カラーGUIも初期化 this.addKeyListeners(); this.hookAndProcessMouseEvents(); if (this.gameCanvas) { this.resizeObserver = new ResizeObserver(entries => { for (let entry of entries) { if (entry.target === this.gameCanvas && this.overlayCanvas) { this.overlayCanvas.width = this.gameCanvas.width; this.overlayCanvas.height = this.gameCanvas.height; this.overlayCanvas.style.left = this.gameCanvas.offsetLeft + 'px'; this.overlayCanvas.style.top = this.gameCanvas.offsetTop + 'px'; if(this.colorGui && this.colorGui.container) { /* カラーGUIの位置も調整する場合はここ */}}}}); this.resizeObserver.observe(this.gameCanvas); } const canvasOrDoc = this.gameCanvas || document; canvasOrDoc.addEventListener('mousedown', (e) => { if (e.target === this.gameCanvas || (this.simpleGui && this.simpleGui.container && !this.simpleGui.container.contains(e.target)) ) { this.realMouseButtons = e.buttons; this.startShotgunContinuousReload(); }}); canvasOrDoc.addEventListener('mouseup', (e) => { if (e.target === this.gameCanvas || (this.simpleGui && this.simpleGui.container && !this.simpleGui.container.contains(e.target)) ) { this.realMouseButtons = e.buttons; if (e.button === 0 && GatsModCore.SETTINGS.shotgunAutoReload && Player.pool[selfId]?.class === 'shotgun') this.stopShotgunContinuousReload(); }}); if (GatsModCore.SETTINGS.changeLandmineColorToBlack) { setTimeout(() => { GatsModCore.toggleLandmineColor(); }, 1500); } this.isModInitialized = true; console.log(`[GatsModCore v10.33] Mod Logic Initialized.`); } addKeyListeners() { // 0キーで両方のGUIをトグル window.addEventListener('keydown', (e) => { if (GatsModCore.isInputActive) { if (e.key === "Escape") { if(document.activeElement && typeof document.activeElement.blur === 'function') document.activeElement.blur(); GatsModCore.isInputActive = false; } return; } if (document.activeElement && (document.activeElement.tagName === 'INPUT' && document.activeElement.type === 'number')) { if (!['f','g','0'].includes(e.key.toLowerCase())) return; } if (e.code === 'Space') this.isSpaceBarDown = true; const key = e.key.toLowerCase(); let checkbox; if (key === 'f') { GatsModCore.SETTINGS.espEnabled = !GatsModCore.SETTINGS.espEnabled; checkbox = document.getElementById('espEnabled-v1033'); if (checkbox) checkbox.checked = GatsModCore.SETTINGS.espEnabled; GatsModCore.saveSettings(); } else if (key === 'g') { GatsModCore.SETTINGS.aimbotEnabled = !GatsModCore.SETTINGS.aimbotEnabled; checkbox = document.getElementById('aimbotEnabled-v1033'); if (checkbox) checkbox.checked = GatsModCore.SETTINGS.aimbotEnabled; GatsModCore.saveSettings(); } else if (e.key === '0') { if (this.simpleGui && this.simpleGui.container && this.simpleGui.container.style) { const currentDisplay = this.simpleGui.container.style.display; this.simpleGui.container.style.display = (currentDisplay === 'none' ? 'block' : 'none'); if (this.colorGui && this.colorGui.container && this.colorGui.container.style) { // カラーGUIもトグル this.colorGui.container.style.display = (currentDisplay === 'none' ? 'block' : 'none'); } console.log(`[GatsModCore] GUIs Toggled via 0 key to: ${this.simpleGui.container.style.display}`); } } else if (GatsModCore.SETTINGS.chatScrollEnabled && !GatsModCore.isInputActive && e.keyCode >= 49 && e.keyCode <= 57) { /* ... */ } }); window.addEventListener('keyup', (e) => { if (e.code === 'Space') this.isSpaceBarDown = false; }); } // ... (残りのメソッドはv10.32から流用、drawESPAndAimbotのみ色設定参照に変更) hookAndProcessMouseEvents() { if (this.originalDocumentOnMouseMove === undefined && typeof document.onmousemove === 'function' && !document.onmousemove._hookedByGatsModMouse_v1033) { this.originalDocumentOnMouseMove = document.onmousemove; } const self = this; document.onmousemove = function(event) { if (self.gameCanvas) { const canvasRect = self.gameCanvas.getBoundingClientRect(); self.realMouseCanvasX = event.clientX - canvasRect.left; self.realMouseCanvasY = event.clientY - canvasRect.top; } if ( GatsModCore.SETTINGS.aimbotEnabled && self.aimTargetScreenCoords && self.isModInitialized && (!GatsModCore.SETTINGS.aimbotOnMousePress || self.realMouseButtons > 0) ) { event.preventDefault(); event.stopPropagation(); return false; } if (self.originalDocumentOnMouseMove) { return self.originalDocumentOnMouseMove.call(document, event); } else if (typeof updateMouseData === 'function') { return updateMouseData(event); } return true; }; document.onmousemove._hookedByGatsModMouse_v1033 = true;} simulateKeyPress(keyCode, key, code) { const downEvent = new KeyboardEvent('keydown', { keyCode: keyCode, key: key, code: code, bubbles: true, cancelable: true }); document.dispatchEvent(downEvent); setTimeout(() => { const upEvent = new KeyboardEvent('keyup', { keyCode: keyCode, key: key, code: code, bubbles: true, cancelable: true }); document.dispatchEvent(upEvent); }, 30); } startShotgunContinuousReload() { if (!this.isModInitialized || !GatsModCore.SETTINGS.shotgunAutoReload) return; const me = Player.pool[selfId]; if (me && me.class === 'shotgun' && (this.realMouseButtons === 1 || (GatsModCore.SETTINGS.alwaysAim && this.aimTargetScreenCoords ) ) ) { this.stopShotgunContinuousReload(); this.shotgunContinuousReloadInterval = setInterval(() => { const currentPlayer = Player.pool[selfId]; if (currentPlayer && currentPlayer.hp > 0 && currentPlayer.activated && (currentPlayer.reloading === 0 || currentPlayer.reloading === undefined) ) { this.simulateKeyPress(82, 'r', 'KeyR'); } else { this.stopShotgunContinuousReload(); }}, GatsModCore.SETTINGS.shotgunReloadDelay);}} stopShotgunContinuousReload() { if (this.shotgunContinuousReloadInterval) { clearInterval(this.shotgunContinuousReloadInterval); this.shotgunContinuousReloadInterval = null; }} applyAimbotAiming() { if (!this.aimTargetScreenCoords || !this.gameCanvas || typeof updateMouseData !== 'function') { return; } const canvasRect = this.gameCanvas.getBoundingClientRect(); let buttonsToSimulate = 0; if (GatsModCore.SETTINGS.alwaysAim) { buttonsToSimulate = 1; } else { buttonsToSimulate = this.realMouseButtons; } const fakeEvent = { clientX: this.aimTargetScreenCoords.x + canvasRect.left, clientY: this.aimTargetScreenCoords.y + canvasRect.top, target: this.gameCanvas, buttons: buttonsToSimulate }; updateMouseData(fakeEvent); } mainGameTick() { this.tickCounter++; if (!this.isModInitialized || !this.overlayCtx || !this.areGameGlobalsReady()){ return; } const me = Player.pool[selfId]; if (!me || !me.activated || me.hp <= 0) { this.aimTargetScreenCoords = null; this.stopShotgunContinuousReload(); return; } this.overlayCtx.clearRect(0, 0, this.overlayCanvas.width, this.overlayCanvas.height); let isAimbotActuallyActive = false; let shieldBlockActiveThisTick = false; if (GatsModCore.SETTINGS.shieldBlockModeEnabled && typeof levelUpgrades !== 'undefined' && levelUpgrades[2] === 'shield' && this.isSpaceBarDown) { shieldBlockActiveThisTick = true; } if (GatsModCore.SETTINGS.aimbotEnabled) { if (shieldBlockActiveThisTick) { isAimbotActuallyActive = true; } else if (GatsModCore.SETTINGS.aimbotOnMousePress) { if (this.realMouseButtons > 0) isAimbotActuallyActive = true; } else { isAimbotActuallyActive = true; }} this.performAimbotTargeting(me, shieldBlockActiveThisTick); if (!this.aimTargetScreenCoords) isAimbotActuallyActive = false; if (isAimbotActuallyActive) { this.applyAimbotAiming(); } this.drawESPAndAimbot(this.overlayCtx, me, isAimbotActuallyActive, shieldBlockActiveThisTick); } performAimbotTargeting(me, isShieldBlockingNow) { /* (v10.31 と同じ) */ if (!this.gameCanvas) { this.aimTargetScreenCoords = null; return; } let shotOriginX_world = me.x; let shotOriginY_world = me.y; if (GatsModCore.SETTINGS.useCustomAimbotOrigin && !isShieldBlockingNow) { const angleRad = (me.playerAngle || 0) * Math.PI / 180; const forward = GatsModCore.SETTINGS.aimbotOriginForwardOffset; const sideways = GatsModCore.SETTINGS.aimbotOriginSidewaysOffset; shotOriginX_world += forward * Math.cos(angleRad) + sideways * Math.cos(angleRad + Math.PI / 2); shotOriginY_world += forward * Math.sin(angleRad) + sideways * Math.sin(angleRad + Math.PI / 2); } const canvasCenterX = this.gameCanvas.width / 2; const canvasCenterY = this.gameCanvas.height / 2; let referenceX = GatsModCore.SETTINGS.aimAtMouseClosest && !isShieldBlockingNow ? this.realMouseCanvasX : canvasCenterX; let referenceY = GatsModCore.SETTINGS.aimAtMouseClosest && !isShieldBlockingNow ? this.realMouseCanvasY : canvasCenterY; let closestTargetDistSq = isShieldBlockingNow ? Infinity : (GatsModCore.SETTINGS.aimbotFov / (GatsModCore.SETTINGS.aimAtMouseClosest ? 1 : GatsModCore.SETTINGS.espScale))**2; let targetCandidate = null; if (isShieldBlockingNow) { if (typeof Bullet !== 'undefined' && Bullet.pool) { let closestBulletWorldDistSq = Infinity; const deadzoneSq = GatsModCore.SETTINGS.shieldBlockDeadzone**2; for (const id in Bullet.pool) { const bullet = Bullet.pool[id]; if (!bullet || !bullet.activated || String(bullet.ownerId) === String(selfId) || (me.teamCode !== 0 && bullet.teamCode === me.teamCode)) continue; const worldDistToBulletSq = (bullet.x - me.x)**2 + (bullet.y - me.y)**2; if (worldDistToBulletSq < deadzoneSq) continue; const playerAngleRad = (me.playerAngle || 0) * Math.PI / 180; const angleToBullet = Math.atan2(bullet.y - me.y, bullet.x - me.x); let angleDiff = Math.abs(playerAngleRad - angleToBullet); if (angleDiff > Math.PI) angleDiff = 2 * Math.PI - angleDiff; if (angleDiff <= (GatsModCore.SETTINGS.shieldBlockFov / 2) * (Math.PI / 180)) { if (worldDistToBulletSq < closestBulletWorldDistSq) { closestBulletWorldDistSq = worldDistToBulletSq; targetCandidate = { x_world: bullet.x, y_world: bullet.y, spdX_world: bullet.spdX || 0, spdY_world: bullet.spdY || 0 };}}}}} else { for (const id in Player.pool) { const p = Player.pool[id]; if (!p || p.hp <= 0 || String(p.id) == String(selfId) || !p.activated || (me.teamCode !== 0 && p.teamCode === me.teamCode) ) continue; let worldTargetX = p.x; let worldTargetY = p.y; if (GatsModCore.SETTINGS.predictionEnabled) { const currentWeaponClass = me.class || 'pistol'; let bulletSpeed = GatsModCore.SETTINGS.weaponBulletSpeeds[currentWeaponClass] || GatsModCore.SETTINGS.weaponBulletSpeeds.lmg || 20; bulletSpeed = Math.max(0.1, bulletSpeed); if (p.spdX !== undefined && p.spdY !== undefined) { let timeToHit = 0; let futureX_intermediate = p.x; let futureY_intermediate = p.y; for (let i = 0; i < 2; i++) { const distanceToFuturePos = Math.sqrt((futureX_intermediate - shotOriginX_world)**2 + (futureY_intermediate - shotOriginY_world)**2); timeToHit = distanceToFuturePos < 1 ? 0 : distanceToFuturePos / bulletSpeed; timeToHit = Math.min(timeToHit, 5); let displacementX_iter = p.spdX * timeToHit; let displacementY_iter = p.spdY * timeToHit; futureX_intermediate = p.x + displacementX_iter; futureY_intermediate = p.y + displacementY_iter;} let baseDisplacementX = p.spdX * timeToHit; let baseDisplacementY = p.spdY * timeToHit; let actualPredictionFactor = GatsModCore.SETTINGS.predictionFactor; if (GatsModCore.SETTINGS.enableDynamicPredictionFactor) { const distanceToEnemy = Math.sqrt((p.x - shotOriginX_world)**2 + (p.y - shotOriginY_world)**2); const minFactor = GatsModCore.SETTINGS.predictionFactorAtMinDistance; const maxFactor = GatsModCore.SETTINGS.predictionFactor; const minDist = GatsModCore.SETTINGS.minPredictionDistance; const maxDist = GatsModCore.SETTINGS.maxPredictionDistance; if (distanceToEnemy <= minDist) { actualPredictionFactor = minFactor; } else if (distanceToEnemy >= maxDist) { actualPredictionFactor = maxFactor; } else { if (maxDist > minDist) { const ratio = (distanceToEnemy - minDist) / (maxDist - minDist); actualPredictionFactor = minFactor + (maxFactor - minFactor) * ratio; } else { actualPredictionFactor = maxFactor; }} actualPredictionFactor = Math.max(0, actualPredictionFactor); } const finalDisplacementX = baseDisplacementX * actualPredictionFactor; const finalDisplacementY = baseDisplacementY * actualPredictionFactor; worldTargetX = p.x + finalDisplacementX; worldTargetY = p.y + finalDisplacementY;}} const screenTargetXUnscaled = canvasCenterX + (worldTargetX - me.x); const screenTargetYUnscaled = canvasCenterY + (worldTargetY - me.y); const distToRefSq = (screenTargetXUnscaled - referenceX)**2 + (screenTargetYUnscaled - referenceY)**2; if (distToRefSq < closestTargetDistSq) { closestTargetDistSq = distToRefSq; targetCandidate = { x_world: worldTargetX, y_world: worldTargetY };}}} if (targetCandidate && (isShieldBlockingNow || closestTargetDistSq <= (GatsModCore.SETTINGS.aimbotFov / (GatsModCore.SETTINGS.aimAtMouseClosest ? 1 : GatsModCore.SETTINGS.espScale))**2) ) { let finalScreenTargetX = canvasCenterX + (targetCandidate.x_world - me.x) / GatsModCore.SETTINGS.espScale; let finalScreenTargetY = canvasCenterY + (targetCandidate.y_world - me.y) / GatsModCore.SETTINGS.espScale; if (isShieldBlockingNow && targetCandidate.spdX_world !== undefined) { const screenSpdX = targetCandidate.spdX_world / GatsModCore.SETTINGS.espScale; const screenSpdY = targetCandidate.spdY_world / GatsModCore.SETTINGS.espScale; const speedMagScreen = Math.sqrt(screenSpdX**2 + screenSpdY**2); if (speedMagScreen > 0.1) { const normScreenSpdX = screenSpdX / speedMagScreen; const normScreenSpdY = screenSpdY / speedMagScreen; finalScreenTargetX += normScreenSpdX * GatsModCore.SETTINGS.shieldBlockPredictionAmount; finalScreenTargetY += normScreenSpdY * GatsModCore.SETTINGS.shieldBlockPredictionAmount; }} this.aimTargetScreenCoords = { x: finalScreenTargetX + GatsModCore.SETTINGS.espOffsetX, y: finalScreenTargetY + GatsModCore.SETTINGS.espOffsetY }; } else { this.aimTargetScreenCoords = null; }} drawESPAndAimbot(ctx, me, isAimbotActuallyActive, isShieldBlockingNow) { // ★★★ 色設定を参照 ★★★ if (!this.overlayCanvas || !ctx || !this.gameCanvas) return; const canvasCenterX = this.gameCanvas.width / 2; const canvasCenterY = this.gameCanvas.height / 2; const isTDM = (typeof gameType !== 'undefined' && gameType === 'TDM'); ctx.save(); ctx.textAlign = 'center'; if (isShieldBlockingNow && GatsModCore.SETTINGS.shieldBlockDeadzone > 0) { const screenRadius = GatsModCore.SETTINGS.shieldBlockDeadzone / GatsModCore.SETTINGS.espScale; ctx.fillStyle = 'rgba(128, 128, 128, 0.15)'; ctx.beginPath(); ctx.arc(canvasCenterX + GatsModCore.SETTINGS.espOffsetX, canvasCenterY + GatsModCore.SETTINGS.espOffsetY, screenRadius, 0, 2 * Math.PI); ctx.fill();} if (GatsModCore.SETTINGS.espEnabled) { ctx.font = 'bold 10px Arial'; for (const id in Player.pool) { const p = Player.pool[id]; if (!p || p.hp <= 0 || String(p.id) == String(selfId) || !p.activated) continue; const isPlayerTeammate = (me.teamCode !== 0 && p.teamCode === me.teamCode); if (isPlayerTeammate && !GatsModCore.SETTINGS.espShowTeammates) continue; const relX = (p.x - me.x) / GatsModCore.SETTINGS.espScale; const relY = (p.y - me.y) / GatsModCore.SETTINGS.espScale; const screenX = canvasCenterX + relX + GatsModCore.SETTINGS.espOffsetX; const screenY = canvasCenterY + relY + GatsModCore.SETTINGS.espOffsetY; const playerRadiusOnScreen = (p.radius || 15) / GatsModCore.SETTINGS.espScale; const hpMax = p.hpMax || 100; const hpPercent = p.hp / hpMax; let currentEspBoxColor = isPlayerTeammate ? GatsModCore.SETTINGS.teammateEspColor : GatsModCore.SETTINGS.enemyEspColor; let currentEspLineWidth = 1.5; let currentNameColor = isPlayerTeammate ? GatsModCore.SETTINGS.teammateNameColor : GatsModCore.SETTINGS.enemyNameColor; if (!isPlayerTeammate && GatsModCore.SETTINGS.espHighlightLowHP && hpPercent < (GatsModCore.SETTINGS.lowHPThreshold / 100)) { currentEspBoxColor = GatsModCore.SETTINGS.lowHpEnemyEspColor; currentEspLineWidth = 2; } ctx.strokeStyle = currentEspBoxColor; ctx.lineWidth = currentEspLineWidth; ctx.strokeRect(screenX - playerRadiusOnScreen, screenY - playerRadiusOnScreen, playerRadiusOnScreen * 2, playerRadiusOnScreen * 2); ctx.beginPath(); ctx.moveTo(canvasCenterX + GatsModCore.SETTINGS.espOffsetX, canvasCenterY + GatsModCore.SETTINGS.espOffsetY); ctx.lineTo(screenX, screenY); ctx.stroke(); let nameYOffset = screenY - playerRadiusOnScreen - 15; if (GatsModCore.SETTINGS.espHighlightCloaked && parseInt(p.ghillie) === 1 && !isPlayerTeammate) { ctx.font = 'bold 12px Arial'; ctx.fillStyle = GatsModCore.SETTINGS.cloakedTextColor; ctx.fillText('透明', screenX, nameYOffset); nameYOffset -= 14; } if (p.username) { ctx.font = 'bold 10px Arial'; ctx.fillStyle = currentNameColor; ctx.fillText(p.username, screenX, nameYOffset); } if (GatsModCore.SETTINGS.espShowHP) { const barWidth = playerRadiusOnScreen * 1.8; const barHeight = 4; const barX = screenX - barWidth / 2; const barY = screenY + playerRadiusOnScreen + 4; ctx.fillStyle = 'rgba(0,0,0,0.5)'; ctx.fillRect(barX, barY, barWidth, barHeight); ctx.fillStyle = hpPercent > 0.6 ? GatsModCore.SETTINGS.hpBarHighColor : hpPercent > 0.3 ? GatsModCore.SETTINGS.hpBarMediumColor : GatsModCore.SETTINGS.hpBarLowColor; ctx.fillRect(barX, barY, barWidth * hpPercent, barHeight); } if (GatsModCore.SETTINGS.espShowFacingLine && p.playerAngle !== undefined) { const angleRad = p.playerAngle * Math.PI / 180; const lineLength = playerRadiusOnScreen * 1.2; const lineEndX = screenX + lineLength * Math.cos(angleRad); const lineEndY = screenY + lineLength * Math.sin(angleRad); ctx.beginPath(); ctx.moveTo(screenX, screenY); ctx.lineTo(lineEndX, lineEndY); ctx.strokeStyle = GatsModCore.SETTINGS.facingLineColor; ctx.lineWidth = 2; ctx.stroke(); } } } if (GatsModCore.SETTINGS.espEnabled && GatsModCore.SETTINGS.espShowBulletDots && typeof Bullet !== 'undefined' && Bullet.pool) { ctx.fillStyle = GatsModCore.SETTINGS.bulletDotColor; const dotRadius = GatsModCore.SETTINGS.bulletEspDotRadius; for (const id in Bullet.pool) { const bullet = Bullet.pool[id]; if (!bullet || !bullet.activated || bullet.isKnife) continue; let isEnemyBullet = false; if (String(bullet.ownerId) === String(selfId)) continue; if (me.teamCode === 0) { isEnemyBullet = true; } else { if (bullet.teamCode === 0 || bullet.teamCode !== me.teamCode) { isEnemyBullet = true; }} if (!isEnemyBullet) continue; const bulletScreenX = canvasCenterX + (bullet.x - me.x) / GatsModCore.SETTINGS.espScale + GatsModCore.SETTINGS.espOffsetX; const bulletScreenY = canvasCenterY + (bullet.y - me.y) / GatsModCore.SETTINGS.espScale + GatsModCore.SETTINGS.espOffsetY; if (bulletScreenX < 0 || bulletScreenX > this.overlayCanvas.width || bulletScreenY < 0 || bulletScreenY > this.overlayCanvas.height) continue; ctx.beginPath(); ctx.arc(bulletScreenX, bulletScreenY, dotRadius, 0, 2 * Math.PI); ctx.fill();}} if (GatsModCore.SETTINGS.aimbotEnabled && this.aimTargetScreenCoords && isAimbotActuallyActive) { const aimX = this.aimTargetScreenCoords.x; const aimY = this.aimTargetScreenCoords.y; let aimLineStartX = canvasCenterX + GatsModCore.SETTINGS.espOffsetX; let aimLineStartY = canvasCenterY + GatsModCore.SETTINGS.espOffsetY; if (GatsModCore.SETTINGS.useCustomAimbotOrigin && !isShieldBlockingNow ) { const angleRad = (me.playerAngle || 0) * Math.PI / 180; const forward = GatsModCore.SETTINGS.aimbotOriginForwardOffset; const sideways = GatsModCore.SETTINGS.aimbotOriginSidewaysOffset; const gunWorldOffsetX = forward * Math.cos(angleRad) + sideways * Math.cos(angleRad + Math.PI / 2); const gunWorldOffsetY = forward * Math.sin(angleRad) + sideways * Math.sin(angleRad + Math.PI / 2); aimLineStartX = canvasCenterX + (gunWorldOffsetX / GatsModCore.SETTINGS.espScale) + GatsModCore.SETTINGS.espOffsetX; aimLineStartY = canvasCenterY + (gunWorldOffsetY / GatsModCore.SETTINGS.espScale) + GatsModCore.SETTINGS.espOffsetY;} ctx.strokeStyle = 'lime'; ctx.lineWidth = 1.0; ctx.beginPath(); ctx.moveTo(aimLineStartX, aimLineStartY); ctx.lineTo(aimX, aimY); ctx.stroke(); ctx.beginPath(); ctx.arc(aimX, aimY, 15, 0, 2 * Math.PI); ctx.stroke();} ctx.restore(); } static toggleLandmineColor() { /* (v10.31 と同じ) */ if (typeof landMine === 'undefined' || !landMine[0] || typeof landMine[0].forEach !== 'function') { console.warn("[GatsMod] 'landMine' data not found. Cannot change color."); if (GatsModCore.SETTINGS.changeLandmineColorToBlack) { GatsModCore.SETTINGS.changeLandmineColorToBlack = false; const checkbox = document.getElementById('changeLandmineColorToBlack-v1013'); if(checkbox) checkbox.checked = false; GatsModCore.saveSettings(); } return; } if (GatsModCore.SETTINGS.changeLandmineColorToBlack) { if (!GatsModCore.originalLandmineColors) { GatsModCore.originalLandmineColors = []; landMine[0].forEach((part, i) => { if (part && part[1] && part[1].length > 3 && typeof part[1][3] === 'string' && part[1][3].startsWith('#')) { GatsModCore.originalLandmineColors[i] = part[1][3]; } else { GatsModCore.originalLandmineColors[i] = null; }});} landMine[0].forEach((part, i) => { if (part && part[1] && part[1].length > 3) { part[1][3] = "#000000"; }}); console.log("[GatsMod] Landmine color changed to black."); } else { if (GatsModCore.originalLandmineColors) { landMine[0].forEach((part, i) => { if (part && part[1] && part[1].length > 3 && GatsModCore.originalLandmineColors[i] !== null) { part[1][3] = GatsModCore.originalLandmineColors[i]; }}); GatsModCore.originalLandmineColors = null; console.log("[GatsMod] Landmine colors reverted.");}}} static chatScrollLoop() { /* (v10.31 と同じ) */ if (!GatsModCore.SETTINGS.chatScrollActive || !GatsModCore.SETTINGS.chatScrollEnabled) return; if (typeof Connection === 'undefined' || !Connection.list || !Connection.list[0] || !Connection.list[0].socket || typeof Connection.list[0].socket.send !== 'function') { GatsModCore.stopChatScroll(); return; } const s = GatsModCore.SETTINGS.chatScrollText; if (!s || s.length === 0) { GatsModCore.stopChatScroll(); return; } let maxLength = GatsModCore.SETTINGS.chatScrollMaxLength; if (s.length < maxLength) { maxLength = s.length; } let displayText = s.substring(GatsModCore.chatScrollCurrentIndex, GatsModCore.chatScrollCurrentIndex + maxLength); if (displayText.length < maxLength) { displayText += s.substring(0, maxLength - displayText.length); } let z = displayText.replaceAll(",", "~"); try { if (typeof Connection.list[0].socket.send === 'function') { Connection.list[0].socket.send(`c,${z}\x00`); } else { GatsModCore.stopChatScroll(); }} catch (e) { GatsModCore.stopChatScroll(); } GatsModCore.chatScrollCurrentIndex = (GatsModCore.chatScrollCurrentIndex + 1) % s.length; if (GatsModCore.SETTINGS.chatScrollActive) { setTimeout(GatsModCore.chatScrollLoop, GatsModCore.SETTINGS.chatScrollSpeed);}} static startChatScroll() { /* (v10.31 と同じ) */ if (!GatsModCore.SETTINGS.chatScrollEnabled) { alert("Chat Scroller is disabled in settings."); return; } GatsModCore.SETTINGS.chatScrollActive = true; GatsModCore.chatScrollCurrentIndex = 0; if (gatsModInstance && gatsModInstance.simpleGui && typeof gatsModInstance.simpleGui.updateScrollingTextDisplay === 'function') { gatsModInstance.simpleGui.updateScrollingTextDisplay(GatsModCore.SETTINGS.chatScrollText); } GatsModCore.chatScrollLoop(); } static stopChatScroll() { /* (v10.31 と同じ) */ GatsModCore.SETTINGS.chatScrollActive = false; } static editScrollPreset(index) { /* (v10.31 と同じ) */ if (!GatsModCore.SETTINGS.chatPresetMessages || GatsModCore.SETTINGS.chatPresetMessages[index] === undefined) return; const currentMessage = GatsModCore.SETTINGS.chatPresetMessages[index]; const newMessage = prompt(`プリセット ${index + 1} の新しいメッセージを入力してください:`, currentMessage.trimEnd()); if (newMessage !== null ) { GatsModCore.SETTINGS.chatPresetMessages[index] = newMessage + " "; GatsModCore.saveSettings(); if (gatsModInstance && gatsModInstance.simpleGui && typeof gatsModInstance.simpleGui.updatePresetButtonLabel === 'function') { gatsModInstance.simpleGui.updatePresetButtonLabel(index, newMessage + " ");} if(GatsModCore.SETTINGS.chatScrollText.trimEnd() === currentMessage.trimEnd()) { GatsModCore.SETTINGS.chatScrollText = newMessage + " "; if (gatsModInstance && gatsModInstance.simpleGui && typeof gatsModInstance.simpleGui.updateScrollingTextDisplay === 'function') { gatsModInstance.simpleGui.updateScrollingTextDisplay(GatsModCore.SETTINGS.chatScrollText); const textInput = document.getElementById('chatScrollText-text-v1032'); if(textInput) textInput.value = GatsModCore.SETTINGS.chatScrollText;}} alert(`プリセット ${index + 1} が更新されました。`);}} static setScrollPreset(index) { /* (v10.31 と同じ) */ if (GatsModCore.SETTINGS.chatPresetMessages && GatsModCore.SETTINGS.chatPresetMessages[index]) { GatsModCore.SETTINGS.chatScrollText = GatsModCore.SETTINGS.chatPresetMessages[index]; GatsModCore.saveSettings(); GatsModCore.startChatScroll(); }} } let gatsModInstance = null; function tryInitializeMod() { if (typeof Player !== 'undefined' && Player.pool && typeof selfId !== 'undefined' && camera && document.getElementById('canvas') && typeof Connection !== 'undefined') { if (!gatsModInstance) { gatsModInstance = new GatsModCore(); }} else { setTimeout(tryInitializeMod, 500); }} tryInitializeMod(); })();(function() { 'use strict'; window.addEventListener ("load", onload); function onload() { let processMessageTmp = processMessage; processMessage = function(event) { processMessageTmp(event); let decoded = new TextDecoder().decode(event.data); if (!decoded.includes("a,")) return; camera.update = function() { let player = Player.pool[selfId]; if (camera.trackingId) { camera.x = player.x - hudXPosition; camera.y = player.y - hudYPosition; } } } } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址