CCCPaste

battlefield6PortalCodeForBotRespawning

import * as modlib from "modlib";

// ======================================================
// Battlefield 6 Portal - FireRange Single Bot (v9.2C ASCII)
// Author: Greg + GPT-5
// ------------------------------------------------------
// Features:
// - Only 1 bot is spawned
// - Bot moves to complementary position and dies instantly
// - Respawns clockwise / anticlockwise / fixed
// - Speed toggle interact point: Walk -> Run -> Sprint -> Walk
// - Spawn order toggle interact point
// - Working notifications using {} placeholders
// - 0.5s cooldown on interactions
// - Fully ASCII safe
// ======================================================

// Spawn order modes
const SPAWN_CLOCKWISE = "Clockwise";
const SPAWN_ANTICLOCKWISE = "Anticlockwise";
const SPAWN_FIXED = "Fixed";

let botCurrentMoveSpeed = "Run";
let botSpawnOrder = SPAWN_FIXED;

const interactPointBotCurrentMoveSpeed = 500;
const interactPointBotSpawnOrder = 501;

let interactCooldown = false;

const ALIVE_CHECK_INTERVAL = 0.05;
const ALIVE_CHECK_DURATION = 0.5;
const POST_SPAWN_DELAY = 0.2;

const INITIAL_SPAWNER_ID = 101;

const SPAWNER_IDS = [
  101,102,103,104,105,106,107,108,109,110,111,112
];

// Outer destination positions
const POS_OUTER_FOR_SPAWNER: Record = {
  101:[10,141,55.93],  102:[17.32,141,63.25], 103:[20,141,73.25],
  104:[17.32,141,83.25], 105:[10,141,90.57], 106:[0,141,93.25],
  107:[-10,141,90.57], 108:[-17.32,141,83.25], 109:[-20,141,73.25],
  110:[-17.32,141,63.25], 111:[-10,141,55.93], 112:[0,141,55.25]
};

// Complementary spawner (opposite direction)
const POS_SPAWNER_COMPLEMENTARY: Record = {
  101:[-5,141,81.91], 102:[-8.66,141,78.25], 103:[-10,141,73.25],
  104:[-8.66,141,68.25], 105:[-5,141,64.59], 106:[0,141,63.25],
  107:[5,141,64.59], 108:[8.66,141,68.25], 109:[10,141,73.25],
  110:[8.66,141,78.25], 111:[5,141,81.91], 112:[0,141,83.25]
};

interface BotRuntime {
  player: mod.Player;
  spawnerId: number;
  posOuter: mod.Vector;
  posSpawnerComplementary: mod.Vector;
  teamId: number;
}

const bots: BotRuntime[] = [];
const spawnerToBot: Record = {};
const spawnerLock: Record = {};

// ======================================================
// Utility
// ======================================================
function createVectorFromArray(arr: number[]): mod.Vector {
  return mod.CreateVector(arr[0], arr[1], arr[2]);
}

function findBotByPlayer(p: mod.Player): BotRuntime | undefined {
  const pid = mod.GetObjId(p);
  return bots.find(b => mod.GetObjId(b.player) === pid);
}

// ======================================================
// Spawn Initial Bot
// ======================================================
async function spawnSingleBot() {
  console.log("[FireRange] Initializing AI spawn...");
  await mod.Wait(2.0);

  try {
    const team = mod.GetTeam(2);
    const sp = mod.GetSpawner(INITIAL_SPAWNER_ID);
    mod.SpawnAIFromAISpawner(sp, team);
    console.log("[FireRange] Spawned initial bot at spawner " + INITIAL_SPAWNER_ID);
  } catch (e) {
    console.log("[FireRange] Spawn failed: " + e);
  }
}

// ======================================================
// Bot Initialization and Movement
// ======================================================
async function initializeBot(bot: BotRuntime) {
  const pid = mod.GetObjId(bot.player);

  try {
    mod.AIEnableShooting(bot.player, false);
    mod.AIEnableTargeting(bot.player, false);
  } catch {}

  // Wait for AI to appear alive
  let waited = 0;
  for (let i = 0; i < ALIVE_CHECK_DURATION / ALIVE_CHECK_INTERVAL; i++) {
    if (mod.GetSoldierState(bot.player, mod.SoldierStateBool.IsAlive)) break;
    await mod.Wait(ALIVE_CHECK_INTERVAL);
    waited += ALIVE_CHECK_INTERVAL;
  }

  if (!mod.GetSoldierState(bot.player, mod.SoldierStateBool.IsAlive)) {
    console.log("[FireRange] Bot " + pid + " never became alive.");
    return;
  }

  console.log("[FireRange] Bot " + pid + " alive after " + waited.toFixed(2) + "s");

  await mod.Wait(POST_SPAWN_DELAY);

  mod.AISetStance(bot.player, mod.Stance.Stand);
  mod.AISetMoveSpeed(bot.player, mod.MoveSpeed[botCurrentMoveSpeed as keyof typeof mod.MoveSpeed]);

  // Move to complementary position
  mod.AIMoveToBehavior(bot.player, bot.posSpawnerComplementary);

  console.log("[FireRange] Bot " + pid + " moving (" + botCurrentMoveSpeed + ") to complementary position.");
}

