CCCPaste

Dynamic AntiHGF Timer

script_name("Dynamic AntiHGF")
script_author("Maku Kenesu")
script_version("1.0")

require "lib.moonloader"
require "lib.sampfuncs"
local inicfg = require "inicfg"

local LABEL_PREFIX = "[AntiHGF] "
local FULL_LABEL_PREFIX = "[AntiHGF by Maku Kenesu] "
local CONFIG_DIR_FALLBACK = getWorkingDirectory() .. "\\config\\"
local CONFIG_FILE_PATH = CONFIG_DIR_FALLBACK .. "AntiHGF.ini"

if not doesDirectoryExist(CONFIG_DIR_FALLBACK) then createDirectory(CONFIG_DIR_FALLBACK) end
if not doesFileExist(CONFIG_FILE_PATH) then
  local file = io.open(CONFIG_FILE_PATH, "w")
  file:write(" ")
  file:close()
  local defaultIni = inicfg.load({
    Options = {
      isScriptEnabled = true,
      safeSecondsFromNow = 11,
      posX = 640,
      posY = 540,
      fontSize = 14,
      fontName = "Arial Bold",
      safeText = "SAFE TO HEAL",
      unsafeText = "NOT SAFE TO HEAL",
      safeColor = "008000",
      unsafeColor = "800000"
    }
  }, CONFIG_FILE_PATH)
  inicfg.save(defaultIni, CONFIG_FILE_PATH)
end

local configIni = inicfg.load(nil, CONFIG_FILE_PATH)
inicfg.save(configIni, CONFIG_FILE_PATH)

local COLOR_PRIMARY = "{FF8400}"
local COLOR_ACCENT = "{FFC100}"
local COLOR_WHITE = "{FFFFFF}"
local COLOR_ALERT = "{FF2222}"
local COLOR_SAFE = "{22FF22}"

local wasPlayerHit = false
local lastHitTimestamp = 0
local healSafeTimestamp = configIni.Options.safeSecondsFromNow
local isFirstHitDetected = true
local renderFontHandle = nil
local textPosX = configIni.Options.posX or 640
local textPosY = configIni.Options.posY or 540
local fontSize = configIni.Options.fontSize or 14
local fontName = configIni.Options.fontName or "Arial Bold"
local selectingPosition = false
local cursorVisible = false

configIni.Options.safeText = configIni.Options.safeText or "SAFE TO HEAL"
configIni.Options.unsafeText = configIni.Options.unsafeText or "NOT SAFE TO HEAL"
configIni.Options.safeColor = configIni.Options.safeColor or "008000"
configIni.Options.unsafeColor = configIni.Options.unsafeColor or "800000"

function main()
  while not isSampAvailable() do wait(100) end
  sampAddChatMessage(COLOR_PRIMARY .. FULL_LABEL_PREFIX .. COLOR_WHITE ..
    "Loaded successfully. " .. COLOR_ACCENT .. "Timer: " .. COLOR_WHITE .. configIni.Options.safeSecondsFromNow .. "s", -1)
  sampAddChatMessage(COLOR_PRIMARY .. FULL_LABEL_PREFIX .. COLOR_WHITE ..
    "Use " .. COLOR_ACCENT .. "/hgf.help" .. COLOR_WHITE .. " for commands.", -1)
  sampRegisterChatCommand("hgf", cmdToggleScript)
  sampRegisterChatCommand("hgf.help", cmdHelp)
  sampRegisterChatCommand("hgf.h", cmdMiniHelp)
  sampRegisterChatCommand("hgf.pos", cmdEnablePositionMode)
  sampRegisterChatCommand("hgf.size", cmdChangeFontSize)
  sampRegisterChatCommand("hgf.text", cmdChangeText)
  sampRegisterChatCommand("hgf.color", cmdChangeColor)
  sampRegisterChatCommand("hgf.font", cmdChangeFont)
  renderFontHandle = renderCreateFont(fontName, fontSize, 8)
  while true do
    wait(0)
    if configIni.Options.isScriptEnabled then
      detectGunfightHit()
      updateHealSafeTimer()
    end
    drawHealStatusText()
    if selectingPosition then handleMouseClickPlacement() end
  end
end

function renderfont(x, y, text, color)
  local black = 0xFF000000
  renderFontDrawText(renderFontHandle, text, x + 1, y + 1, black)
  renderFontDrawText(renderFontHandle, text, x - 1, y + 1, black)
  renderFontDrawText(renderFontHandle, text, x + 1, y - 1, black)
  renderFontDrawText(renderFontHandle, text, x - 1, y - 1, black)
  renderFontDrawText(renderFontHandle, text, x, y, color)
