{"version":3,"sources":["../../../src/engine/garbage/index.ts"],"sourcesContent":["import { deepCopy, RNG } from \"../utils\";\n\nexport interface GarbageQueueInitializeParams {\n  cap: {\n    value: number;\n    marginTime: number;\n    increase: number;\n    absolute: number;\n    max: number;\n  };\n  messiness: {\n    change: number;\n    within: number;\n    nosame: boolean;\n    timeout: number;\n    center: boolean;\n  };\n\n  garbage: {\n    speed: number;\n    holeSize: number;\n  };\n\n  multiplier: {\n    value: number;\n    increase: number;\n    marginTime: number;\n  };\n\n  bombs: boolean;\n\n  seed: number;\n  boardWidth: number;\n  rounding: \"down\" | \"rng\";\n  openerPhase: number;\n  specialBonus: boolean;\n}\n\nexport interface Garbage {\n  frame: number;\n  amount: number;\n  size: number;\n}\n\nexport interface IncomingGarbage extends Garbage {\n  cid: number;\n  gameid: number;\n  confirmed: boolean;\n}\nexport interface OutgoingGarbage extends Garbage {\n  id: number;\n  column: number;\n}\n\nexport interface GarbageQueueSnapshot {\n  seed: number;\n  lastTankTime: number;\n  lastColumn: number | null;\n  sent: number;\n  hasChangedColumn: boolean;\n  lastReceivedCount: number;\n  queue: IncomingGarbage[];\n}\n\nexport class GarbageQueue {\n  options: GarbageQueueInitializeParams;\n\n  queue: IncomingGarbage[];\n\n  lastTankTime: number = 0;\n  lastColumn: number | null = null;\n  hasChangedColumn: boolean = false;\n  lastReceivedCount: number = 0;\n  rng: RNG;\n\n  // for opener phase calculations\n  sent = 0;\n\n  constructor(options: GarbageQueueInitializeParams) {\n    this.options = deepCopy(options);\n    if (!this.options.cap.absolute)\n      this.options.cap.absolute = Number.MAX_SAFE_INTEGER;\n\n    this.queue = [];\n\n    this.rng = new RNG(this.options.seed);\n  }\n\n  snapshot(): GarbageQueueSnapshot {\n    return {\n      seed: this.rng.seed,\n      lastTankTime: this.lastTankTime,\n      lastColumn: this.lastColumn,\n      sent: this.sent,\n      hasChangedColumn: this.hasChangedColumn,\n      lastReceivedCount: this.lastReceivedCount,\n      queue: deepCopy(this.queue)\n    };\n  }\n\n  fromSnapshot(snapshot: GarbageQueueSnapshot) {\n    this.queue = deepCopy(snapshot.queue);\n    this.lastTankTime = snapshot.lastTankTime;\n    this.lastColumn = snapshot.lastColumn;\n    this.rng = new RNG(snapshot.seed);\n    this.sent = snapshot.sent;\n    this.hasChangedColumn = snapshot.hasChangedColumn;\n    this.lastReceivedCount = snapshot.lastReceivedCount;\n  }\n\n  rngex() {\n    return this.rng.nextFloat();\n  }\n\n  get size() {\n    return this.queue.reduce((a, b) => a + b.amount, 0);\n  }\n\n  resetReceivedCount() {\n    this.lastReceivedCount = 0;\n  }\n\n  receive(...args: IncomingGarbage[]) {\n    this.queue.push(...args.filter((arg) => arg.amount > 0));\n\n    while (this.size > this.options.cap.absolute) {\n      const total = this.size;\n      if (this.queue.at(-1)!.amount <= total - this.options.cap.absolute) {\n        this.queue.pop();\n      } else {\n        this.queue.at(-1)!.amount -= total - this.options.cap.absolute;\n      }\n    }\n  }\n\n  confirm(cid: number, gameid: number, frame: number) {\n    const obj = this.queue.find((g) => g.cid === cid && g.gameid === gameid);\n    if (!obj) return false;\n    obj.frame = frame;\n    obj.confirmed = true;\n    return true;\n  }\n\n  cancel(\n    amount: number,\n    pieceCount: number,\n    legacy: { openerPhase?: boolean } = {}\n  ) {\n    let send = amount,\n      cancel = 0;\n\n    let cancelled: IncomingGarbage[] = [];\n    if (\n      pieceCount + 1 <=\n        this.options.openerPhase - (legacy.openerPhase ? 1 : 0) &&\n      this.size >= this.sent\n    )\n      cancel += amount;\n    while ((send > 0 || cancel > 0) && this.size > 0) {\n      this.queue[0].amount--;\n      if (\n        cancelled.length === 0 ||\n        cancelled[cancelled.length - 1].cid !== this.queue[0].cid\n      ) {\n        cancelled.push({ ...this.queue[0], amount: 1 });\n      } else {\n        cancelled[cancelled.length - 1].amount++;\n      }\n      if (this.queue[0].amount <= 0) {\n        this.queue.shift();\n        if (this.rngex() < this.options.messiness.change) {\n          this.#reroll_column();\n          this.hasChangedColumn = true;\n        }\n      }\n      if (send > 0) send--;\n      else cancel--;\n    }\n\n    this.sent += send;\n    return [send, cancelled] as const;\n  }\n\n  get #columnWidth() {\n    return Math.max(\n      0,\n      this.options.boardWidth - (this.options.garbage.holeSize - 1)\n    );\n  }\n\n  #reroll_column() {\n    const centerBuffer = this.options.messiness.center\n      ? Math.round(this.options.boardWidth / 5)\n      : 0;\n\n    let col: number;\n    if (this.options.messiness.nosame && this.lastColumn !== null) {\n      col =\n        centerBuffer +\n        Math.floor(this.rngex() * (this.#columnWidth - 1 - 2 * centerBuffer));\n      if (col >= this.lastColumn) col++;\n    } else {\n      col =\n        centerBuffer +\n        Math.floor(this.rngex() * (this.#columnWidth - 2 * centerBuffer));\n    }\n\n    this.lastColumn = col;\n    return col;\n  }\n\n  tank(frame: number, cap: number, hard: boolean): OutgoingGarbage[] {\n    if (this.queue.length === 0) return [];\n\n    const res: OutgoingGarbage[] = [];\n\n    this.queue = this.queue.sort((a, b) => a.frame - b.frame);\n\n    if (\n      this.options.messiness.timeout &&\n      frame >= this.lastTankTime + this.options.messiness.timeout\n    ) {\n      this.#reroll_column();\n      this.hasChangedColumn = true;\n    }\n\n    const tankAll = false;\n    const lines = tankAll\n      ? 400\n      : Math.floor(Math.min(cap, this.options.cap.max));\n\n    for (let i = 0; i < lines && this.queue.length !== 0; i++) {\n      const item = this.queue[0];\n\n      // TODO: Fix this\n      // The real game uses an \"active\" system where garbages have a proptery, may be an issue later\n      if (item.frame + this.options.garbage.speed > (hard ? frame : frame - 1))\n        break;\n\n      item.amount--;\n      this.lastReceivedCount++;\n\n      let col: number = this.lastColumn!;\n      if (\n        (col === null || this.rngex() < this.options.messiness.within) &&\n        !this.hasChangedColumn\n      ) {\n        col = this.#reroll_column();\n        this.hasChangedColumn = true;\n      }\n\n      res.push({\n        ...item,\n        amount: 1,\n        column: col,\n        id: item.cid\n      });\n\n      this.hasChangedColumn = false;\n\n      if (item.amount <= 0) {\n        this.queue.shift();\n\n        if (this.rngex() < this.options.messiness.change) {\n          this.#reroll_column();\n          this.hasChangedColumn = true;\n        }\n      }\n    }\n\n    return res;\n  }\n\n  round(amount: number): number {\n    switch (this.options.rounding) {\n      case \"down\":\n        return Math.floor(amount);\n      case \"rng\":\n        const floored = Math.floor(amount);\n        if (floored === amount) return floored;\n        const decimal = amount - floored;\n        return floored + (this.rngex() < decimal ? 1 : 0);\n      default:\n        throw new Error(`Invalid rounding mode ${this.options.rounding}`);\n    }\n  }\n}\n\nexport * from \"./legacy\";\n"],"names":["deepCopy","RNG","GarbageQueue","options","queue","lastTankTime","lastColumn","hasChangedColumn","lastReceivedCount","rng","sent","cap","absolute","Number","MAX_SAFE_INTEGER","seed","snapshot","fromSnapshot","rngex","nextFloat","size","reduce","a","b","amount","resetReceivedCount","receive","args","push","filter","arg","total","at","pop","confirm","cid","gameid","frame","obj","find","g","confirmed","cancel","pieceCount","legacy","send","cancelled","openerPhase","length","shift","messiness","change","Math","max","boardWidth","garbage","holeSize","centerBuffer","center","round","col","nosame","floor","tank","hard","res","sort","timeout","tankAll","lines","min","i","item","speed","within","column","id","rounding","floored","decimal","Error"],"mappings":"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"}