// ======================================================
// Spawn Order Logic
// ======================================================
function getBotSpawnerIdBasedOnSpawnOrder(bot: BotRuntime, order: string): number {
  let sid = bot.spawnerId;

  switch (order) {
    case SPAWN_CLOCKWISE:
      sid = sid === 112 ? 101 : sid + 1;
      break;

    case SPAWN_ANTICLOCKWISE:
      sid = sid === 101 ? 112 : sid - 1;
      break;

    case SPAWN_FIXED:
    default:
      break;
  }
  return sid;
}

// ======================================================
// Events
// ======================================================
export function OnGameModeStarted() {
  mod.EnableInteractPoint(mod.GetInteractPoint(interactPointBotCurrentMoveSpeed), true);
  mod.EnableInteractPoint(mod.GetInteractPoint(interactPointBotSpawnOrder), true);
  spawnSingleBot();
}

export function OnSpawnerSpawned(eventPlayer: mod.Player, eventSpawner: mod.Spawner) {
  const sid = mod.GetObjId(eventSpawner);
  if (!SPAWNER_IDS.includes(sid)) return;

  const pid = mod.GetObjId(eventPlayer);
  if (!mod.GetSoldierState(eventPlayer, mod.SoldierStateBool.IsAISoldier)) return;
  if (bots.some(b => mod.GetObjId(b.player) === pid)) return;

  const bot: BotRuntime = {
    player: eventPlayer,
    spawnerId: sid,
    posOuter: createVectorFromArray(POS_OUTER_FOR_SPAWNER[sid]),
    posSpawnerComplementary: createVectorFromArray(POS_SPAWNER_COMPLEMENTARY[sid]),
    teamId: 2
  };

  bots.push(bot);
  spawnerToBot[sid] = bot;

  console.log("[FireRange] Bot spawned -> pid=" + pid + " from spawner " + sid);

  (async () => {
    await mod.Wait(POST_SPAWN_DELAY);
    initializeBot(bot);
  })();
}

export function OnAIMoveToSucceeded(player: mod.Player) {
  const bot = findBotByPlayer(player);
  if (!bot) return;

  mod.Kill(player);
  console.log("[FireRange] Bot pid=" + mod.GetObjId(player) + " reached destination and was killed.");
}

export function OnPlayerDied(eventPlayer: mod.Player) {
  const bot = findBotByPlayer(eventPlayer);
  if (!bot) return;

  const nextSpawnerId = getBotSpawnerIdBasedOnSpawnOrder(bot, botSpawnOrder);

  if (spawnerLock[nextSpawnerId]) {
    console.log("[FireRange] Respawn skipped (locked)");
    return;
  }

  spawnerLock[nextSpawnerId] = true;

  console.log("[FireRange] Bot died -> respawn at spawner " + nextSpawnerId);

  try {
    const sp = mod.GetSpawner(nextSpawnerId);
    const team = mod.GetTeam(bot.teamId);
    mod.SpawnAIFromAISpawner(sp, team);
    spawnerToBot[nextSpawnerId] = null;
  } catch (e) {
    console.log("[FireRange] Respawn error: " + e);
  }

  (async () => {
    await mod.Wait(1.5);
    spawnerLock[nextSpawnerId] = false;
  })();
}

// ======================================================
// Interact Points
// ======================================================
export function OnPlayerInteract(eventPlayer: mod.Player, eventInteractPoint: mod.InteractPoint) {
  if (interactCooldown) return;

  const id = mod.GetObjId(eventInteractPoint);

  // Speed toggle
  if (id === interactPointBotCurrentMoveSpeed) {
    switch (botCurrentMoveSpeed) {
      case "Walk": botCurrentMoveSpeed = "Run"; break;
      case "Run": botCurrentMoveSpeed = "Sprint"; break;
      case "Sprint": botCurrentMoveSpeed = "Walk"; break;
    }

    mod.DisplayNotificationMessage(
      mod.Message("Bot speed set to {}", botCurrentMoveSpeed)
    );

    console.log("[FireRange] Speed set to " + botCurrentMoveSpeed);
  }

  // Spawn order toggle
  if (id === interactPointBotSpawnOrder) {
    switch (botSpawnOrder) {
      case SPAWN_CLOCKWISE: botSpawnOrder = SPAWN_ANTICLOCKWISE; break;
      case SPAWN_ANTICLOCKWISE: botSpawnOrder = SPAWN_FIXED; break;
      case SPAWN_FIXED: botSpawnOrder = SPAWN_CLOCKWISE; break;
    }

    mod.DisplayNotificationMessage(
      mod.Message("Bot spawn order set to {}", botSpawnOrder)
    );

    console.log("[FireRange] Spawn order set to " + botSpawnOrder);
  }

  // Cooldown
  interactCooldown = true;
  (async () => {
    await mod.Wait(0.5);
    interactCooldown = false;
  })();
}