- move sources from individual tables to a single table with searchable format

- implemented 'group by source' and most source-related filters in items.php
note: some fields are not yet set and searches against those will yield no usable result

- fixed js-error; always expecting array characters in g_user
- fixed rep gain on first login, when using external auth
- fixed wrong lootIds in ?_objects, where the field size was too small
This commit is contained in:
Sarjuuk 2014-09-02 23:35:20 +02:00
parent 5f09b7e5c5
commit 13e45827e4
20 changed files with 37622 additions and 198 deletions

View file

@ -194,7 +194,7 @@ define('CUSTOM_HAS_VIDEO', 0x04000000);
define('CUSTOM_DISABLED', 0x08000000);
define('CUSTOM_SERVERSIDE', 0x10000000);
define('CUSTOM_UNAVAILABLE', 0x20000000);
define('CUSTOM_EXCLUDE_FOR_LISTVIEW', 0x40000000); // will not show up in search or on listPage (override for staff)
define('CUSTOM_EXCLUDE_FOR_LISTVIEW', 0x40000000); // will not show up in search or on listPage (override for staff)
// Custom Flags (per type)
define('SPELL_CU_TALENT', 0x0001); // passive talent
@ -223,6 +223,9 @@ define('NPC_CU_INSTANCE_BOSS', 0x01);
define('NPC_CU_DIFFICULTY_DUMMY', 0x02);
define('NPC_CU_DUNGEON_ENCOUNTER', 0x04);
define('ITEM_CU_OT_ITEMLOOT', 0x01); // there are no sourceTypes for these two cases
define('ITEM_CU_OT_OBJECTLOOT', 0x02);
// as seen in wFlags
define('QUEST_CU_REPEATABLE', 0x01);
define('QUEST_CU_DAILY', 0x02);

View file

@ -33,10 +33,10 @@ class Loot
LOOT_MILLING, // item
LOOT_CREATURE, // npc
LOOT_PICKPOCKET, // npc
LOOT_SKINNING, // npc (see its flags for mining, herbing or actual skinning)
LOOT_SKINNING, // npc (see its flags for mining, herbing, salvaging or actual skinning)
LOOT_FISHING, // zone
LOOT_GAMEOBJECT, // object
LOOT_MAIL, // quest || achievement
LOOT_GAMEOBJECT, // object (see its lockType for mining, herbing, fishing or generic looting)
LOOT_MAIL, // quest
LOOT_SPELL // spell
);
@ -343,8 +343,7 @@ class Loot
['object', [], '$LANG.tab_minedfrom', 'mined-from-object', [], [], []],
['object', [], '$LANG.tab_gatheredfrom', 'gathered-from-object', [], [], []],
['object', [], '$LANG.tab_fishedin', 'fished-in-object', [], [], []],
['spell', [], '$LANG.tab_createdby', 'created-by', [], [], []],
['achievement', [], '$LANG.tab_rewardfrom', 'reward-from-achievemnt', [], [], []]
['spell', [], '$LANG.tab_createdby', 'created-by', [], [], []]
);
$refResults = [];
$chanceMods = [];
@ -520,12 +519,6 @@ class Loot
foreach ($srcObj->iterate() as $_)
$tabsFinal[10][1][] = array_merge($srcData[$srcObj->id], empty($result[$srcObj->id]) ? ['percent' => -1] : $result[$srcObj->id]);
}
/*
todo: search for achievements here
$tabsFinal[17]
*/
break;
case LOOT_SPELL:
$conditions = ['OR', ['effect1CreateItemId', $this->entry], ['effect2CreateItemId', $this->entry], ['effect3CreateItemId', $this->entry]];

View file

@ -393,6 +393,22 @@ abstract class BaseType
}
}
/* source More .. keys seen used
'n': name [always set]
't': type [always set]
'ti': typeId [always set]
'bd': BossDrop [0; 1] [Creature / GO]
'dd': DungeonDifficulty [-2: DungeonHC; -1: DungeonNM; 1: Raid10NM; 2:Raid25NM; 3:Raid10HM; 4: Raid25HM] [Creature / GO]
'q': cssQuality [Items]
'z': zone [set when all happens in here]
'p': PvP [pvpSourceId]
's': TYPE_TITLE: side; TYPE_SPELL: skillId (yeah, double use. Ain't life just grand)
'c': category [Spells / Quests]
'c2': subCat [Quests]
'icon': iconString
*/
public function getSourceData() {}
// should return data required to display a listview of any kind
// this is a rudimentary example, that will not suffice for most Types
abstract public function getListviewData();
@ -689,7 +705,10 @@ abstract class Filter
foreach (array_merge($this->fiData['c'], $this->fiData['v'], $override) as $k => $v)
{
if (isset($addCr[$k]))
{
$v = $v ? array_merge((array)$v, (array)$addCr[$k]) : $addCr[$k];
unset($addCr[$k]);
}
if (is_array($v) && !empty($v))
$_[$k] = $k.'='.implode(':', $v);
@ -697,6 +716,14 @@ abstract class Filter
$_[$k] = $k.'='.$v;
}
// no criteria were set, so no merge occured .. append
if ($addCr)
{
$_['cr'] = 'cr='.$addCr['cr'];
$_['crs'] = 'crs='.$addCr['crs'];
$_['crv'] = 'crv='.$addCr['crv'];
}
return implode(';', $_);
}

View file

@ -216,6 +216,25 @@ class CreatureList extends BaseType
return $data;
}
public function getSourceData()
{
$data = [];
foreach ($this->iterate() as $__)
{
$data[$this->id] = array(
'n' => $this->getField('name', true),
't' => TYPE_NPC,
'ti' => $this->id,
// 'bd' => (int)($this->curTpl['cuFlags'] & NPC_CU_INSTANCE_BOSS || ($this->curTpl['typeFlags'] & 0x4 && $this->curTpl['rank']))
// 'z' where am i spawned
// 'dd' DungeonDifficulty requires 'z'
);
}
return $data;
}
public function addRewardsToJScript(&$refs) { }
}

View file

