Achivements/Criteria

* link back to achievement from achievement_criteria_data
 * closes #466

 * also don't try to resolve continental maps to zoneIds
This commit is contained in:
Sarjuuk 2025-12-15 14:41:56 +01:00
parent ec1b1d3da0
commit fe9fdb455c
8 changed files with 151 additions and 25 deletions

View file

@ -370,8 +370,17 @@ class AchievementBaseResponse extends TemplateResponse implements ICache
$extraData[] = '<a href="?event='.$we->id.'">'.$we->getField('name', true).'</a>';
break;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID:
if ($z = new ZoneList(array(['mapIdBak', $xData['value1']])))
$extraData[] = '<a href="?zone='.$z->id.'">'.$z->getField('name', true).'</a>';
$extraData[] = match((int)$xData['value1'])
{
0 => Lang::maps('EasternKingdoms'),
1 => Lang::maps('Kalimdor'),
530 => Lang::maps('Outland'),
571 => Lang::maps('Northrend'),
default => (function(int $mapId) {
$z = new ZoneList(array(['mapId', $mapId]));
return '<a href="?zone='.$z->id.'">'.$z->getField('name', true).'</a>';
})($xData['value1'])
};
break;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE:
$extraData[] = TitleList::makeLink($xData['value1']);

View file