end

function detectGunfightHit()
  local WEAPON_IDS = {22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34}
  for _, weaponId in ipairs(WEAPON_IDS) do
    if hasCharBeenDamagedByWeapon(PLAYER_PED, weaponId) or isCharShooting(PLAYER_PED) then
      if isFirstHitDetected then
        sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT .. configIni.Options.unsafeText, -1)
        addOneOffSound(0.0, 0.0, 0.0, 1053)
        isFirstHitDetected = false
      end
      lastHitTimestamp = os.time()
      healSafeTimestamp = lastHitTimestamp + configIni.Options.safeSecondsFromNow
      wasPlayerHit = true
      clearCharLastWeaponDamage(PLAYER_PED)
      break
    end
  end
end

function updateHealSafeTimer()
  local currentTime = os.time()
  if wasPlayerHit and currentTime >= healSafeTimestamp then
    wasPlayerHit = false
    isFirstHitDetected = true
    sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_SAFE .. configIni.Options.safeText, -1)
    addOneOffSound(0.0, 0.0, 0.0, 1052)
  end
end

function drawHealStatusText()
  if not renderFontHandle then return end
  local displayText, displayColor
  if configIni.Options.isScriptEnabled then
    if wasPlayerHit then
      displayText = configIni.Options.unsafeText
      displayColor = tonumber("0xFF" .. configIni.Options.unsafeColor)
    else
      displayText = configIni.Options.safeText
      displayColor = tonumber("0xFF" .. configIni.Options.safeColor)
    end
    renderfont(textPosX, textPosY, displayText, displayColor)
  else
    renderfont(textPosX, textPosY, LABEL_PREFIX .. "Disabled", 0xFFAAAAAA)
  end
  if selectingPosition then
    renderfont(20, 20, LABEL_PREFIX .. "Click anywhere to set text position", 0xFFFFFF00)
  end
end

function showCursorState(show)
  if show then
    if not cursorVisible then
      showCursor(true)
      lockPlayerControl(true)
      cursorVisible = true
    end
  else
    if cursorVisible then
      showCursor(false)
      lockPlayerControl(false)
      cursorVisible = false
    end
  end
end

function handleMouseClickPlacement()
  showCursorState(true)
  if wasKeyPressed(VK_LBUTTON) then
    local mx, my = getCursorPos()
    if mx and my then
      textPosX, textPosY = mx, my
      configIni.Options.posX, configIni.Options.posY = mx, my
      inicfg.save(configIni, CONFIG_FILE_PATH)
      selectingPosition = false
      showCursorState(false)
      sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_WHITE ..
        "Position saved at X: " .. COLOR_ACCENT .. mx .. COLOR_WHITE .. " Y: " .. COLOR_ACCENT .. my, -1)
    end
  end
end

function cmdEnablePositionMode()
  selectingPosition = not selectingPosition
  local stateText = selectingPosition and (COLOR_SAFE .. "Enabled") or (COLOR_ALERT .. "Disabled")
  sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_WHITE ..
    "Position selection mode: " .. stateText, -1)
  if not selectingPosition then showCursorState(false) end
end

function cmdToggleScript()
  configIni.Options.isScriptEnabled = not configIni.Options.isScriptEnabled
  local statusText = configIni.Options.isScriptEnabled and (COLOR_SAFE .. "Enabled") or (COLOR_ALERT .. "Disabled")
  sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_WHITE .. statusText, -1)
  inicfg.save(configIni, CONFIG_FILE_PATH)
end

function cmdChangeFontSize(arg)
  local size = tonumber(arg)
  if size and size > 5 and size <= 40 then
    configIni.Options.fontSize = size
    inicfg.save(configIni, CONFIG_FILE_PATH)
    renderFontHandle = renderCreateFont(configIni.Options.fontName, size, 8)
    sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_WHITE ..
      "Font size set to " .. COLOR_ACCENT .. size, -1)
  else
    sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
      "Usage: " .. COLOR_ACCENT .. "/hgf.size [6-40]", -1)
  end
end

function cmdChangeFont(arg)
  if not arg or arg == "" then
    sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
      "Usage: " .. COLOR_ACCENT .. "/hgf.font [font name]", -1)
    return
  end
  configIni.Options.fontName = arg
  inicfg.save(configIni, CONFIG_FILE_PATH)
  renderFontHandle = renderCreateFont(arg, configIni.Options.fontSize, 8)
  sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_WHITE ..
    "Font changed to " .. COLOR_ACCENT .. arg, -1)