@ -124,6 +124,24 @@ class GameObjectList extends BaseType
return $data;
}
public function getSourceData()
{
$data = [];
foreach ($this->iterate() as $__)
{
$data[$this->id] = array(
'n' => $this->getField('name', true),
't' => TYPE_OBJECT,
'ti' => $this->id
// 'bd' => bossdrop
// 'dd' => dungeondifficulty
);
}
return $data;
}
}

View file

@ -13,6 +13,8 @@ class ItemList extends BaseType
public $json = [];
public $itemMods = [];
public $sources = [];
public $sourceMore = [];
public $rndEnchIds = [];
public $subItems = [];
@ -25,7 +27,8 @@ class ItemList extends BaseType
protected $queryOpts = array(
'is' => ['j' => ['?_item_stats AS `is` ON `is`.`id` = `i`.`id`', true]],
's' => ['j' => ['?_spell AS `s` ON s.effect1CreateItemId = i.id', true], 'g' => 'i.id'],
'i' => [['is'], 'o' => 'i.quality DESC, i.itemLevel DESC']
'i' => [['is', 'src'], 'o' => 'i.quality DESC, i.itemLevel DESC'],
'src' => ['j' => ['?_source src ON type = 3 AND typeId = i.id', true], 's' => ', moreType, moreTypeId, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10, src11, src12, src13, src14, src15, src16, src17, src18, src19, src20, src21, src22, src23, src24']
);
public function __construct($conditions = [], $miscData = null)
@ -52,6 +55,18 @@ class ItemList extends BaseType
$_ = &$_curTpl['requiredRace'];
if ($_ < 0 || ($_ & RACE_MASK_ALL) == RACE_MASK_ALL)
$_ = 0;
// sources
if ($_curTpl['moreType'] && $_curTpl['moreTypeId'])
$this->sourceMore[$_curTpl['moreType']][] = $_curTpl['moreTypeId'];
for ($i = 1; $i < 25; $i++)
{
if ($_ = $_curTpl['src'.$i])
$this->sources[$this->id][$i][] = $_;
unset($_curTpl['src'.$i]);
}
}
}
@ -225,6 +240,8 @@ class ItemList extends BaseType
* ITEMINFO_MODEL (0x20): sameModelAs-Tab
*/
$data = [];
// random item is random
if ($addInfoMask & ITEMINFO_SUBITEMS)
$this->initSubItems();
@ -232,7 +249,11 @@ class ItemList extends BaseType
if ($addInfoMask & ITEMINFO_JSON)
$this->extendJsonStats();
$data = [];
// gather sourceMore data
if (!($addInfoMask & ITEMINFO_MODEL)) // probably others too
foreach ($this->sourceMore as $type => $ids)
$this->sourceMore[$type] = (new Util::$typeClasses[$type](array(['id', $ids], CFG_SQL_LIMIT_NONE)))->getSourceData();
foreach ($this->iterate() as $__)
{
foreach ($this->json[$this->id] as $k => $v)
@ -354,10 +375,16 @@ class ItemList extends BaseType
if ($addInfoMask & ITEMINFO_MODEL)
if ($_ = $this->getField('displayId'))
$data[$this->id]['displayid'] = $_;
if (!empty($this->sources[$this->id]))
{
$data[$this->id]['source'] = array_keys($this->sources[$this->id]);
if ($this->curTpl['moreType'] && $this->curTpl['moreTypeId'] && !empty($this->sourceMore[$this->curTpl['moreType']][$this->curTpl['moreTypeId']]))
$data[$this->id]['sourcemore'] = [$this->sourceMore[$this->curTpl['moreType']][$this->curTpl['moreTypeId']]];
}
}
/* even more complicated crap
"source":[5],"sourcemore":[{"n":"Commander Oxheart","t":1,"ti":64606,"z":5842}],
modelviewer {type:X, displayid:Y, slot:z} .. not sure, when to set
*/
@ -1182,6 +1209,25 @@ class ItemList extends BaseType
return $onUseStats;
}
public function getSourceData()
{
$data = [];
foreach ($this->iterate() as $__)
{
$data[$this->id] = array(
'n' => $this->getField('name', true),
't' => TYPE_ITEM,
'ti' => $this->id,
'q' => $this->curTpl['quality'],
// 'p' => PvP [NYI]
'icon' => $this->curTpl['iconString']
);
}
return $data;
}
private function canTeachSpell()
{
// 483: learn recipe; 55884: learn mount/pet
@ -1467,6 +1513,7 @@ class ItemListFilter extends Filter
private $ubFilter = []; // usable-by - limit weapon/armor selection per CharClass - itemClass => available itemsubclasses
private $extCostQuery = 'SELECT item FROM npc_vendor nv JOIN ?_itemextendedcost iec ON iec.id = nv.extendedCost WHERE %s UNION
SELECT item FROM game_event_npc_vendor genv JOIN ?_itemextendedcost iec ON iec.id = genv.extendedCost WHERE %1$s';
private $otFields = [18 => 4, 68 => 15, 69 => 16, 70 => 17, 72 => 2, 73 => 19, 75 => 21, 76 => 23, 88 => 20, 92 => 5, 93 => 3, 143 => 18, 171 => 8, 172 => 12];
public $extraOpts = []; // score for statWeights
public $wtCnd = [];
@ -1485,7 +1532,7 @@ class ItemListFilter extends Filter
8 => [10656, 10658, 10660 ],
9 => -1,
10 => [26798, 26801, 26797 ],
11 => [ 9788, 9787, 17041, 17040, 17039, 20219, 20222, 10656, 10658, 10660, 26798, 26801, 26797], // i know, i know .. lazy as fuck
11 => [ 9788, 9787, 17041, 17040, 17039, 20219, 20222, 10656, 10658, 10660, 26798, 26801, 26797], // i know, i know .. lazy as fuck
12 => false,
13 => -1,
14 => -1,
@ -1509,8 +1556,31 @@ class ItemListFilter extends Filter
31099, 40619, 40620, 40621, 30245, 30246, 30247, 45650, 45651, 45652, 34167, 40634, 40635, 40636, 45653, 45654, 45655, 40637, 40638, 40639, 45656, 45657, 45658,
34170, 34192, 29763, 29764, 29762, 31101, 31103, 31102, 30248, 30249, 30250, 47557, 47558, 47559, 34233, 34234, 34202, 34195, 34209, 40622, 40623, 40624, 34193,
45659, 45660, 45661, 34212, 34351, 34215
),
128 => array( // source
1 => true, // Any
2 => false, // None
3 => 1, // Crafted
4 => 2, // Drop
5 => 3, // PvP
6 => 4, // Quest
7 => 5, // Vendor
9 => 10, // Starter
10 => 11, // Event
11 => 12 // Achievement
),
126 => array( // Zones
4494, 36, 2597, 3358, 45, 331, 3790, 4277, 16, 3524, 3, 3959, 719, 1584, 25, 1583, 2677, 3702, 3522, 4, 3525, 3537, 46, 1941,
2918, 3905, 4024, 2817, 4395, 4378, 148, 393, 1657, 41, 2257, 405, 2557, 65, 4196, 1, 14, 10, 15, 139, 12, 3430, 3820, 361,
357, 3433, 721, 394, 3923, 4416, 2917, 4272, 4820, 4264, 3483, 3562, 267, 495, 4742, 3606, 210, 4812, 1537, 4710, 4080, 3457, 38, 4131,
3836, 3792, 2100, 2717, 493, 215, 3518, 3698, 3456, 3523, 2367, 2159, 1637, 4813, 4298, 2437, 722, 491, 44, 3429, 3968, 796, 2057, 51,
3607, 3791, 3789, 209, 3520, 3703, 3711, 1377, 3487, 130, 3679, 406, 1519, 4384, 33, 2017, 1477, 4075, 8, 440, 141, 3428, 3519, 3848,
17, 2366, 3840, 3713, 3847, 3775, 4100, 1581, 3557, 3845, 4500, 4809, 47, 3849, 4265, 4493, 4228, 3698, 4406, 3714, 3717, 3715, 717, 67,
3716, 457, 4415, 400, 1638, 1216, 85, 4723, 4722, 1337, 4273, 490, 1497, 206, 1196, 4603, 718, 3277, 28, 40, 11, 4197, 618, 3521,
3805, 66, 1176, 1977
)
);
// cr => [type, field, misc, extraCol]
protected $genericFilter = array( // misc (bool): _NUMERIC => useFloat; _STRING => localized; _FLAG => match Value; _BOOLEAN => stringSet
9 => [FILTER_CR_FLAG, 'flags', ITEM_FLAG_CONJURED ], // conjureditem
@ -1610,6 +1680,8 @@ class ItemListFilter extends Filter
91 => [FILTER_CR_ENUM, 'totemCategory' ], // tool
176 => [FILTER_CR_STAFFFLAG, 'flags' ], // flags
177 => [FILTER_CR_STAFFFLAG, 'flagsExtra' ], // flags2
71 => [FILTER_CR_FLAG, 'cuFlags', ITEM_CU_OT_ITEMLOOT ], // otitemopening
74 => [FILTER_CR_FLAG, 'cuFlags', ITEM_CU_OT_OBJECTLOOT ], // otobjectopening
130 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
113 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
167 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_VIDEO ], // hasvideos
@ -1819,7 +1891,7 @@ class ItemListFilter extends Filter
case 86: // craftedprof [enum]
$_ = @$this->enums[99][$cr[1]]; // recycled enum
if (is_bool($_))
return ['i.source', '1:', $_ ? null : '!'];
return ['src.src1', null, $_ ? '!' : null];
else if (is_int($_))
return ['s.skillLine1', $_];
@ -1838,32 +1910,49 @@ class ItemListFilter extends Filter
/* todo */ return [1];
case 150: // dropsinheroic25 [heroicraid-any]
/* todo */ return [1];
case 68: // otdisenchanting [yn]
/* todo */ return [1];
case 69: // otfishing [yn]
/* todo */ return [1];
case 70: // otherbgathering [yn]
/* todo */ return [1];
case 71: // otitemopening [yn]
/* todo */ return [1];
case 72: // otlooting [yn]
/* todo */ return [1];
case 68: // otdisenchanting [yn]
case 69: // otfishing [yn]
case 70: // otherbgathering [yn]
// case 71: // otitemopening [yn] [implemented via cuFlags]
case 72: // otlooting [yn]
case 73: // otmining [yn]
// case 74: // otobjectopening [yn] [implemented via cuFlags]
case 75: // otpickpocketing [yn]
case 76: // otskinning [yn]
case 88: // otprospecting [yn]
case 93: // otpvp [pvp]
case 143: // otmilling [yn]
/* todo */ return [1];
case 73: // otmining [yn]
/* todo */ return [1];
case 74: // otobjectopening [yn]
/* todo */ return [1];
case 75: // otpickpocketing [yn]
/* todo */ return [1];
case 88: // otprospecting [yn]
/* todo */ return [1];
case 93: // otpvp [pvp]
/* todo */ return [1];
case 171: // otredemption [yn]
/* todo */ return [1];
case 76: // otskinning [yn]
/* todo */ return [1];
case 172: // rewardedbyachievement [yn]
case 92: // soldbyvendor [yn]
if ($this->int2Bool($cr[1]))
return ['src.src'.$this->otFields[$cr[0]], null, $cr[1] ? '!' : null];
break;
case 18: // rewardedbyfactionquest [side]
$field = 'src.src'.$this->otFields[$cr[0]];
switch ($cr[1])
{
case 1: // Yes
return [$field, null, '!'];
case 2: // Alliance
return [$field, 1];
case 3: // Horde
return [$field, 2];
case 4: // Both
return [$field, 3];
case 5: // No
return [$field, null];
}
break;
case 126: // rewardedbyquestin [zone-any]
if (in_array($cr[1], $this->enums[$cr[0]]))
return ['AND', ['src.src4', null, '!'], ['src.moreZoneId', $cr[1]]];
else if ($cr[1] == FILTER_ENUM_ANY)
return ['src.src4', null, '!']; // well, this seems a bit redundant..
break;
case 158: // purchasablewithcurrency [enum]
case 118: // purchasablewithitem [enum]
if (in_array($cr[1], $this->enums[$cr[0]]))
@ -1894,18 +1983,29 @@ class ItemListFilter extends Filter
return ['id', $foo, $cr[1] ? null : '!'];
}
break;
case 18: // rewardedbyfactionquest [side]
/* todo */ return [1];
case 126: // rewardedbyquestin [zone-any]
/* todo */ return [1];
case 172: // rewardedbyachievement [yn]
/* todo */ return [1];
case 92: // soldbyvendor [yn]
/* todo */ return [1];
case 129: // soldbynpc [str-small]
/* todo */ return [1];
if (!$this->isSaneNumeric($cr[2], true))
break;
if ($iIds = DB::Aowow()->selectCol('SELECT item FROM npc_vendor WHERE entry = ?d UNION SELECT item FROM game_event_npc_vendor v JOIN creature c ON c.guid = v.guid WHERE c.id = ?d', $cr[2], $cr[2]))
return ['i.id', $iIds];
else
return [0];
case 90: // avgbuyout [op] [int]
/* todo */ return [1];
if (!DB::isConnectable(DB_CHARACTERS))
return [1];
if (!$this->isSaneNumeric($cr[2]) || !$this->int2Op($cr[1]))
break;
/* no no no .. for each realm!
// todo (med): get the avgbuyout into the listview
if ($_ = DB::Characters()->select('SELECT ii.itemEntry AS ARRAY_KEY, AVG(ah.buyoutprice / ii.count) AS buyout FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid GROUP BY ii.itemEntry HAVING avgbuyout '.$cr[1].' ?f', $c[1]))
return ['i.id', array_keys($_)];
else
return [0];
*/
return [0];
case 65: // avgmoney [op] [int]
if (!$this->isSaneNumeric($cr[2]) || !$this->int2Op($cr[1]))
break;
@ -1921,7 +2021,7 @@ class ItemListFilter extends Filter
case 163: // disenchantsinto [disenchanting]
if (!$this->isSaneNumeric($cr[1]))
break;
// 35
/* todo */ return [1];
case 85: // objectivequest [side]
/* todo */ return [1];
@ -1965,6 +2065,18 @@ class ItemListFilter extends Filter
return ['startQuest', 0];
}
break;
case 128: // source [enum]
$_ = @$this->enums[$cr[0]][$cr[1]];
if ($_ !== null)
{
if (is_int($_)) // specific
return ['src.src'.$_, null, '!'];
else if ($_) // any
return ['OR', ['src.src1', null, '!'], ['src.src2', null, '!'], ['src.src3', null, '!'], ['src.src4', null, '!'], ['src.src5', null, '!'], ['src.src8', null, '!']];
else if (!$_) // none
return ['AND', ['src.src1', null], ['src.src2', null], ['src.src3', null], ['src.src4', null], ['src.src5', null], ['src.src8', null]];
}
break;
}
unset($cr);

