AimForge DOCS
Pricing Login
docs / examples / killfeed

Killfeed reader

Use ocr() to read the kill feed region of the screen and react to your own kills — increment a counter, trigger a script, play audio (via a function callback), etc.

Full script

//!gui:section label="Feed Region" mode="expanded"
//!gui:slider var=feedX1 label="X1" min=0 max=2560 default=1450
//!gui:slider var=feedY1 label="Y1" min=0 max=1440 default=200
//!gui:slider var=feedX2 label="X2" min=0 max=2560 default=1900
//!gui:slider var=feedY2 label="Y2" min=0 max=1440 default=320
//!gui:checkbox var=showRegion label="Show region" default=1
//!gui:endsection

//!gui:section label="Detection" mode="expanded"
//!gui:text var=triggerText label="Trigger Text" default="ENEMY DOWN"
//!gui:slider var=minConf label="OCR Confidence" min=0 max=1 default=0.7 step=0.05
//!gui:endsection

//!gui:button label="Reset Counter" func="resetKills"

// --- One-time state setup ---
if (!isset(state.lastSeen)) { state.lastSeen = ""; }
if (!isset(state.killCount)) { state.killCount = 0; }
if (!isset(state.lastKillTime)) { state.lastKillTime = 0; }

// --- Visualize the OCR region ---
if (settings.showRegion) {
  drawRectangle(settings.feedX1, settings.feedY1,
                settings.feedX2, settings.feedY2,
                "#ff7b85", 1);
}

// --- Read the kill feed ---
result = ocr("killfeed",
             settings.feedX1, settings.feedY1,
             settings.feedX2, settings.feedY2,
             settings.minConf);

if (result != null && result.confidence > settings.minConf) {
  // Detect a new entry — text changed since last frame
  if (result.text != state.lastSeen) {
    state.lastSeen = result.text;

    // Throttle: at most one "kill" per 500ms to avoid double-counts
    if (time - state.lastKillTime > 0.5) {
      // Check whether the new text contains our trigger phrase
      // (simple equality; for substring matching the runtime supports `==` only)
      if (result.text == settings.triggerText) {
        state.killCount = state.killCount + 1;
        state.lastKillTime = time;
        print("KILL #", state.killCount, ":", result.text);
      }
    }
  }
}

// --- Monitor panel ---
monitor("kills", state.killCount);
monitor("feed", state.lastSeen);

// Pass through aim values unchanged
return (x, y);

// --- Reset button handler ---
function resetKills() {
  state.killCount = 0;
  state.lastSeen = "";
  print("Counter reset");
  return 0;
}

How it works

The OCR call

result = ocr("killfeed", x1, y1, x2, y2, confidence);

ocr() is asynchronous — it queues an OCR job in the background and returns the most recent result. The "killfeed" slot ID means subsequent calls reuse the same worker. The first call after script load returns null while the worker warms up; subsequent calls return {text, confidence, ...} (see Vision).

Because it's async, calling it every frame is cheap — the cost is just looking up the cached result.

Change detection

We store the last seen text in state.lastSeen. When the current OCR result differs, we know something new has happened in the kill feed.

Throttling

time - state.lastKillTime > 0.5 ensures we don't double-count when the OCR result flickers between two valid reads of the same kill. Tune the 0.5s window to match your feed's update rate.

The reset button

//!gui:button label="Reset Counter" func="resetKills" creates a button in the GUI bound to the resetKills() function. Pressing it zeros the counter. Functions called from buttons can mutate state.*, call setSetting(), write to the log via print(), etc.

Tuning the region

Set Show region to on, then adjust the four region sliders until the red rectangle exactly covers the kill feed area on your screen. Smaller regions = faster OCR. Don't include the entire side of the screen.

Extension ideas