@ -143,7 +143,7 @@ class ClassBaseResponse extends TemplateResponse implements ICache
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
// Tab: Spells (grouped)
// tab: spells (grouped)
// '$LANG.tab_armorproficiencies',
// '$LANG.tab_weaponskills',
// '$LANG.tab_glyphs',
@ -185,7 +185,7 @@ class ClassBaseResponse extends TemplateResponse implements ICache
), SpellList::$brickFile));
}
// Tab: Items (grouped)
// tab: items (grouped)
$conditions = array(
['requiredClass', 0, '>'],
['requiredClass', $cl->toMask(), '&'],
@ -216,7 +216,7 @@ class ClassBaseResponse extends TemplateResponse implements ICache
), ItemList::$brickFile));
}
// Tab: Quests
// tab: quests
$conditions = array(
['reqClassMask', $cl->toMask(), '&'],
[['reqClassMask', ChrClass::MASK_ALL, '&'], ChrClass::MASK_ALL, '!']
@ -233,7 +233,7 @@ class ClassBaseResponse extends TemplateResponse implements ICache
), QuestList::$brickFile));
}
// Tab: Itemsets
// tab: itemsets
$sets = new ItemsetList(array(['classMask', $cl->toMask(), '&']));
if (!$sets->error)
{
@ -247,7 +247,7 @@ class ClassBaseResponse extends TemplateResponse implements ICache
), ItemsetList::$brickFile));
}
// Tab: Trainer
// tab: trainers
$conditions = array(
['npcflag', NPC_FLAG_TRAINER | NPC_FLAG_CLASS_TRAINER, '&'],
['trainerType', 0], // trains class spells
@ -265,11 +265,33 @@ class ClassBaseResponse extends TemplateResponse implements ICache
), CreatureList::$brickFile));
}
// Tab: Races
// tab: races
$races = new CharRaceList(array(['classMask', $cl->toMask(), '&']));
if (!$races->error)
$this->lvTabs->addListviewTab(new Listview(['data' => $races->getListviewData()], CharRaceList::$brickFile));
// tab: criteria-of
$conditions = array(
'AND',
['ac.type', ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS],
['ac.value1', $this->typeId]
);
if ($extraCrt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` IN (?a) AND `value1` = ?d', [ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE, ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE], $this->typeId))
$conditions = ['OR', $conditions, ['ac.id', $extraCrt]];
$crtOf = new AchievementList($conditions);
if (!$crtOf->error)
{
$this->extendGlobalData($crtOf->getJSGlobals());
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $crtOf->getListviewData(),
'name' => '$LANG.tab_criteriaof',
'id' => 'criteria-of'
), AchievementList::$brickFile));
}
// tab: condition-for
$cnd = new Conditions();
$cnd->getByCondition(Type::CHR_CLASS, $this->typeId)->prepare();

View file

@ -177,6 +177,7 @@ class EventBaseResponse extends TemplateResponse implements ICache
}
// tab: achievements
$exclAcvs = [];
if ($_ = $this->subject->getField('achievementCatOrId'))
{
$condition = $_ > 0 ? [['category', $_]] : [['id', -$_]];
@ -190,6 +191,9 @@ class EventBaseResponse extends TemplateResponse implements ICache
'visibleCols' => ['category']
);
// don't reuse for criteria-of tab
$exclAcvs = array_keys($tabData['data']);
if ($_holidayId && AchievementListFilter::getCriteriaIndex(11, $_holidayId))
$tabData['note'] = sprintf(Util::$filterResultString, '?achievements&filter=cr=11;crs='.$_holidayId.';crv=0');
@ -200,6 +204,26 @@ class EventBaseResponse extends TemplateResponse implements ICache
$itemCnd = [];
if ($_holidayId)
{
// tab: criteria-of
if ($extraCrt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` = ?d AND `value1` = ?d', ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY, $_holidayId))
{
$condition = array(['ac.id', $extraCrt]);
if ($exclAcvs)
$condition[] = ['a.id', $exclAcvs, '!'];
$crtOf = new AchievementList($condition);
if (!$crtOf->error)
{
$this->extendGlobalData($crtOf->getJSGlobals());
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $crtOf->getListviewData(),
'name' => '$LANG.tab_criteriaof',
'id' => 'criteria-of'
), AchievementList::$brickFile));
}
}
$itemCnd = array(
'OR',
['eventId', $this->typeId], // direct requirement on item

View file

@ -738,10 +738,14 @@ class NpcBaseResponse extends TemplateResponse implements ICache
// tab: criteria of [ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE have no data set to check for]
$conditions = array(
'AND',
['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE]],
['ac.value1', $this->typeId]
);
if ($extraCrt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` = ?d AND `value1` = ?d', ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE, $this->typeId))
$conditions = ['OR', $conditions, ['ac.id', $extraCrt]];
$crtOf = new AchievementList($conditions);
if (!$crtOf->error)
{

View file

@ -152,7 +152,7 @@ class RaceBaseResponse extends TemplateResponse implements ICache
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
// Classes
// tab: classes
$classes = new CharClassList(array(['racemask', $ra->toMask(), '&']));
if (!$classes->error)
{
@ -160,7 +160,7 @@ class RaceBaseResponse extends TemplateResponse implements ICache
$this->lvTabs->addListviewTab(new Listview(['data' => $classes->getListviewData()], CharClassList::$brickFile));
}
// Tongues
// tab: languages
$conditions = array(
['typeCat', -11], // proficiencies
['reqRaceMask', $ra->toMask(), '&'] // only languages are race-restricted
@ -178,7 +178,7 @@ class RaceBaseResponse extends TemplateResponse implements ICache
), SpellList::$brickFile));
}
// Racials
// tab: racial-traits
$conditions = array(
['typeCat', -4], // racial traits
['reqRaceMask', $ra->toMask(), '&']
@ -200,7 +200,7 @@ class RaceBaseResponse extends TemplateResponse implements ICache
$this->lvTabs->addListviewTab(new Listview($tabData, SpellList::$brickFile));
}
// Quests
// tab: quests
$conditions = array(
['reqRaceMask', $ra->toMask(), '&'],
[['reqRaceMask', ChrRace::MASK_HORDE, '&'], ChrRace::MASK_HORDE, '!'],
@ -214,7 +214,7 @@ class RaceBaseResponse extends TemplateResponse implements ICache
$this->lvTabs->addListviewTab(new Listview(['data' => $quests->getListviewData()], QuestList::$brickFile));
}
// Mounts
// tab: mounts
// ok, this sucks, but i rather hardcode the trainer, than fetch items by namepart
if (isset(self::MOUNT_VENDORS[$this->typeId]))
{
@ -240,7 +240,7 @@ class RaceBaseResponse extends TemplateResponse implements ICache
}
}
// Sounds
// tab: sounds
if ($vo = DB::Aowow()->selectCol('SELECT `soundId` AS ARRAY_KEY, `gender` FROM ?_races_sounds WHERE `raceId` = ?d', $this->typeId))
{
$sounds = new SoundList(array(['id', array_keys($vo)]));
@ -258,6 +258,28 @@ class RaceBaseResponse extends TemplateResponse implements ICache
}
}
// tab: criteria-of
$conditions = array(
'AND',
['ac.type', ACHIEVEMENT_CRITERIA_TYPE_HK_RACE],
['ac.value1', $this->typeId]
);
if ($extraCrt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` IN (?a) AND `value2` = ?d', [ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE, ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE], $this->typeId))
$conditions = ['OR', $conditions, ['ac.id', $extraCrt]];
$crtOf = new AchievementList($conditions);
if (!$crtOf->error)
{
$this->extendGlobalData($crtOf->getJSGlobals());
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $crtOf->getListviewData(),
'name' => '$LANG.tab_criteriaof',
'id' => 'criteria-of'
), AchievementList::$brickFile));
}
// tab: condition-for
$cnd = new Conditions();
$cnd->getByCondition(Type::CHR_RACE, $this->typeId)->prepare();

View file