View file

@ -50,7 +50,11 @@ class SpellList extends BaseType
private $interactive = false;
private $charLevel = MAX_LEVEL;
protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_spell s';
protected $queryBase = 'SELECT s.*, id AS ARRAY_KEY FROM ?_spell s';
protected $queryOpts = array(
's' => [['src']], // 6: TYPE_SPELL
'src' => ['j' => ['?_source src ON type = 6 AND typeId = s.id', true], 's' => ', src1, src2, src3, src4, src5, src6, src7, src8, src9, src10, src11, src12, src13, src14, src15, src16, src17, src18, src19, src20, src21, src22, src23, src24']
);
public function __construct($conditions = [])
{
@ -80,15 +84,12 @@ class SpellList extends BaseType
$this->ranks[$this->id] = $this->getField('rank', true);
// sources
if (!empty($_curTpl['source']))
for ($i = 1; $i < 25; $i++)
{
$sources = explode(' ', $_curTpl['source']);
foreach ($sources as $src)
{
$src = explode(':', $src);
if ($src[0] != -3) // todo (high): sourcemore - implement after items
$this->sources[$this->id][$src[0]][] = $src[1];
}
if ($_ = $_curTpl['src'.$i])
$this->sources[$this->id][$i][] = $_;
unset($_curTpl['src'.$i]);
}
// set full masks to 0
@ -1695,7 +1696,7 @@ Lasts 5 min. $?$gte($pl,68)[][Cannot be used on items level 138 and higher.]
);
// Sources
if (!empty($this->sources[$this->id]) && $s = $this->sources[$this->id])
if (!empty($this->sources[$this->id]) && ($s = $this->sources[$this->id]))
$data[$this->id]['source'] = array_keys($s);
// Proficiencies
@ -1883,6 +1884,24 @@ spells / buffspells = {
return $castingTime;
}
public function getSourceData()
{
$data = [];
foreach ($this->iterate() as $__)
{
$data[$this->id] = array(
'n' => $this->getField('name', true),
't' => TYPE_SPELL,
'ti' => $this->id,
's' => empty($this->curTpl['skillLines']) ? 0 : $this->curTpl['skillLines'][0],
'c' => $this->curTpl['typeCat'],
'icon' => $this->curTpl['iconStringAlt'] ? $this->curTpl['iconStringAlt'] : $this->curTpl['iconString'],
);
}
return $data;
}
}
@ -1943,14 +1962,16 @@ class SpellListFilter extends Filter
break;
return ['OR', ['AND', ['powerType', [1, 6]], ['powerCost', (10 * $cr[2]), $cr[1]]], ['AND', ['powerType', [1, 6], '!'], ['powerCost', $cr[2], $cr[1]]]];
case 9: // Source [enum]
case 9: // source [enum]
$_ = @$this->enums[$cr[0]][$cr[1]];
if ($_ !== null)
{
if (is_bool($_))
return ['source', 0, ($_ ? '!' : null)];
else if (is_int($_))
return ['source', '%'.$_.':%'];
if (is_int($_)) // specific
return ['src.src'.$_, null, '!'];
else if ($_) // any
return ['OR', ['src.src1', null, '!'], ['src.src2', null, '!'], ['src.src4', null, '!'], ['src.src5', null, '!'], ['src.src6', null, '!'], ['src.src7', null, '!'], ['src.src9', null, '!']];
else if (!$_) // none
return ['AND', ['src.src1', null], ['src.src2', null], ['src.src4', null], ['src.src5', null], ['src.src6', null], ['src.src7', null], ['src.src9', null]];
}
break;
case 20: // has Reagents [yn]

