← game tracker

THE GRIND / MULTIPLAYER

{data.game.shortName}

{#if data.user}{:else}{/if}
{#if form?.message}{/if} {#if saveError}{/if}
{#each tabs as name (name)} {#if name === 'weapons'}{/each}
{#if tab === 'weapons'}
{#if weaponPages > 1}{weaponPage}/{weaponPages}{/if} {#each rules.classes as name (name)}{/each}

{maxedWeapons} maxed · {allWeaponLevels.value} / {allWeaponLevels.total || '—'} weapon levels

{#each weaponColumns as column, columnIndex (columnIndex)}
{#each column as group (group.key)} {@const groupLevels = weaponLevelsProgress(rules, group.members, weaponRanks)}

{group.name}

{group.members.length}
{#each group.members as weapon (weapon.id)} {@const current = weaponRanks.get(weapon.id)} {@const limits = weaponRankLimits(rules, weapon)} {@const levels = countRank(limits, current)} {@const complete = weaponFinished(rules, weapon, current, isDone)}
{#if limits.rankable} weaponRanks.set(r.itemId, r)} onedit={() => { rankWeapon = weapon.id; rankOpen = true; }} /> {:else}{/if}
{/each}
{/each}
{/each} {#if !weaponRows.length}

No weapons match these filters.

{/if}

{weaponRows.length} weapons · + to level up · rank to edit / prestige · weapon name for camos · saved as you go

{:else if tab === 'achievements'}
{#each categories as [category, list] (category)} {@const rows = list.filter((item) => !hideDone || !isDone(item.id, 'done'))}

{category}

{list.filter((item) => isDone(item.id, 'done')).length} of {list.length}

isDone(item.id, 'done')).length, total: list.length }} color="sky" compact />
    {#each rows as item (item.id)}
  • {:else}
  • all unlocked.
  • {/each}
{/each}
{:else}
(challengePage = 1)} /> (challengePage = 1)} >{#each challengeCategories as category (category)}{/each}
{#each challengeRows.slice((challengePage - 1) * 36, challengePage * 36) as challenge (challenge.id)} {@const progress = data.challengeProgress.find((p) => p.challengeId === challenge.id)}
{#if challenge.icon}{/if}

{challenge.category}

{challenge.name}

{challenge.requirement}

{#if challenge.reward}

Unlock: {challenge.reward}

{/if}
{#if challenge.target}{:else}{/if}
Source & requirements ↗
{:else}

{data.challenges.length ? 'No matching challenges.' : 'No multiplayer challenge catalog has been imported for this game yet.'}

{/each}
{challengeRows.length} challenges · {challengePage} / {Math.max( 1, Math.ceil(challengeRows.length / 36) )}

Requirements adapted from Call of Duty Wiki contributors under CC BY-SA. Each card links to its source. This catalog includes confirmed source rows; coverage is not exhaustive.

{/if}
{ if (!open) detailWeaponId = null; }} > {#if detailWeapon} {@const w = detailWeapon} {@const limits = weaponRankLimits(rules, w)} {@const current = weaponRanks.get(w.id)} {w.name}{w.category} · Track every level, prestige and camo. {#if limits.rankable} weaponRanks.set(r.itemId, r)} onedit={() => { detailWeaponId = null; rankWeapon = w.id; rankOpen = true; }} />{/if} {#each rules.milestones.filter((m) => appliesTo(m, w)) as milestone (milestone.key)} {#if milestone.key === 'maxLevel' && hasReachedMaxLevel(rules, w, current)}

✓ Max level reached

{:else}{/if} {/each} {#if saveError}{/if} {/if}
{selectedWeapon?.name ?? 'Player'} level & prestigeRecord your current rank in {data.game.shortName}. Weapon prestige also records that max level has been reached.{#if form?.message}{/if}
{ rankSaving = true; return async ({ result, update }) => { await update(); rankSaving = false; if (result.type === 'success') rankOpen = false; }; }} > {#if rankWeapon}{/if}
Progress overviewMastery, camos and achievements in {data.game.shortName}.
{#each bars as bar (bar.label)} {/each}

Weapon classes

{#each classesProgress as group (group.category)}{/each}
p.done).length} unlocked · partial targets count too`} /> (weaponRanks.get(w.id)?.prestige ?? 0) > 0).length, total: weapons.length }} color="violet" />

{[...rules.milestones, ...rules.tiers] .filter((r) => r.description) .map((r) => `${r.label}: ${r.description}`) .join('. ')}. DLC weapons do not gate class or overall camos.