@ -625,11 +625,16 @@ class SpellBaseResponse extends TemplateResponse implements ICache
// tab: criteria of
$conditions = array(
'AND',
['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL,
ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL]
],
['ac.value1', $this->typeId]
);
if ($extraCrt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` IN (?a) AND `value1` = ?d', [ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA, ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA], $this->typeId))
$conditions = ['OR', $conditions, ['ac.id', $extraCrt]];
$coAchievemnts = new AchievementList($conditions);
if (!$coAchievemnts->error)
{

View file

@ -137,7 +137,7 @@ class TitleBaseResponse extends TemplateResponse implements ICache
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
// tab: quest source
// tab: reward-from-quest
$quests = new QuestList(array(['rewardTitleId', $this->typeId]));
if (!$quests->error)
{
@ -152,7 +152,7 @@ class TitleBaseResponse extends TemplateResponse implements ICache
), QuestList::$brickFile));
}
// tab: achievement source
// tab: reward-from-achievement
if ($aIds = DB::World()->selectCol('SELECT `ID` FROM achievement_reward WHERE `TitleA` = ?d OR `TitleH` = ?d', $this->typeId, $this->typeId))
{
$acvs = new AchievementList(array(['id', $aIds]));
@ -170,8 +170,8 @@ class TitleBaseResponse extends TemplateResponse implements ICache
}
}
// tab: criteria of
if ($crt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` = 23 AND `value1` = ?d', $this->typeId))
// tab: criteria-of
if ($crt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` = ?d AND `value1` = ?d', ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE, $this->typeId))
{
$acvs = new AchievementList(array(['ac.id', $crt]));
if (!$acvs->error)

View file

@ -569,7 +569,7 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
// tab: Drops
// tab: drops
if (in_array($this->subject->getField('category'), [MAP_TYPE_DUNGEON, MAP_TYPE_RAID]))
{
// Issue 1 - if the bosses drop items that are also sold by vendors moreZoneId will be 0 as vendor location and boss location are likely in conflict with each other
@ -611,7 +611,7 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
$this->lvTabs->addListviewTab(new Listview($tabData, ItemList::$brickFile));
}
// tab: NPCs
// tab: npcs
if ($cSpawns && !$creatureSpawns->error)
{
$tabData = ['data' => $creatureSpawns->getListviewData()];
@ -627,7 +627,7 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
$this->lvTabs->addListviewTab(new Listview($tabData, CreatureList::$brickFile));
}
// tab: Objects
// tab: objects
if ($oSpawns && !$objectSpawns->error)
{
$tabData = ['data' => $objectSpawns->getListviewData()];
@ -659,7 +659,7 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
}
}
// tab: Quests [including data collected by SOM-routine]
// tab: quests [including data collected by SOM-routine]
if ($questsLV)
{
$tabData = ['data' => $questsLV];
@ -679,7 +679,7 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
$this->lvTabs->addListviewTab(new Listview($tabData, QuestList::$brickFile));
}
// tab: item-quest starter
// tab: starts-quest
// select every quest starter, that is a drop
$questStartItem = DB::Aowow()->select(
'SELECT qse.`typeId` AS ARRAY_KEY, `moreType`, `moreTypeId`, `moreZoneId`
@ -705,7 +705,7 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
}
}
// tab: Quest Rewards [ids collected by SOM-routine]
// tab: quest-rewards [ids collected by SOM-routine]
if ($rewardsLV)
{
$rewards = new ItemList(array(['id', array_unique($rewardsLV)]));
@ -728,7 +728,47 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
// tab: achievements
// tab: fished in zone
// tab: criteria-of
$conditions = array('OR',
array(
'AND',
['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA]],
['ac.value1', $this->typeId]
)
);
if ($extraCrt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` = ?d AND `value1` = ?d', ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA, $this->typeId))
$conditions[] = ['ac.id', $extraCrt];
if ($this->subject->getField('category') != MAP_TYPE_ZONE)
{
$conditions[] = array (
'AND',
['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA,
ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA, ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND,
ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP]
],
['ac.value1', $this->subject->getField('mapId')]
);
if ($extraCrt = DB::World()->selectCol('SELECT `criteria_id` FROM achievement_criteria_data WHERE `type` = ?d AND `value1` = ?d', ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID, $this->subject->getField('mapId')))
$conditions[] = ['ac.id', $extraCrt];
}
$crtOf = new AchievementList($conditions);
if (!$crtOf->error)
{
$this->extendGlobalData($crtOf->getJSGlobals());
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $crtOf->getListviewData(),
'name' => '$LANG.tab_criteriaof',
'id' => 'criteria-of'
), AchievementList::$brickFile));
}
// tab: fishing
$fish = new LootByContainer();
if ($fish->getByContainer(Loot::FISHING, [$this->typeId]))
{