View file

@ -13,7 +13,11 @@ class TitleList extends BaseType
public $sources = [];
protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_titles t';
protected $queryBase = 'SELECT t.*, id AS ARRAY_KEY FROM ?_titles t';
protected $queryOpts = array(
't' => [['src']], // 11: TYPE_TITLE
'src' => ['j' => ['?_source src ON type = 11 AND typeId = t.id', true], 's' => ', src3, moreType, moreTypeId']
);
public function __construct($conditions = [])
{
@ -22,19 +26,22 @@ class TitleList extends BaseType
// post processing
foreach ($this->iterate() as $id => &$_curTpl)
{
// preparse sources
if (!empty($_curTpl['source']))
{
$sources = explode(' ', $_curTpl['source']);
foreach ($sources as $src)
{
if (!$src) // rogue whitespace slipped through
continue;
// preparse sources - notice: under this system titles can't have more than one source (or two for achivements), which is enough for standard TC cases but may break custom cases
if ($_curTpl['moreType'] == TYPE_ACHIEVEMENT)
$this->sources[$this->id][12][] = $_curTpl['moreTypeId'];
else if ($_curTpl['moreType'] == TYPE_QUEST)
$this->sources[$this->id][4][] = $_curTpl['moreTypeId'];
else if ($_curTpl['src3'])
$this->sources[$this->id][3][] = $_curTpl['src3'];
$src = explode(':', $src);
$this->sources[$id][$src[0]][] = $src[1];
}
}
// titles display up to two achievements at once
if ($_curTpl['src12Ext'])
$this->sources[$this->id][12][] = $_curTpl['src12Ext'];
unset($_curTpl['src12Ext']);
unset($_curTpl['moreType']);
unset($_curTpl['moreTypeId']);
unset($_curTpl['src3']);
// shorthand for more generic access
foreach (Util::$localeStrings as $i => $str)

View file

@ -292,16 +292,16 @@ class User
);
if ($newId)
Util::gainSiteReputation(SITEREP_ACTION_REGISTER, $newId);
Util::gainSiteReputation($newId, SITEREP_ACTION_REGISTER);
return $newId;
}
private static function createSalt()
{
$algo = '$2a';
$strength = '$09';
$salt = '$'.Util::createHash(22);
$algo = '$2a';
$strength = '$09';
$salt = '$'.Util::createHash(22);
return $algo.$strength.$salt;
}
@ -446,9 +446,7 @@ class User
$gUser['superCommentVotes'] = self::canSupervote();
$gUser['downvoteRep'] = CFG_REP_REQ_DOWNVOTE;
$gUser['upvoteRep'] = CFG_REP_REQ_UPVOTE;
if ($_ = self::getCharacters())
$gUser['characters'] = $_;
$gUser['characters'] = self::getCharacters();
if ($_ = self::getProfiles())
$gUser['profiles'] = $_;