end

function cmdChangeText(arg)
  if not arg or arg == "" then
    sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
      "Usage: " .. COLOR_ACCENT .. "/hgf.text [safe | unsafe] [your text]", -1)
    return
  end
  local t, text = arg:match("^(%S+)%s+(.+)$")
  if t and text then
    if t == "safe" then
      configIni.Options.safeText = text
      sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_SAFE ..
        "Safe text updated: " .. COLOR_WHITE .. text, -1)
    elseif t == "unsafe" then
      configIni.Options.unsafeText = text
      sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
        "Unsafe text updated: " .. COLOR_WHITE .. text, -1)
    else
      sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
        "Use: " .. COLOR_ACCENT .. "/hgf.text safe [text]" .. COLOR_WHITE .. " or " ..
        COLOR_ACCENT .. "/hgf.text unsafe [text]", -1)
      return
    end
    inicfg.save(configIni, CONFIG_FILE_PATH)
  else
    sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
      "Usage: " .. COLOR_ACCENT .. "/hgf.text [safe | unsafe] [your text]", -1)
  end
end

function cmdChangeColor(arg)
  if not arg or arg == "" then
    sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
      "Usage: " .. COLOR_ACCENT .. "/hgf.color [safe | unsafe] [RRGGBB]", -1)
    return
  end
  local t, hex = arg:match("^(%S+)%s+([A-Fa-f0-9]+)$")
  if t and hex then
    if #hex ~= 6 then
      sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
        "Color must be 6-digit hex like " .. COLOR_ACCENT .. "FF2222", -1)
      return
    end
    if t == "safe" then
      configIni.Options.safeColor = hex
      sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_SAFE ..
        "Safe color set to " .. COLOR_ACCENT .. hex, -1)
    elseif t == "unsafe" then
      configIni.Options.unsafeColor = hex
      sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
        "Unsafe color set to " .. COLOR_ACCENT .. hex, -1)
    else
      sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
        "Use: " .. COLOR_ACCENT .. "/hgf.color safe [RRGGBB]" .. COLOR_WHITE .. " or " ..
        COLOR_ACCENT .. "/hgf.color unsafe [RRGGBB]", -1)
      return
    end
    inicfg.save(configIni, CONFIG_FILE_PATH)
  else
    sampAddChatMessage(COLOR_PRIMARY .. LABEL_PREFIX .. COLOR_ALERT ..
      "Usage: " .. COLOR_ACCENT .. "/hgf.color [safe | unsafe] [RRGGBB]", -1)
  end
end

function cmdHelp()
  sampAddChatMessage(COLOR_WHITE .. "-------------- " .. COLOR_PRIMARY .. FULL_LABEL_PREFIX .. COLOR_WHITE .. "--------------", -1)
  sampAddChatMessage(COLOR_ACCENT .. "/hgf" .. COLOR_WHITE .. " - Enable/Disable script", -1)
  sampAddChatMessage(COLOR_ACCENT .. "/hgf.pos" .. COLOR_WHITE .. " - Click to choose text position", -1)
  sampAddChatMessage(COLOR_ACCENT .. "/hgf.size [6-40]" .. COLOR_WHITE .. " - Change font size", -1)
  sampAddChatMessage(COLOR_ACCENT .. "/hgf.font [font]" .. COLOR_WHITE .. " - Change font name", -1)
  sampAddChatMessage(COLOR_ACCENT .. "/hgf.text [safe | unsafe] [text]" .. COLOR_WHITE .. " - Change displayed text", -1)
  sampAddChatMessage(COLOR_ACCENT .. "/hgf.color [safe | unsafe] [RRGGBB]" .. COLOR_WHITE .. " - Change colors", -1)
  sampAddChatMessage(COLOR_ACCENT .. "/hgf.help" .. COLOR_WHITE .. " or " ..
    COLOR_ACCENT .. "/hgf.h" .. COLOR_WHITE .. " - Show help", -1)
  sampAddChatMessage(COLOR_WHITE .. "-----------------------------------------------------------------", -1)
end

function cmdMiniHelp()
  sampAddChatMessage(COLOR_ACCENT .. "/hgf" .. COLOR_WHITE ..
    ", /hgf.pos, /hgf.size, /hgf.font, /hgf.text, /hgf.color, /hgf.help", -1)
end