# Spearity

`Spearity`, [Rarity](https://www.curseforge.com/wow/addons/rarity) (yazar: **Allara**, GPL-2.0)
addonunun bağımsız bir fork'udur. Rarity ile aynı anda kurulabilir; ayarları ve
istatistikleri tamamen ayrıdır.

## Kurulum

`Spearity` ve `Spearity_Options` klasörlerini şuraya kopyala:

```
World of Warcraft\_retail_\Interface\AddOns\
```

Oyun içinde `/spearity` veya `/spear` yaz.

## Fork'ta yapılan değişiklikler (r752-spear1)

Temel: Rarity `r752-alpha-17` (upstream'in son resmi sürümü r751, Ocak 2026).

- Addon klasörleri `Rarity` / `Rarity_Options` → `Spearity` / `Spearity_Options`
- Tüm global identifier'lar, frame ve popup adları, keybinding adları `Spearity` oldu
- SavedVariables: `RarityDB` → `SpearityDB` (ayarlar sıfırdan başlar, Rarity'ninkine dokunmaz)
- AceAddon / AceLocale / LibDataBroker kayıt adları `Spearity`
- Slash komutları: `/rarity`, `/rare` → `/spearity`, `/spear`
- AddOn Compartment fonksiyonları: `Spearity_OnAddonCompartmentClick` vb.
- TOC `Interface` değeri `120001` → `120100` (retail 12.1.0, Ağustos 2026)
- `X-Curse-Project-ID` kaldırıldı (addon yöneticileri klasörü Rarity ile ezmesin diye)
- İkon: `spear.png` guild logosundan üretilen `Icons/spearity.tga` (64x64) —
  TOC `IconTexture`, minimap butonu, addon compartment ve takip barı varsayılan ikonu.
  `Icons/spearity-large.tga` (128x128) yedek olarak duruyor.

## Bakım notu

Upstream'de yeni bir sürüm çıktığında: yeni Rarity kaynağını al, yukarıdaki
yeniden adlandırmaları tekrar uygula (`Rarity`→`Spearity`, `RARITY`→`SPEARITY`,
`/rarity`→`/spearity`, `"rare"`→`"spear"` chat komutu), `Icons/spearity*.tga`
dosyalarını ve bu notu geri koy.

Lisans: GPL-2.0 (bkz. `Spearity/LICENSE`). Orijinal telif hakkı Allara'ya aittir.

## r752-spear2 — güncel client API düzeltmeleri

Upstream'de kalmış, retail 12.1.0'da çöken çağrılar:

- `UIParentLoadAddOn` artık FrameXML globalleri arasında yok →
  `C_AddOns.LoadAddOn`'a geçildi (`Core/Collections.lua`, `Core/GUI/MainWindow.lua`).
  Bu, girişte gelen `Collections.lua:71: attempt to call a nil value` hatasıydı.
- `CombatText_AddMessage` yükleme sonrası hâlâ yoksa artık `UIErrorsFrame`'e düşüyor
  (ikinci bir hata zincirini önlemek için).
- Eski companion API'si (`GetNumCompanions` / `GetCompanionInfo`) nil ise no-op'a düşüyor.
- Pet Journal filtre sabitleri: `LE_PET_JOURNAL_FILTER_*` yoksa `Enum.PetJournalFilter`
  kullanılıyor, o da yoksa filtre çağrısı atlanıyor.

`SpearityAPICheck/` klasörü tek kullanımlık teşhis addonudur: addonun kullandığı
91 global API'den hangileri bu client'ta yok, girişte sohbete yazar. İşi bitince
klasörü silebilirsin.

## r752-spear3 — 12.0'da kaldırılan combat log API'si

- `CombatLogGetCurrentEventInfo` patch 12.0.0'da kaldırıldı; yerine
  `C_CombatLog.GetCurrentEventInfo` geldi. `Core.lua` ve `Core/EventHandlers.lua`
  bu fonksiyonu upvalue olarak alıyordu. **Çağrı yerlerinin tamamı zaten yorum
  satırında olduğu için çökme üretmiyordu**, ama upvalue'lar artık doğru API'ye
  bakıyor (o kod bir gün açılırsa çalışsın diye).
- `LE_PET_JOURNAL_FLAG_*` sabitleri de bu client'ta yok, ama onları kullanan
  dal (`C_PetJournal.SetFlagFilter ~= nil`, 7.0 öncesi) retail'de hiç
  çalışmıyor — yine de spear2'de guard'landı.

`SpearityAPICheck` v2'ye çıktı: artık sadece dosya başındaki upvalue'ları değil,
doğrudan çağrı yerlerini ve açık `_G.X` erişimlerini de tarıyor — 117 global.
TSM_API ve TomTom listeden çıkarıldı (üçüncü parti, kodda zaten guard'lı).

## r752-spear4 — LoadOnDemand fonksiyonu guard'landı

- `AchievementShield_SetPoints`, `Blizzard_AchievementUI` (LoadOnDemand) içinde
  tanımlı olduğu için girişte global değil — teşhis addonunun onu "eksik"
  göstermesi bu yüzden **yanlış alarmdı**. Kod onu ancak `AchievementFrame_LoadUI()`
  çağrıldıktan sonra kullanıyor, yani mevcut haliyle de çalışıyor olması gerek.
- Yine de `FauxAchievementPopup.lua` içinde guard'landı: fonksiyon yoksa
  başarım rozetindeki puan etiketi boş bırakılıyor. Çağrı sadece kozmetik
  (her zaman 0 puan yazıyor), o yüzden fallback kayıpsız.

### Teşhis addonunun bilinen kısıtı

`SpearityAPICheck` PLAYER_LOGIN'de çalışır, dolayısıyla LoadOnDemand
addonlarının (Blizzard_AchievementUI, Blizzard_Collections, Blizzard_CombatText)
tanımladığı fonksiyonları "eksik" gösterir. Bu beklenen davranış.

## 1.0 — ilk yayın sürümü

- **Community bölümü kaldırıldı.** `Spearity_Options/Options.lua` içindeki
  `community` grubu (GitHub ve Discord bağlantı butonları) tamamen silindi —
  26 satır. Rebrand sonrası o linkler zaten var olmayan adreslere gidiyordu.
  `CopyPastePopup` modülü duruyor, çünkü debug penceresi de onu kullanıyor.
- **Sürüm 1.0.** Upstream'in SVN kalıntısı `rNNN` parse'ı `Core/Init.lua`'dan
  kaldırıldı; TOC'taki `## Version` artık tek kaynak.
  - `Spearity.VERSION` → ham string ("1.0"), Options başlığında gösterilir
  - `Spearity.MINOR_VERSION` → sayısal (major*10000 + minor*100 + patch, yani
    1.0 = 10000). Eski `r752`'nin üstünde kalır, `lastRevision` ve export
    payload'ı bozulmaz. `rNNN` biçimi de hâlâ tanınıyor.
- TOC `Notes` alanı temizlendi (AddOns listesinde fork açıklaması görünmüyor),
  `Author` alanı `Candas (fork of Rarity by Allara)` oldu. Atıf hem burada hem
  `LICENSE` dosyasında ve bu notta duruyor — GPL-2.0 için gereken bu.

## CurseForge'a yüklerken

1. **`SpearityAPICheck` klasörünü paketlemeye dahil etme** — o teşhis aracı, silin.
2. Zip'in kökünde `Spearity/` ve `Spearity_Options/` klasörleri olmalı (başka
   sarmalayıcı klasör olmadan).
3. Proje oluşturduktan sonra CurseForge sana bir proje ID'si verir; onu
   `## X-Curse-Project-ID: <id>` olarak `Spearity.toc`'a ekle. Şu an kasıtlı
   olarak yok — Rarity'nin ID'si (30801) duruyor olsaydı addon yöneticileri
   klasörü Rarity ile ezerdi.
4. `#@no-lib-strip@` / `#@end-no-lib-strip@` işaretleyicilerine dokunma;
   CurseForge paketleyicisi kütüphaneleri ayıklamak için onları okuyor.
5. Proje açıklamasına bunun Rarity fork'u olduğunu ve GPL-2.0 altında
   dağıtıldığını yaz. GPL bu dağıtıma izin veriyor, tek şart atıf ve lisansın
   korunması — ikisi de yerinde.

## Teşhis addonu v3 — sınıflandırmalı

`SpearityAPICheck` artık eksikleri ikiye ayırıyor:

- **Bilinen eksikler** (şu an 6 tane): kodda zaten ele alınmış ya da
  LoadOnDemand olduğu için girişte doğal olarak yok. Sadece sayı olarak
  raporlanır; detay için `/spearitycheck` yaz.
- **Beklenmeyen eksikler**: yeni kırılma. Temiz çalıştırmada tek satır
  `Beklenmeyen eksik yok` yazar.

Bu yüzden addonu **silme, sakla**. Yeni bir WoW patch'i çıktığında girip
bakman yeterli: tek satır yeşilse uyumluluk tamam, kırmızı liste varsa
tam olarak neyin kaldırıldığını gösterir. Kapsam 121 global.

Kodda API taşıması yaptığında `Check.lua` içindeki `KNOWN_ABSENT` tablosuna
eski global'i ve sebebini eklemeyi unutma — yoksa her girişte yanlış alarm verir.

## Taint düzeltmesi (1.0 içinde)

**Belirti:** `GetAuraDataByIndex(): Auras cannot be accessed when secret while
tainted by 'Spearity'` — hata Blizzard'ın `Blizzard_MawBuffs.lua` dosyasında
görünüyor, objective tracker güncellenirken tetikleniyor.

**Kaynak:** `Core/EventHandlers.lua`, `OnChestOfMassiveGainsOpened()` içindeki
`AuraUtil.ForEachAura` çağrısı. O fonksiyon tüm aura listesini Blizzard'ın
**paylaşılan** aura yardımcı katmanından geçiriyor; addon bir kez çağırdığında
o katman oturum boyunca "Spearity tarafından kirlenmiş" sayılıyor. Patch 12.0'ın
secret-value kuralları gereği Blizzard'ın kendi aura okumaları da o noktadan
sonra reddediliyor. Hata Spearity'nin kodunda görünmüyor, ama sebebi o.

**Çözüm:** Tek bir buff sorgulandığı için liste taramasına hiç gerek yoktu.
`C_UnitAuras.GetPlayerAuraBySpellID(407063)` ile doğrudan tek-spell sorgusu
yapılıyor — paylaşılan yola dokunmuyor. API yoksa ya da sorgu reddedilirse
deneme sayılmıyor (istatistiklerin şişmemesi için orijinalin muhafazakâr
davranışı korundu), sebebi debug moduna yazılıyor.

Kodda artık hiç `AuraUtil` kullanımı yok.

**Not:** `Collections.lua` içindeki `C_PetJournal.SetFilterChecked` /
`SetAllPetTypesChecked` çağrıları da Pet Journal filtrelerini addon tarafından
değiştirdiği için Collections arayüzünü kirletir. Bu upstream davranışı ve
evcil hayvan taraması ona bağlı — kaldırmak tespiti bozar. Şimdilik dokunmadım.

## Düzeltme: C_CombatLog.GetCurrentEventInfo diye bir API yok

Daha önce `CombatLogGetCurrentEventInfo`'yu (12.0'da kaldırıldı)
`C_CombatLog.GetCurrentEventInfo`'ya bağlamıştım. **O da bu client'ta yok** —
`C_CombatLog` tablosu var ama böyle bir üyesi yok. Yanlış bir API adına
geçmişim; teşhis addonu yakaladı.

Doğru çözüm taşımak değil, silmekti: `R:OnCombat` upstream'de komple yorum
satırında ve `COMBAT_LOG_EVENT_UNFILTERED` hiç kaydedilmiyor. Yani o upvalue
ölü koddu. `Core.lua` ve `Core/EventHandlers.lua`'dan kaldırıldı, yerine
durumu açıklayan bir not bırakıldı. Hiçbir davranış değişmedi.

## 7.0-öncesi dal seçicileri (yanlış alarm değil, kasıtlı tasarım)

Teşhis addonu şunları eksik gösteriyordu; hepsi upstream'in "eski istemci mi?"
kontrolü olarak kullandığı fonksiyonlar ve nil olmaları **beklenen**:

| Eksik global | Neden zararsız |
|---|---|
| `C_MountJournal.GetMountInfo` | `if ... ~= nil` dal seçicisi; nil → modern `GetMountInfoByID` dalı çalışır |
| `C_MountJournal.GetMountInfoExtra` | O dalın içinde, hiç çağrılmıyor |
| `C_PetJournal.SetFlagFilter` | Dal seçicisi; nil → `SetFilterChecked` dalı çalışır |
| `C_PetJournal.AddAllPetTypesFilter` | O dalın içinde, hiç çağrılmıyor |
| `C_PetJournal.AddAllPetSourcesFilter` | O dalın içinde, hiç çağrılmıyor |
| `LE_PET_JOURNAL_FLAG_*` | O dalın içinde, ayrıca guard'lı |
| `Enum.PetJournalFilter` | `LE_PET_JOURNAL_FILTER_*` için yedek; o sabitler mevcut |

Bunlar `KNOWN_ABSENT` tablosuna sebepleriyle eklendi. Teşhis addonu artık
temiz çalışmalı: 150 global, 11 bilinen eksik, 0 beklenmeyen.

## CurseForge projesi

Proje oluşturuldu: ID **1676041**. `## X-Curse-Project-ID: 1676041` satırı
`Spearity.toc`'a eklendi — addon yöneticileri (CurseForge uygulaması, WowUp)
güncellemeyi bu ID ile buluyor. Yeni sürüm yüklerken TOC'taki `## Version`
alanını artırmayı unutma.

## 1.1 — The Coiled Isle (12.1.0)

Upstream Rarity'nin `master` branch'inde de Coiled Isle verisi **hiç yoktu**
(13 Midnight mount, `COILED_ISLE` sabiti bile tanımsız). Son upstream sürümü
Ocak 2026, bölge ise 11 Ağustos 2026'da açıldı. Bu yüzden veri sıfırdan yazıldı.

Veri kaynağı: Wowhead bölge kısıtlı ve JS ile render oluyor, wago.tools ve wiki
API'si robots.txt ile kapalı, bu mount'ların wiki sayfası da henüz yok. Bu yüzden
her ID **oyun içi client'tan** toplandı (`SpearityScout`).

Eklenenler:

- `COILED_ISLE = 2512` — oyunda doğrulandı (parent map 2537 Quel'Thalas).
  Wiki'nin verdiği 16365 UiMapID değil, AreaID.
- **Topaz Skyfang** — itemId 276549, spellId 1299961, ada rare'lerinden
- **Ruby Writhe** — itemId 276803, spellId 1300779, ada rare'lerinden
- **Vibrant Venomfang** (pet) — itemId 276234, creatureId 267689,
  konteyner: Wriggling Venom-Soaked Satchel (277137), USE metodu
- 3 enUS locale girdisi

### Bilinen eksikler

1. **Rare NPC listesi tamamlanmadı.** İki mount da `npcs` listesinde şu an
   yalnızca Venom Lancer Ori'kassi (255927) taşıyor. Buranın rare'leri Curse
   Surge noktaları arasında dönüşümlü doğduğu için tek seferde hepsi görülemiyor.
   `/scout rares` biriktirdikçe listeye eklenmeli — aksi halde deneme sayacı
   gerçek farmı yansıtmaz.
2. **Vibrant Venomfang'da `spellId` yok.** Kafesli item'ın açığa çıkardığı tek
   büyü, her kafesli pet'in paylaştığı genel "Learning" (55884); türün summon
   büyüsü ise pet toplanmadan okunamıyor. Tespit `creatureId` ile çalıştığı için
   işlevsel sorun yok, ama `/spearity validate` bu tek girdiyi hatalı sayar.
   Pet toplandığında `/scout petspell 5092` gerçek ID'yi verir.
3. `chance` değerleri tahmin — dosyadaki diğer girdilerin konvansiyonu izlendi
   (bölge rare mount'ları 100, konteyner pet'leri 20).

### Takip edilmeyenler (kasıtlı)

Coiled Isle'ın diğer koleksiyon parçaları vendor / achievement / quest / yabani
pet kaynaklı. Rarity yalnızca rastgele düşenleri takip eder, o yüzden bunlar
dışarıda: Sea-Dwelling Isle Serpent, Violet-Backed Skyfang, Indigo Coiled Horror,
Emerald Skyfang, Auriferous Venomfang; Snek'zali, Zesty, Zan, Three-Eyed Fish ve
bölgenin 7 yabani pet'i.

### Rare NPC listesi — nasıl tamamlanır

Spearity denemeyi **kill'de değil, cesetten loot geldiğinde** sayar
(`Core.lua`, `LOOT_READY` → loot kaynağının GUID'i → `npcs_to_items[npcID]`).
Aradaki `IsAttemptAllowed` kapısı yalnızca sınıf/dungeon/covenant bakar, bu
girdilerde hiçbiri yok. Yani tek koşul: öldürülen rare'ın NPC ID'si `npcs`
listesinde olmalı.

`SpearityScout` bu yüzden `LOOT_READY`'yi dinleyip lootlanan her NPC'yi
kaydeder. `/scout looted` çıktısı her NPC'yi `[TRACKED]` / `[ NOT ]` diye
işaretler ve doğrudan yapıştırılabilir bir blok basar.

Doğrulanmış Coiled Isle rare'leri:

| npcID | İsim | Kaynak |
|---|---|---|
| 255927 | Venom Lancer Ori'kassi | vignette |
| 265237 | Lockjaw | loot (oyunda doğrulandı) |

Liste hâlâ eksik — bölgenin rare'leri Curse Surge noktaları arasında dönüşümlü
doğuyor. Farmladıkça `/scout looted` çıktısındaki yeni NPC'ler iki mount
girdisine de eklenmeli.

### Uyarı: achievement assetID'leri creature ID DEĞİL

"Coiled to Strike" (achievement 63358) adanın 12 rare'ini kriter olarak
listeler ve hangi rare'lerin var olduğu konusunda güvenilir kaynaktır. Ancak
kriterlerin `assetID` alanı creature ID taşımıyor:

| Rare | assetID | Gerçek creature ID |
|---|---|---|
| Lockjaw | 96456 | 265237 |
| Kari'zah the Forgotten | 97122 | 268090 |

Bu numaralar `npcs` listesine yapıştırılırsa takip **sessizce hiç çalışmaz**.
ID'ler yalnızca oyundan gelebilir: haritadaki vignette, mouseover, hedefleme
veya loot olayı. `/scout coiled` bu eşlemenin ilerlemesini gösterir.

Adanın 12 rare'i: Farthik the Plunderer, Siltmouth, Kari'zah the Forgotten,
Lockjaw, Hisstara, Szarith the Fanged, Garsecg, Nar'zira, Coin-Eye Skully,
Big Mon, Sss'alik, Destra. Ayrıca Venom Lancer Ori'kassi bu achievement'ta
yok ama adada görüldü (255927).

Not: "Prey: Coiled Nightmares" (63415) kriterleri 268643-268646 aralığında ve
gerçek creature ID'lerine benziyor, ama doğrulanmadı — Prey rare'leri ayrı bir
sistem ve bu mount'ları düşürüp düşürmedikleri belirsiz.

### Rare ekleme aracı

`tools/add-coiled-rares.py` — `/scout coiled` çıktısındaki `PASTE THIS` bloğunu
doğrudan alır, iki mount girdisinin `npcs` listelerine ekler, zaten var olanları
atlar, atomik yazar:

```
python3 tools/add-coiled-rares.py "268049, -- Siltmouth"
# veya blogu stdin'den ver:
python3 tools/add-coiled-rares.py < paste.txt
```

Yalnızca Ori'kassi (255927) içeren listelere dokunur, böylece diğer bölgelerin
`npcs` listeleri etkilenmez. `tools/` klasörü pakete girmez.

Doğrulanmış Coiled Isle rare ID'leri (7/13):
255927 Ori'kassi, 265237 Lockjaw, 268090 Kari'zah the Forgotten,
264854 Farthik the Plunderer, 258920 Nar'zira, 261142 Destra, 268049 Siltmouth.

Eksik: Hisstara, Szarith the Fanged, Garsecg, Coin-Eye Skully, Big Mon, Sss'alik.

### 1.1 son durum

Mount'lar (`Topaz Skyfang`, `Ruby Writhe`) — **12 ada rare'inin tamamı** + Ori'kassi,
yani 13 NPC: 255927 Ori'kassi, 256631 Big Mon, 257906 Coin-Eye Skully,
258916 Garsecg, 258920 Nar'zira, 261109 Sss'alik, 261142 Destra,
263456 Szarith the Fanged, 264854 Farthik the Plunderer, 265237 Lockjaw,
265262 Hisstara, 268049 Siltmouth, 268090 Kari'zah the Forgotten.

Pet'ler:
- `Vibrant Venomfang` — itemId 276234, creatureId 267689, konteyner 277137 (USE)
- `Lil' Mon` — itemId 280540, creatureId 271772, Big Mon'dan (256631, NPC)

İkisinde de `spellId` yok; sebebi yukarıda. `/spearity validate` bu iki girdiyi
eksik sayar, tespit `creatureId` ile çalıştığı için işlevsel sorun değil.

### Eklenmeyen: Poison Dart Frog

speciesID 5133, creatureId 271106, itemId 280178. Kaynağı
"Treasure: Unfortunate Scout's Satchel" — bu bir dünya treasure objesi, çantaya
giren bir konteyner item'ı değil (deep taramada item olarak hiç görünmedi).
Rarity'nin `USE` metodu çantadaki konteyner itemlarını bekliyor, dolayısıyla
güvenilir bir tespit yolu yok. Bilinçli olarak dışarıda bırakıldı.

### Elle girilen ID'ler nasıl doğrulanır

`/scout coiled` isim üzerinden çalışır, dolayısıyla yalnızca bu client'ın
**gördüğü** rare'ler hakkında konuşabilir. Elle yazılmış bir ID'yi doğrulamaz —
`[ NO ID ]` "takip edilmiyor" değil, "bu ismi hiç görmedim" demektir.

`/scout verify` ters yönden çalışır: Spearity'nin gerçekten kullandığı npcID'leri
alır ve her biri için oyunun ne bildiğini söyler.

- `[OK]` — oyunda görüldü ve adı Coiled Isle rare listesinde
- `[?]` — henüz görülmedi, ID doğrulanmamış (yanlış demek değil)
- `[!!]` — görüldü ama adı bu listede değil, muhtemelen yanlış ID

Elle girilen 4 ID (265262 Hisstara, 263456 Szarith the Fanged, 258916 Garsecg,
261109 Sss'alik) **Wowhead'den alındı ve doğrulandı**; ayrıca oyundan toplanan
9 ID de Wowhead'e karşı çapraz kontrol edildi. Yani liste iki bağımsız kaynakla
teyitli. `/scout verify` bu dördünü `[?]` gösterecek — bu yalnızca "bu client
onları henüz görmedi" demek, hata değil.