View file

@ -332,7 +332,7 @@ class ItemPage extends genericPage
BUTTON_WOWHEAD => true,
BUTTON_LINKS => ['color' => 'ff'.Util::$rarityColorStings[$this->subject->getField('quality')], 'linkId' => 'item:'.$this->typeId.':0:0:0:0:0:0:0:0'],
BUTTON_VIEW3D => in_array($_slot, $_visSlots) && $_model ? ['displayId' => $this->subject->getField('displayId'), 'slot' => $_slot, 'type' => TYPE_ITEM, 'typeId' => $this->typeId] : false,
BUTTON_COMPARE => $_cu, // bool required
BUTTON_COMPARE => $_cu,
BUTTON_EQUIP => in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]),
BUTTON_UPGRADE => $_cu ? ['class' => $_class, 'slot' => $_slot] : false
);
@ -425,6 +425,23 @@ class ItemPage extends genericPage
}
}
// tab: achievement reward
$acvReward = new AchievementList(array(['ar.item', $this->typeId], ['a.itemExtra', $this->typeId], 'OR'));
if (!$acvReward->error)
{
$this->extendGlobalData($acvReward->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
$this->lvTabs[] = array(
'file' => 'achievement',
'data' => $acvReward->getListviewData(),
'params' => [
'name' => '$LANG.tab_rewardfrom',
'id' => 'reward-from-achievement',
'visibleCols' => "$['category']"
]
);
}
// tabs: this item contains..
$sourceFor = array(
[LOOT_ITEM, $this->subject->id, '$LANG.tab_contains', 'contains', ['Listview.extraCols.percent'], [] , []],
@ -467,7 +484,7 @@ class ItemPage extends genericPage
}
}
if ($reqIds = array_keys($reqQuest)) // apply quest-conditions as back-reference
if ($reqIds = array_keys($reqQuest)) // apply quest-conditions as back-reference
{
$conditions = array(
'OR',
@ -494,7 +511,7 @@ class ItemPage extends genericPage
// tab: container can contain
if ($this->subject->getField('slots') > 0)
{
$contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 1, '<'], 0));
$contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 1, '<'], CFG_SQL_LIMIT_NONE));
if (!$contains->error)
{
$this->extendGlobalData($contains->getJSGlobals(GLOBALINFO_SELF));
@ -518,7 +535,7 @@ class ItemPage extends genericPage
// tab: can be contained in (except keys)
else if ($_bagFamily != 0x0100)
{
$contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 0, '>'], 0));
$contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 0, '>'], CFG_SQL_LIMIT_NONE));
if (!$contains->error)
{
$this->extendGlobalData($contains->getJSGlobals(GLOBALINFO_SELF));
@ -547,7 +564,7 @@ class ItemPage extends genericPage
$this->extendGlobalData($criteriaOf->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
$hCols = [];
if (!$criteriaOf->hasSetFields(['rewardIds']))
if (!$criteriaOf->hasSetFields(['reward_loc0']))
$hCols = ['rewards'];
$this->lvTabs[] = array(
@ -769,6 +786,12 @@ class ItemPage extends genericPage
$currency[] = [-$id, $qty];
}
if ($currency)
$this->extendGlobalIds(TYPE_CURRENCY, array_column($currency, 0));
if ($tokens)
$this->extendGlobalIds(TYPE_ITEM, array_column($tokens, 0));
$row['stock'] = $vendors[$k]['stock'];
$row['cost'] = [$this->subject->getField('buyPrice')];
@ -785,7 +808,7 @@ class ItemPage extends genericPage
);
}
if ($currency || $tokens) // fill idx:3 if required
if ($currency || $tokens) // fill idx:3 if required
$row['cost'][] = $currency;
if ($tokens)
@ -834,8 +857,6 @@ class ItemPage extends genericPage
$boughtBy = new ItemList(array(['id', $boughtBy]));
if (!$boughtBy->error)
{
$this->extendGlobalData($boughtBy->getJSGlobals(GLOBALINFO_SELF));
$iCur = new CurrencyList(array(['itemId', $this->typeId]));
$filter = $iCur->error ? [TYPE_ITEM => $this->typeId] : [TYPE_CURRENCY => $iCur->id];
@ -848,6 +869,7 @@ class ItemPage extends genericPage
'extraCols' => "$[Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack'), Listview.extraCols.cost]"
]
);
$this->extendGlobalData($boughtBy->getJSGlobals(GLOBALINFO_ANY));
}
}

View file

@ -210,15 +210,14 @@ class ItemsPage extends GenericPage
);
$groups = [];
$nameSource = [];
$gbField = '';
$grouping = @$this->filter['gb'];
$extraOpts = [];
$maxResults = CFG_SQL_LIMIT_DEFAULT;
switch (@$this->filter['gb'])
switch ($grouping)
{
// slot: (try to limit the lookups by class grouping and intersecting with preselected slots)
// if intersect yields an empty array no lookups will occur
case 3: // todo(med): source .. well .. no, not at the moment .. the database doesn't event have a field for that, so reroute to slots
case 1:
if (isset($this->category[0]) && $this->category[0] == ITEM_CLASS_ARMOR)
$groups = $availableSlots[ITEM_CLASS_ARMOR];
@ -237,7 +236,6 @@ class ItemsPage extends GenericPage
{
$nameSource = Lang::$item['inventoryType'];
$this->forceTabs = true;
$gbField = 'slot';
}
break;
@ -263,23 +261,18 @@ class ItemsPage extends GenericPage
$extraOpts = ['i' => ['o' => ['itemlevel DESC']]];
$nameSource[$l] = Lang::$item['tabOther'];
$this->forceTabs = true;
$gbField = 'itemlevel';
}
break;
case 3:
$groups = array_filter(array_keys(Lang::$game['sources']));
array_walk($groups, function (&$v, $k) {
$v = $v.':';
});
case 3: // source
$groups = [0, 1, 2, 3, 4, 5, 10, 11, 12];
$nameSource = Lang::$game['sources'];
$this->forceTabs = true;
$gbField = 'source';
break;
// none
default:
$grouping = 0;
$groups[0] = null;
}
@ -289,7 +282,20 @@ class ItemsPage extends GenericPage
foreach ($groups as $group)
{
$finalCnd = $gbField ? array_merge($conditions, [[$gbField, abs($group), $group > 0 ? null : '<'], $maxResults]) : $conditions;
switch ($grouping)
{
case 1:
$finalCnd = array_merge($conditions, [['slot', $group], $maxResults]);
break;
case 2:
$finalCnd = array_merge($conditions, [['itemlevel', abs($group), $group > 0 ? null : '<'], $maxResults]);
break;
case 3:
$finalCnd = array_merge($conditions, [$group ? ['src.src'.$group, null, '!'] : ['src.typeId', null], $maxResults]);
break;
default:
$finalCnd = $conditions;
}
$items = new ItemList($finalCnd, ['extraOpts' => array_merge($extraOpts, $this->filterObj->extraOpts)]);
@ -306,7 +312,7 @@ class ItemsPage extends GenericPage
$upg = [];
if ($upgItemData)
{
if ($gbField == 'slot') // match upgradeItem to slot
if ($grouping == 1) // slot: match upgradeItem to slot
{
$upg = array_keys(array_filter($this->filter['upg'], function ($v) use ($group) {
return $v == $group;
@ -318,7 +324,7 @@ class ItemsPage extends GenericPage
if ($upg)
$tab['params']['_upgradeIds'] = '$'.json_encode($upg, JSON_NUMERIC_CHECK);
}
else if ($gbField)
else if ($grouping)
{
$upg = array_keys($this->filter['upg']);
$tab['params']['_upgradeIds'] = '$'.json_encode($upg, JSON_NUMERIC_CHECK);
@ -327,9 +333,21 @@ class ItemsPage extends GenericPage
}
}
if ($gbField)
if ($grouping)
{
$tab['params']['id'] = $group > 0 ? $gbField.'-'.$group : 'other';
switch ($grouping)
{
case 1:
$tab['params']['id'] = 'slot-'.$group;
break;
case 2:
$tab['params']['id'] = $group > 0 ? 'level-'.$group : 'other';
break;
case 3:
$tab['params']['id'] = $group ? 'source-'.$group : 'unknown';
break;
}
$tab['params']['name'] = $nameSource[$group];
$tab['params']['tabs'] = '$tabsGroups';
}
@ -343,39 +361,34 @@ class ItemsPage extends GenericPage
{
$tab['params']['_truncated'] = 1;
$addCr = [];
if ($gbField == 'slot')
{
$note = 'lvnote_viewmoreslot';
$override = ['sl' => $group, 'gb' => ''];
}
else if ($gbField == 'itemlevel')
{
$note = 'lvnote_viewmorelevel';
if ($group > 0)
$override = ['minle' => $group, 'maxle' => $group, 'gb' => ''];
else
$override = ['maxle' => abs($group) - 1, 'gb' => ''];
}
else if ($gbField == 'source')
{
if ($_ = @[null, 3, 4, 5, 6, 7, 8][$group])
{
$note = 'lvnote_viewmoresource';
$addCr = ['cr' => 128, 'crs' => $_, 'crv' => 0];
}
$override = ['gb' => ''];
}
$cls = isset($this->category[0]) ? '='.$this->category[0] : '';
$override = ['gb' => ''];
if ($upg)
$override['upg'] = implode(':', $upg);
$cls = isset($this->category[0]) ? '='.$this->category[0] : '';
$this->filterUrl = $this->filterObj->urlize($override, $addCr);
switch ($grouping)
{
case 1:
$override['sl'] = $group;
$tab['params']['note'] = '$$WH.sprintf(LANG.lvnote_viewmoreslot, \''.$cls.'\', \''.$this->filterObj->urlize($override).'\')';
break;
case 2:
if ($group > 0)
{
$override['minle'] = $group;
$override['maxle'] = $group;
}
else
$override['maxle'] = abs($group) - 1;
if ($note)
$tab['params']['note'] = '$$WH.sprintf(LANG.'.$note.', \''.$cls.'\', \''.$this->filterUrl.'\')';
$tab['params']['note'] = '$$WH.sprintf(LANG.lvnote_viewmorelevel, \''.$cls.'\', \''.$this->filterObj->urlize($override).'\')';
break;
case 3:
if ($_ = [null, 3, 4, 5, 6, 7, 9, 10, 11][$group])
$tab['params']['note'] = '$$WH.sprintf(LANG.lvnote_viewmoresource, \''.$cls.'\', \''.$this->filterObj->urlize($override, ['cr' => 128, 'crs' => $_, 'crv' => 0]).'\')';
break;
}
}
else if ($items->getMatches() > $maxResults)
{
@ -393,7 +406,7 @@ class ItemsPage extends GenericPage
if (!$p)
unset($tab['params'][$k]);
if ($gbField)
if ($grouping)
$tab['params']['hideCount'] = '$1';
$this->lvTabs[] = $tab;
@ -405,7 +418,10 @@ class ItemsPage extends GenericPage
// whoops, we have no data? create emergency content
if (empty($this->lvTabs))
$this->lvTabs[] = ['file' => 'item', 'data' => [], 'params' => []];
{
$this->forceTabs = false;
$this->lvTabs[] = ['file' => 'item', 'data' => [], 'params' => []];
}
// sort for dropdown-menus
asort(Lang::$game['ra']);

View file

@ -1361,7 +1361,7 @@ class SearchPage extends GenericPage
if ($data = $misc->getListviewData())
{
if ($this->searchMask & SEARCH_TYPE_REGULAR)
$this->extendGlobalData($misc->getJSGlobals(GLOBALINFO_SELF));
$this->extendGlobalData($misc->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
if ($this->searchMask & SEARCH_TYPE_OPEN)
foreach ($misc->iterate() as $__)

View file

@ -86,47 +86,40 @@ class TitlePage extends GenericPage
/* Extra Tabs */
/**************/
// tab: sources
if (!empty($this->subject->sources[$this->typeId]))
// tab: quest source
$quests = new QuestList(array(['rewardTitleId', $this->typeId]));
if (!$quests->error)
{
foreach ($this->subject->sources[$this->typeId] as $type => $entries)
{
switch ($type)
{
case 4:
$quests = new QuestList(array(['id', $entries]));
$this->extendGlobalData($quests->getJSGlobals(GLOBALINFO_REWARDS));
$this->extendGlobalData($quests->getJSGlobals(GLOBALINFO_REWARDS));
$this->lvTabs[] = array(
'file' => 'quest',
'data' => $quests->getListviewData(),
'params' => array(
'id' => 'reward-from-quest',
'name' => '$LANG.tab_rewardfrom',
'hiddenCols' => "$['experience', 'money']",
'visibleCols' => "$['category']"
)
);
break;
case 12:
$acvs = new AchievementList(array(['id', $entries]));
$this->extendGlobalData($acvs->getJSGlobals());
$this->lvTabs[] = array(
'file' => 'quest',
'data' => $quests->getListviewData(),
'params' => array(
'id' => 'reward-from-quest',
'name' => '$LANG.tab_rewardfrom',
'hiddenCols' => "$['experience', 'money']",
'visibleCols' => "$['category']"
)
);
}
$this->lvTabs[] = array(
'file' => 'achievement',
'data' => $acvs->getListviewData(),
'params' => array(
'id' => 'reward-from-achievement',
'name' => '$LANG.tab_rewardfrom',
'visibleCols' => "$['category']",
'sort' => "$['reqlevel', 'name']"
)
);
break;
// case 13:
// not displayed
}
}
// tab: achievement source
$acvs = new AchievementList(array(['ar.title_A', $this->typeId], ['ar.title_H', $this->typeId], 'OR'));
if (!$acvs->error)
{
$this->extendGlobalData($acvs->getJSGlobals());
$this->lvTabs[] = array(
'file' => 'achievement',
'data' => $acvs->getListviewData(),
'params' => array(
'id' => 'reward-from-achievement',
'name' => '$LANG.tab_rewardfrom',
'visibleCols' => "$['category']",
'sort' => "$['reqlevel', 'name']"
)
);
}
// tab: criteria of (to be added by TC)

37139
setup/updates/04_sources.sql Normal file

File diff suppressed because one or more lines are too long

View file

@ -490,7 +490,7 @@ var PageTemplate = new function()
menu.push(userPage);
// Settings
var settings = ['settings', LANG.settings, 'https://' + window.location.hostname + '?account', null, {icon: g_staticUrl + '/images/icons/cog.gif', checkedUrl: /account/i}];
var settings = ['settings', LANG.settings, 'http://' + window.location.hostname + '?account', null, {icon: g_staticUrl + '/images/icons/cog.gif', checkedUrl: /account/i}];
menu.push(settings);
// Reputation

View file

@ -1592,7 +1592,18 @@ var g_sources = {
9: 'Talent',
10: 'Startausrüstung',
11: 'Ereignis',
12: 'Erfolg'
12: 'Erfolg',
14: 'Schwarzmarkt',
15: 'Entzaubert',
16: 'Geangelt',
17: 'Gesammelt',
18: 'Gemahlen',
19: 'Abgebaut',
20: 'Sondiert',
21: 'Aus Taschendiebstahl',
22: 'Geborgen',
23: 'Gehäutet',
24: 'In-Game-Store'
};
var g_sources_pvp = {
@ -3415,8 +3426,8 @@ var LANG = {
[10, "Talent"], [8, "Lehrer"], [7, "Händler"], [2, "Nichts"]
],
itemsource: [
[1, "Beliebig"], [3, "Hergestellt"], [4, "Drop"], [5, "PvP"], [6, "Quest"],
[8, "Einlösung"], [7, "Händler"], [2, "Nichts"]
[1, "Beliebig"], [11, "Erfolg"], [3, "Hergestellt"], [4, "Drop"], [10, "Ereignis"],
[5, "PvP"], [6, "Quest"], [9, "Startausrüstung"], [7, "Händler"], [2, "Nichts"]
],
glyphtype: [[ 1, "Erhebliche"], [2, "Geringe"] ],
classs: [

View file

@ -1637,7 +1637,19 @@ var g_sources = {
9: 'Talent',
10: 'Starter',
11: 'Event',
12: 'Achievement'
12: 'Achievement',
// sarjuuk: 13 is string from serverside table, used by titles
14: 'Black Market',
15: 'Disenchanted',
16: 'Fished',
17: 'Gathered',
18: 'Milled',
19: 'Mined',
20: 'Prospected',
21: 'Pickpocketed',
22: 'Salvaged',
23: 'Skinned',
24: 'In-Game Store'
};
var g_sources_pvp = {
@ -3460,8 +3472,8 @@ var LANG = {
[10, "Talent"], [8, "Trainer"], [7, "Vendor"], [2, "None"]
],
itemsource: [
[1, "Any"], [3, "Crafted"], [4, "Drop"], [5, "PvP"], [6, "Quest"],
[8, "Redemption"], [7, "Vendor"], [2, "None"]
[1, "Any"], [11, "Achievement"], [3, "Crafted"], [4, "Drop"], [10, "Event"],
[5, "PvP"], [6, "Quest"], [9, "Starter"], [7, "Vendor"], [2, "None"]
],
glyphtype: [ [1, "Major"], [2, "Minor"] ],
classs: [

View file

@ -1593,7 +1593,18 @@ var g_sources = {
9: 'Talento',
10: 'Habilidad Inicial',
11: 'Evento',
12: 'Logro'
12: 'Logro',
14: 'Mercado negro',
15: 'Desencantado',
16: 'Pescado',
17: 'Recolectado',
18: 'Molido',
19: 'Minado',
20: 'Prospectar',
21: 'Robado',
22: 'Rescatado',
23: 'Despellejado',
24: 'Tienda del juego'
};
var g_sources_pvp = {
@ -3418,8 +3429,8 @@ var LANG = {
[10, "Talento"], [8, "Entrenador"], [7, "Vendedor"], [2, "Ninguno"]
],
itemsource: [
[1, "Cualquiera"], [3, "Creado"], [4, "Encontrado"], [5, "JcJ"], [6, "Misión"],
[8, "Redención"], [7, "Vendedor"], [2, "Ninguno"]
[1, "Cualquiera"], [11, "Logro"], [3, "Creado"], [4, "Encontrado"], [10, "Evento"],
[5, "JcJ"], [6, "Misión"], [9, "Habilidad Inicial"], [7, "Vendedor"], [2, "Ninguno"]
],
glyphtype: [ [1, "Sublime"], [2, "Menor"] ],
classs: [

View file

@ -1581,7 +1581,18 @@ var g_sources = {
9: 'Talent',
10: 'Débutant',
11: 'Événement',
12: 'Haut fait'
12: 'Haut fait',
14: 'Marché Noir',
15: 'Désenchanté',
16: 'Pêché',
17: 'Cueilli',
18: 'Moulu',
19: 'Miné',
20: 'Prospecté',
21: 'Subtilisé (pickpocket)',
22: 'Ferraillé',
23: 'Dépecé',
24: 'Boutique en jeu'
};
var g_sources_pvp = {
@ -3406,8 +3417,8 @@ var LANG = {
[10, "Talent"], [8, "Maître"], [7, "Vendeur"], [2, "Aucun"]
],
itemsource: [
[1, "N'importe quelle"], [3, "Fabriqué"], [4, "Butin"], [5, "JcJ"], [6, "Quête"],
[8, "Échange d'un code"], [7, "Vendeur"], [2, "Aucun"]
[1, "N'importe quelle"], [11, "Haut fait"], [3, "Fabriqué"], [4, "Butin"], [10, "Événement"],
[5, "JcJ"], [6, "Quête"], [9, "Débutant"], [7, "Vendeur"], [2, "Aucun"]
],
glyphtype: [ [1, "Majeur"], [2, "Mineur"] ],
classs: [

View file

@ -1581,7 +1581,18 @@ var g_sources = {
9: 'Талант',
10: 'Начальное заклинание',
11: 'Мероприятие',
12: 'Достижение'
12: 'Достижение',
14: 'Черный Рынок',
15: 'Распылено',
16: 'Вылавливается',
17: 'Собрано',
18: '[Milled]',
19: 'Выкапывается',
20: 'Просеивается',
21: 'Можно украсть',
22: 'Разобрано',
23: 'Собирается при снятии шкуры',
24: 'Внутриигровой магазин'
};
var g_sources_pvp = {
@ -3406,8 +3417,8 @@ var LANG = {
[10, "Талант"], [8, "Тренер"], [7, "Продавец"], [2, "Нет"]
],
itemsource: [
[1, "Все"], [3, "Ремесло"], [4, "Добыча"], [5, "PvP"], [6, "Задание"],
[8, "Рекламная акция"], [7, "Продавец"], [2, "Нет"]
[1, "Все"], [11, "Достижение"], [3, "Ремесло"], [4, "Добыча"], [10, "Мероприятие"],
[5, "PvP"], [6, "Задание"], [9, "Начальное заклинание"], [7, "Продавец"], [2, "Нет"]
],
glyphtype: [ [1, "Большой"], [2, "Малый"] ],
classs: [