<?php

$repack = ""; // "Sunwell", "Jeutie", "Quantum", "CNA" etc.
if (count($argv) > 1)
   $repack = $argv[1];
elseif (getenv("WOWVER") != "") {
   // При запуске из wows-patch.cmd
   preg_match('/^.*\\\\\w+(-\d[\.\w]*)+-(\w+)/i', getenv("BASEDIR"), $capt);
   $repack = @$capt[2];
   if ($repack == "")  exit(11);
}
if (! in_array($repack, array("", "Jeutie", "Sunwell"))) // пока так, но можно расширить список
    exit(12);

$startTime = microtime(true);

require "_trinity.php";
MySTART();

define("FIRST_RUN", $repack=="Jeutie" || MyVAL("SELECT dmg_multiplier FROM creature_template WHERE entry=14338; -- Knot Thimblejack: original value is 5") == 5);

// Список совпадает с номерами, присутствующими в таблице Sunwell БД access_requirement
// Список совпадает с объединением перечислений номеров карт подземелий в TweakCreatureDmgHP()
// Battleground-карты рассматриваются здесь как overworld, а не instances
$InstancedMaps = "33,34,36,43,47,48,70,90,109,129,189,209,229,230,249,269,289,309,329,349,389,409,429,469,509,531,532,533,534,540,542,543,544,545,546,547,548,550,552,553,554,555,556,557,558,560,564,565,568,574,575,576,578,580,585,595,599,600,601,602,603,604,608,615,616,619,624,631,632,649,650,658,668,724";


///////////////////////// HELPER FUNCTIONS

function IsNotRepack($rpname)
{
  return $GLOBALS['repack'] != "" and $GLOBALS['repack'] != $rpname;
}

function PrintHeader($fnname)
{
  global $count; $count = null;
  static $sections = 0;
  if ($sections++ != 0) echo "\n";
  echo ":::::: $fnname()\n";
}

function Logs($format, $arg1=null, $arg2=null, $arg3=null)
{
  global $count, $countTotal;
  if ($arg1 === null)
     $arg1 = $count !== null ? $count : mysql_affected_rows();
  printf(" ■ $format\n", $arg1, $arg2, $arg3);
  $countTotal += @$arg1;
  $count = null;
  // Сбрасывать через unset($count) нельзя, т.к. рвётся связь между глобальной
  // переменной и той, что объявлена через global $count внутри функций
  // Значение null считается за 0 в числовых операциях (no error/warning)
}


function RetrieveArmorLimits()
{
$armorLimits = array();

$res = MyOP("SELECT InventoryType, ItemLevel, MIN(armor) AS MinArmor FROM item_template WHERE InventoryType IN (1,3,5,6,7,8,9,10) AND class=4 AND IF(ItemLevel<40, subclass=3, subclass=4) AND armor>=2 GROUP BY InventoryType, ItemLevel");

while($calc = mysql_fetch_object($res))
  $armorLimits[$calc->InventoryType][$calc->ItemLevel] = $calc->MinArmor;

$res = MyOP("SELECT InventoryType, ItemLevel, MAX(subclass) AS MaxSC, COUNT(subclass) AS BadCount FROM item_template WHERE InventoryType IN (1,3,5,6,7,8,9,10) AND class=4 AND subclass IN (1,2,3,4) GROUP BY InventoryType, ItemLevel");

while($calc = mysql_fetch_object($res))
  if ($calc->ItemLevel < 40 ? $calc->MaxSC < 3 : $calc->MaxSC < 4)
      $armorLimits[$calc->InventoryType][$calc->ItemLevel] = -max($calc->BadCount,1);

$MaxIL = MyVAL("SELECT MAX(ItemLevel) FROM item_template");
$nGroups = 0; $nPonded = 0;
$myCase = "CASE InventoryType";

foreach(array(1,3,5,6,7,8,9,10,20) as $inv) {
  $myCase .= "\nWHEN $inv then CASE ItemLevel";
  for($IL = 1; $IL <= $MaxIL; $IL++) {
    $lim = @$armorLimits[$inv == 20/*Robe*/ ? 5/*Chest*/ : $inv][$IL];
    if ($lim === null)  continue;
    if ($lim >= 0)
        $myCase .= " WHEN $IL then $lim";
    else {
        for($l = $IL; $l <= $MaxIL; $l++) {
            $upLim = @$armorLimits[$inv == 20 ? 5 : $inv][$l];
            if ($upLim === null or $upLim < 0) continue;
            $myCase .= " WHen $IL then ". max($upLim - ($l - $IL), 0);
            break;
        }
        //global $item_invslot; echo " ! NO Mail/Plate ($inv)$item_invslot[$inv] IL $IL {", -$lim, "}", ($l < $MaxIL ? " -- use [+".($l - $IL)."]" : ""), "\n";
        ++$nPonded;
    }
    ++$nGroups;
  }
  $myCase .= " ELSE 9999 END";
}
$myCase .= "\nELSE 9999 END\n";

//printf(" ! Armor Limits retrieved: %d groups, %d ponded\n", $nGroups, $nPonded);
return $myCase;
}



///////////////////////// BUNDLE FUNCTIONS

function FixGeneral()
{
global $count; PrintHeader(__FUNCTION__);

MyOP("UPDATE waypoint_scripts SET datalong2=2 WHERE id=14 AND command=16 AND datalong=9739");
// https://github.com/TrinityCore/TrinityCore/issues/19427
Logs("Fix Captain Dranarus sound range (Shattrath, omnipresent Blood Elf voice): %d rows");


if (IsNotRepack("Sunwell")) return;

if (FIRST_RUN)
{
$count = MyRUN("
SET @GUID=(SELECT (MAX(guid) DIV 1000000 + 1)*1000000 FROM creature);
INSERT creature SET guid=@GUID, id=10685, map=1, position_x=16247, position_y=16383, position_z=47.12, orientation=4.62, spawntimesecs=180, spawndist=15, curhealth=14, curmana=0, MovementType=1; -- Swine
");
Logs("Add a critter (GM Island) to set stable starting value for new GUIDs dynamically added into `creature` table: %d creatures" );


// Исправляется понижение урона в WotLK БД от элитных (включая разжалованных в Normal) существ
// Например, урон от Bazil Thredd в 2 раза меньше, чем по ClassicDB/Nostalrius
MyOP("UPDATE creature_template SET mindmg=FLOOR(mindmg*(@t:=IF(rank IN(1,2) AND minlevel>11 AND maxlevel<40 AND INTERVAL(dmg_multiplier,1.69,1.71)=1, 3.4, dmg_multiplier))), maxdmg=FLOOR(maxdmg*@t), dmg_multiplier=1.0 WHERE dmg_multiplier!=1");
Logs("Got rid of dmg_multiplier!=1 in creature_template TABLE: %d creatures");
}

MyOP("DELETE FROM disables WHERE sourceType=2");
Logs("Remove disable from Karazhan(SunwellCore) and all other maps: %d disables");


MyOP('UPDATE page_text SET text="The corruption and evil that rumor says travels with the arcane is nothing compared to the pain we\'ve already felt. We are no longer victims, $N. We are the ones who control our fate. Sylvanas has paved the way for us--she has proven that our will is our own; that we are no longer thralls to that bastard Arthas.$B$BSeek me out in the church, I shall instruct you further... if that is your desire.$B$B- Isabella, Mage Trainer" WHERE entry=2447');
Logs("Fix text of Glyphic Scroll (quest item, Deathknell): %d rows");

$count = MyRUN("
DELETE FROM game_graveyard_zone WHERE id=512 AND ghost_zone=148 AND faction=67; -- remove Darkshore -> Ashenvale for Horde
UPDATE game_graveyard_zone SET faction=0 WHERE id=469 AND ghost_zone=148; -- allow Darkshore graveyard for Horde
UPDATE game_graveyard_zone SET faction=0 WHERE id= 35 AND ghost_zone=148; -- allow Darkshore graveyard for Horde
");
Logs("Fix graveyards for Horde: %d transitions" );

}


function FixGameobjects()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;

$count = MyRUN("
UPDATE gameobject SET position_x=1119.91, position_y=-4494, position_z=24.32 WHERE guid=4788 AND id=1731; -- Copper Vein внутри скалы (Durotar)
UPDATE gameobject SET position_x=-11732.6, position_y=1332.68, position_z=0 WHERE guid=11646 AND id=2045; -- Stranglekelp под поверхностью дна моря (Stranglethorn Valley)
UPDATE gameobject SET position_z=3.5 WHERE guid=3440 AND id=1622 AND position_z > 5; -- Bruiseweed высоко в воздухе (Stonetalon Mountains)
UPDATE gameobject SET position_z=-2 WHERE guid=631 AND id=1617 AND position_z<-3; -- Silverleaf под землёй (Mulgore)
UPDATE gameobject SET position_z=-9.7 WHERE guid IN (48120, 63507) AND id IN (1732, 1733) AND position_z>30; -- Tin Vein и Silver Vein под поверхностью недоступной горы над входным туннелем в Blackfathom Deeps
UPDATE gameobject SET position_x=-694.33, position_y=170.31, position_z=17.5 WHERE guid IN (75523, 75314, 75315, 75316) AND TRUNCATE(position_x,0)=-688 AND FLOOR(position_y)=168 AND FLOOR(position_z)=18; -- 4 руды смещены за пределы Azurelode Mine, до них не достать, попадают в зону видимости верхней карты (Hillsbrad Foothills)
UPDATE gameobject SET position_z=149 WHERE guid=5637 AND id=1732 AND FLOOR(position_z)<149; -- Tin Vein под поверхностью
");
Logs("Fix/slightly correct positions of gameobjects: %d objects" );

}


function FixGameobjectAllocation()
// В какой-то степени это Tweak, а не Fix, т.к. кол-во ресурсов настраивается
// под одного игрока, т.е. их немного. Впрочем, если времена восстановления
// оставлены стандартные, то нормально и для нескольких игроков
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;

// Есть два шаблона Bubbly Fissure: годный, представленный одним экземляром в
// The Stagnant Oasis и негодный, представленный 13 экземплярами,
// для которых и заменяем номер шаблона, см. http://www.wowhead.com/object=179491/waterlogged-footlocker
MyOP("UPDATE gameobject SET id=180057 WHERE id=177524");
Logs("Fix underwater Bubbly Fissures to restore Breath: %d gameobjects");


// Группирование ресурсов: часть ресурсов не группирована, вследствие
// чего - ресурсов огромное количество; но и там, где они распределены -
// распределены плохо (в некоторых шахтах систематически нет руды,
// в некоторых частях карты ничего нет и т.п.)
if (! FIRST_RUN) return;

CreateObjectPools("Herbs", "gameobject", 700, 380, true, 'AmountOfResourcesLow', <<<EOT
"Peacebloom", "Silverleaf", "Earthroot", "Mageroyal", "Swiftthistle", "Bloodthistle", "Briarthorn", "Stranglekelp", "Bruiseweed", "Wild Steelbloom", "Grave Moss", "Kingsblood", "Liferoot", "Fadeleaf", "Goldthorn", "Khadgar's Whisker", "Wintersbite", "Firebloom", "Purple Lotus", "Arthas' Tears", "Sungrass", "Blindweed", "Ghost Mushroom", "Gromsblood", "Golden Sansam", "Dreamfoil", "Mountain Silversage", "Plaguebloom", "Icecap",
"Bloodpetal Sprout"
EOT
);

CreateObjectPools("Black Lotus", "gameobject", 6000, 9000, true, 'Amount1', <<<EOT
"Black Lotus"
EOT
);

CreateObjectPools("Corrupted Felwood Herbs", "gameobject", 700, 400, true,  'AmountHalve', <<<EOT
"Corrupted Songflower", "Corrupted Windblossom", "Corrupted Night Dragon", "Corrupted Whipper Root"
EOT
); // всего ~30 штук


CreateObjectPools("Minerals", "gameobject", 700, 380, true, 'AmountOfResourcesLow', <<<EOT
"Copper Vein", "Tin Vein", "Silver Vein", "Ooze Covered Silver Vein", "Iron Deposit", "Ooze Covered Iron Deposit", "Gold Vein", "Ooze Covered Gold Vein", "Mithril Deposit", "Ooze Covered Mithril Deposit", "Small Thorium Vein", "Ooze Covered Thorium Vein", "Rich Thorium Vein", "Ooze Covered Rich Thorium Vein", "Truesilver Deposit", "Ooze Covered Truesilver Deposit",
"Lesser Bloodstone Deposit", "Dark Iron Deposit"
EOT
); // "Hakkari Thorium Vein",
//"Fel Iron Deposit", "Adamantite Deposit", "Rich Adamantite Deposit", "Khorium Vein", "Nethercite Deposit",
//"Cobalt Deposit", "Rich Cobalt Deposit", "Saronite Deposit", "Rich Saronite Deposit", "Pure Saronite Deposit", "Titanium Vein",


CreateObjectPools("Quest Resources", "gameobject", 500, 400, true, 'AmountOfResources', <<<EOT
"Blue Power Crystal", "Green Power Crystal", "Red Power Crystal", "Yellow Power Crystal",
"Mathystra Relic",
"Cactus Apple", "Equipment Boxes", "Gnomish Toolbox", "Gloom Weed", "Doom Weed", "Lesser Bloodstone Deposit", "Taillasher Eggs", "Crossroads' Supply Crates",
"Spire Spider Egg"
EOT
); // см. также Increase respawn time of resources and quest GO
// "Shellfish Trap" нельзя так просто ставить в pool - есть 2 с одинаковым названием, непонятно как соотносятся


// Понизить слишком высокую плотность сундуков с ценностями: в БД Sunwell их
// количество заметно большее, чем в ClassicDB
CreateObjectPools("Treasure Chests", "gameobject", 700, 700, true, 'Amount1', <<<EOT
"Battered Chest", "Tattered Chest", "Solid Chest",
"Large Battered Chest", "Large Solid Chest", "Large Iron Bound Chest", "Large Mithril Bound Chest",
"Fel Iron Chest", "Adamantite Bound Chest", "Heavy Fel Iron Chest"
EOT
); // in TBC Instances only: "Bound Fel Iron Chest", "Solid Fel Iron Chest", "Bound Adamantite Chest", "Solid Adamantite Chest"


MyOP("
INSERT IGNORE gameobject (id,map,position_x,position_y,position_z,orientation,rotation0,rotation1,rotation2,rotation3,spawntimesecs,animprogress,state) VALUES
(176214, 0, 2192.74, -4479.21,  87.66,   3.03687, 0, 0, 0.99863,   0.052336, 900, 100, 1),
(176214, 0, 2888.38, -4086.29, 101.381, -2.19912, 0, 0, 0.891007, -0.453990, 900, 100, 1);
");
// !!! В WotLK есть ещё 6 штук без trap GO
Logs("Fix/add 2 missing Blood of Heroes trap GOs (EPL): %d gameobjects");

// Есть два объекта с названием "Blood of Heroes" - lootable и невидимый trap на тех же координатах
CreateObjectPools("Blood of Heroes", "gameobject", 6000, 9000, true, create_function('$n,$rndseed', 'return 2;'), "(entry = 176213)");

CreateObjectPools("Warpwood Pods (Dire Maul)", "gameobject", 9000, 9000, true,
 create_function('$n,$rndseed', 'return max(1, round($n/5));'), <<<EOT
 "Warpwood Pod"
EOT
);

CreateObjectPools("Snowdrifts", "gameobject", 700, 700, true, 'AmountOfResources', <<<EOT
"Holiday Snow"
EOT
); // "Hardpacked Snowdrift" уже включён в pool_gameobject_template

CreateObjectPools("Silithyst Geysers", "gameobject", 6000, 3000, true, 'AmountHalve', <<<EOT
"Silithyst Geyser"
EOT
);

// ??? CreateObjectPools "Cat Figurine"


/*
MyOP("UPDATE gameobject_template AS gt JOIN gameobject ON (gt.entry=id) JOIN pool_gameobject AS pg USING(guid) SET chance=IF(gt.entry=180901,5,10) WHERE type=25 AND chance=20");
// В БД Sunwell каждый пул альтенатив содержит несколько равновероятных
// рыбных мест (chance=0) и одно место кораблекрушения (chance=20)
// Других значений chance, кроме 0 и 20 - нет среди мест ловли (type=25).
// Обломки в одиночной игре ловить слишком уж выгодно на низких уровнях
Logs("Reduce chance of Wreckages in favor of Schools of fish: %d fishnodes");
// -- Такое распределение в приниципе не годится из-за однообразия: на каждом
// месте ловли всегда что-нибудь да есть
*/

CreateObjectPools("Shipwreck Pools", "gameobject", 1700, 3000, true, 'Amount1', <<<EOT
"Floating Debris", "Floating Wreckage", "Bloodsail Wreckage", "Schooner Wreckage", "Waterlogged Wreckage",
"Steam Pump Flotsam"
EOT
);

foreach(array(
 "Sagefish School", "Greater Sagefish School", "Stonescale Eel Swarm",
 "Oil Spill",
 "School of Deviate Fish",
 "Muddy Churning Waters",
 "School of Darter", "Pure Water", "Highland Mixed School", "Mudfish School", "Bluefish School",
 "Imperial Manta Ray School", "Nettlefish School", "Dragonfin Angelfish School", "Borean Man O' War School", "Deep Sea Monsterbelly School", "Musselback Sculpin School", "Moonglow Cuttlefish School", "Glassfin Minnow School",
 ) as $school )
CreateObjectPools("Fishing Pools - $school", "gameobject", 1500, 3000, true, 'AmountOfFishings', <<<EOT
"$school"
EOT
);

CreateObjectPools("Fishing Pools - numerous (Firefin, Blackmouth, Lesser Sagefish, Brackish, Sporefish, Fangtooth Herring, Glacial Salmon)", "gameobject", 1500, 3000, true, 'AmountOfFishings', <<<EOT
"Sparse Firefin Snapper School", "Firefin Snapper School", "Abundant Firefin Snapper School", "Teeming Firefin Snapper School",
"Sparse Oily Blackmouth School", "Oily Blackmouth School", "Lesser Oily Blackmouth School", "Abundant Oily Blackmouth School", "Teeming Oily Blackmouth School",
"Lesser Sagefish School",
"Brackish Mixed School", "Sporefish School",
"Fangtooth Herring School", "Glacial Salmon School"
EOT
// Мест Imperial Manta Ray School (Northrend) слишком много, поэтому они пока
// отдельно, иначе (при географической коллизии) могут подавлять другие
);

/* нельзя так просто, т.к. они становятся доступны вне времени события; надо заносить все pool_entry в game_event_pool?
CreateObjectPools("Fishing Pools - School of Tastyfish (Stranglethorn Extravaganza Event)", "gameobject", 1500, 3000, true, 'AmountHalve', <<<EOT
"School of Tastyfish"
EOT
);
*/

}


function FixQuests()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;


MyOP("UPDATE quest_template SET SpecialFlags=SpecialFlags&~1 WHERE Id=813 AND PrevQuestId=-812");
// см. Player::SatisfyQuestPreviousQuest() - странно, что условие != QUEST_STATUS_NONE, а не != QUEST_STATUS_INCOMPLETE
// Противоядие, получаемое по заданию 813, не удаляется при отмене (и провале по времени?) задания 812 - поэтому и смысла в Repeatable флаге мало
Logs("Fix quest \"Finding the Antidote\" from being available after finished quest \"Need for a Cure\": %d quests");

MyOP("UPDATE quest_template SET RequiredRaces=0x44D WHERE Id=5713");
Logs("Make quest \"One Shot.  One Kill\" (NPC Sentinel Aynasha, Darkshore) Alliance only: %d quests");

MyOP("UPDATE quest_template SET RequiredRaces=0x44D WHERE Id=4740");
Logs("Make quest \"WANTED: Murkdeep!\" (signpost, Auberdine) Alliance only: %d quests");

MyOP("UPDATE quest_template SET RequiredRaces=0x44D WHERE Id in (931, 2399)");
Logs("Make quests \"The Shimmering Frond\" (tree, Teldrassil) and \"The Sprouted Fronds\" Alliance only: %d quests");

MyOP("UPDATE quest_template SET PrevQuestId=527 WHERE Id=546");
Logs("Fix prequest for quest \"Souvenirs of Death\": %d quests");

MyOP("UPDATE quest_template SET SpecialFlags=SpecialFlags&~1 WHERE Id=3629");
Logs("Fix/remove repeatable flag from one of \"Goblin Engineering\" quests: %d quests");

}


function FixLoot()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;


MyOP("UPDATE creature_loot_template SET ChanceOrQuestChance=IF(item=5094,30,15) WHERE item IN (5092, 5093, 5094) AND ChanceOrQuestChance<10");
Logs("Fix/increase drop chance for quest Razormane Wand / Backstabber / War Shield (Barrens): %d loots");


MyOP("UPDATE creature_template SET skinloot=IF(minlevel<=5,100001,0) WHERE skinloot=100008 AND NOT entry IN (1042,1043,1069,1044)");
Logs("Fix incorrect loot IDs for low level creatures (with Red Whelp Scale and Medium Leather): %d creatures");

MyOP("DELETE FROM creature_loot_template WHERE entry=5928 AND ChanceOrQuestChance=100 AND minCountOrRef=-26042");
Logs("Fix/remove WotLK L75 Cooking recipes from L27 Sorrow Wing (rare wyvern, Stonetalon Mountains): %d loots");

MyOP("UPDATE creature_loot_template SET ChanceOrQuestChance=0.3 WHERE item=3609 AND entry IN (17190,16353) AND ChanceOrQuestChance>2");
Logs("Fix/reduce \"Plans: Copper Chain West\" drop chance for Siltfin Murloc [50] and Mistbat [8.3]: %d loots");


MyOP("INSERT IGNORE skinning_loot_template SET entry=(SELECT DISTINCT skinloot FROM creature_template WHERE entry IN (14887/*,14888,14889,14890*/)), item=20381, mincountOrRef=1, maxcount=2");
Logs("Fix/add Dreamscale to skinning loot of Taerar,Ysondre,Lethon,Emeriss: %d rows");


MyOP("INSERT IGNORE creature_loot_template (entry,item,ChanceOrQuestChance) VALUES
 (5648, 862, 0.02), (5648,9484, 0.02), -- Sandfury Shadowcaster
 (5650, 862, 0.02), (5650,9484, 0.02); -- Sandfury Witch Doctor
");
Logs("Fix/add missing rare items Runed Ring and Spellshock Leggings (Zul'Farrak): %d loots");

}


function FixCreatures()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;


MyOP("UPDATE creature_template SET InhabitType=3 WHERE entry IN (4821,4822,4823, 4686,4687, 5467, 3231); -- Skittering/Snapping/Barbed Crustacean (BFD), Deepstrider Giant/Searcher (Desolace), Deep Dweller (Tanaris), Corrupted Dreadmaw Crocolisk (Durotar)");
// Иначе Corrupted Dreadmaw Crocolisk GUID 15100 застревает "на ровном месте" (в мелководье)
Logs("Fix InhabitType for some water+ground creatures: %d creatures");


$count = MyRUN("
UPDATE creature SET position_x=1032.46, position_y=1479.80, position_z=37.48 WHERE /*guid=17952 AND*/ id=1766 AND FLOOR(position_x)=1029 AND FLOOR(position_y)=1474 AND FLOOR(position_z)=36; -- Worg, внутри дерева (Silverpine Forest)
UPDATE creature SET position_x=1618.04, position_y=-5615.69, position_z=101.28, orientation=1.80 WHERE /*guid=56554 AND*/ id=9448 AND FLOOR(position_x)=1617 AND FLOOR(position_y)=-5614; -- Scarlet Praetorian внутри дерева
UPDATE creature SET position_x=1578.53, position_y=-5321.02, position_z=75.887047, orientation=5.28 WHERE /*guid=92054 AND*/ id=9447 AND FLOOR(position_x)=1580 AND FLOOR(position_y)=-5322; -- Scarlet Warder пересекается со столом
UPDATE creature SET position_x=-857.44, position_y=-4625.16, position_z=41.91 /*position_x=-841.72, position_y=-4615.29, position_z=45.33*/ WHERE guid=3401 AND ROUND(position_x)=-848 AND ROUND(position_y)=-4618; -- Clattering Scorpid, координаты на границе дерева (Durotar), hack из-за некорректного random movement
UPDATE creature SET position_z=-55.5 /*position_z=-58.15*/ WHERE guid=86048 AND map=43 AND ROUND(position_x)=-96 AND ROUND(position_y)=-262; -- Druid of the Fang (Wailing Caverns), под поверхностью
");
Logs("Fix/slightly correct positions of creatures: %d creatures" );

/*
MyOP("UPDATE creature SET MovementType=0, spawndist=0 WHERE
   guid IN (44571,44575,44287) AND id=1548 -- Cursed Darkhound (Tirisfal Glades)
OR guid=7996 AND id=3100 -- Elder Mottled Boar (Skulk Rock, Durotar)
OR guid=8658 AND id=3124 -- Scorpid Worker (Valley of Trials, Durotar)
OR guid=51556 AND id=199 -- Young Fleshripper (Jangolode Mine, Westfall)
");
Logs("Fix/hack(disable random movement) for creatures falling to underground caves: %d creatures" );
*/

MyOP("UPDATE creature SET MovementType=1, spawndist=18 WHERE id=4166 AND MovementType=0 AND spawndist=0");
Logs("Fix/hack random movement for each Gazelle with missing wayponts (Barrens): %d creatures");


MyOP("UPDATE creature_template SET flags_extra=flags_extra|0x20000000 WHERE entry=3652");
Logs("Disable mmaps for Trigore the Lasher (Barrens), unable to jump from ledge: %d creatures");

MyOP("UPDATE creature_template SET flags_extra=flags_extra|0x20000000 WHERE entry=3652");
Logs("Disable mmaps for Trigore the Lasher (Barrens), unable to jump from ledge: %d creatures");


MyOP("UPDATE creature_template SET faction=35 where entry=16781 AND faction=84");
Logs("Fix faction of Midsummer Celebrants killed by Horde guards (Alliance => Friendly): %d creatures");

MyOP("UPDATE creature_template SET faction=794/*Argent Dawn, ClassicDB*/ where entry=4787; -- was 80 Darnassus");
Logs("Fix faction of Argent Guard Thaelrid (Blackfathom Deeps) to allows accept Horde quest 6561 \"Blackfathom Villainy\": %d creatures");

}


function FixMissingCreatures()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;


$count = IsCreatureGuidExists(6228) ? 0 :
MyOP("INSERT creature SET id=6228, map=90, position_x=-670.959, position_y=700.469, position_z=-331.599, orientation=2.79324, spawntimesecs=21600, spawndist=20, curhealth=4924, curmana=1926, MovementType=1");
Logs("Fix/add Dark Iron Ambassador (rare elite, Gnomeregan): %d guids" );

$count = IsCreatureGuidExists(723) ? 0 :
MyRUN("INSERT creature SET id=723, map=0, position_x=-12482.2, position_y=-958.652, position_z=40.6509, orientation=1.42566, spawntimesecs=21600, spawndist=30, curhealth=5947, MovementType=1");
Logs("Fix/add Mosh'Ogg Butcher: %d guids" );

$count = IsCreatureGuidExists(5400) ? 0 :
MyOP("INSERT creature SET id=5400, map=0, position_x=-10238.4, position_y=-3998.45, position_z=-109.881, orientation=5.96744, spawntimesecs=28800, curhealth=6352, spawndist=10, MovementType=1");
Logs("Fix/add Zekkis (rare Troll, outside Temple of Atal'Hakkar): %d guids" );

$count = IsCreatureGuidExists(5399) ? 0 :
MyOP("INSERT creature SET id=5399, map=109, position_x=-414.111, position_y=23.1485, position_z=-90.8587, orientation=5.53157, spawntimesecs=6600, curhealth=6261, spawndist=10, MovementType=1");
Logs("Fix/add Veyzhak the Cannibal (rare Troll, Temple of Atal'Hakkar): %d guids" );

$count = IsCreatureGuidExists(3652) ? 0 :
MyOP("INSERT creature SET id=3652, map=1, position_x=-621.612, position_y=-2270.82, position_z=18.8419, orientation=2.67112, spawntimesecs=28800, curhealth=1341, spawndist=0");
Logs("Fix/add Trigore the Lasher (rare Hydra, outside Wailing Caverns): %d guids" );

$count = IsCreatureGuidExists(14237) ? 0 :
MyOP("INSERT creature SET id=14237, map=1, position_x=-4240.73, position_y=-2866.63, position_z=37.1291, orientation=5.23007, spawntimesecs=259200, curhealth=2508, spawndist=5, MovementType=1");
Logs("Fix/add Oozeworm (rare Rock borer, Dustwallow Marsh): %d guids" );

$count = IsCreatureGuidExists(14236) ? 0 :
MyOP("INSERT creature SET id=14236, map=1, position_x=-4190, position_y=-4011, position_z=-9, orientation=4.337, spawntimesecs=259200, curhealth=6455, spawndist=4, MovementType=1");
Logs("Fix/add Lord Angler (rare Makrura, Dustwallow Marsh): %d guids" );

$count = IsCreatureGuidExists(9718) ? 0 :
MyOP("INSERT creature SET id=9718, map=229, position_x=-94.917, position_y=-339.754, position_z=70.9524, orientation=1.55013, spawntimesecs=259200, curhealth=8996, spawndist=5, MovementType=1");
Logs("Fix/add Ghok Bashguud (rare elite Orc, Lower Blackrock Spire): %d guids" );

}


function FixAndTweakJeutie()
{
global $count; PrintHeader(__FUNCTION__);

// "Jeutie" only / not the default!
if ($GLOBALS['repack'] != "Jeutie") return;


// Дополнительные точки телепортации GM
MyOP("INSERT IGNORE INTO game_tele (id, position_x,position_y,position_z,orientation, map, name) VALUES (1424, 3481.26, 2000.03, 64.9759, 1.91766, 571, 'StarsRest')");
Logs("Additional Teleport Places: %d");

// [9.6.9] Добавляет отсутствующего quest NPC Gregory Tabor события Pilgrim's Bounty
//MyOP("INSERT INTO creature(id, map, spawnMask, phaseMask, modelid, equipment_id, position_x,position_y,position_z,orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES ('34675','0','1','1','0','0','-9133.91','355.333','92.3983','2.0151','300','0','0','1524','0','0','0','0','0')");
//Logs("Fix quest NPC Gregory Tabor, event Pilgrim's Bounty: %d rows");

// Frostbrood Vanquisher (dragon) cannot move
MyOP("UPDATE quest_template SET Method=0 WHERE Id=12779");
Logs("Fix Frostbrood Vanquisher (dragon), cannot move: %d rows");

$RewardFactionValueIdOverride = 'RewardFactionValueIdOverride'; $RewardFactionValueId = 'RewardFactionValueId';
if (mysql_query("SELECT `${RewardFactionValueIdOverride}1` FROM quest_template LIMIT 1") === FALSE)
    { $RewardFactionValueIdOverride = 'RewardFactionOverride'; $RewardFactionValueId = 'RewardFactionValue'; } // Jeutie r1.6+

// [9.6.9] Set Sporeggar reputation rewards from  [q] 9714/97159726/9727/9739/9742/9743/9744/9806/9807/9808 from 250 to 750
MyOP("UPDATE quest_template SET `${RewardFactionValueIdOverride}1`=75000 WHERE Id IN (9714,9715,9726,9727,9739,9742,9743,9744,9806,9807,9808)");
Logs("Fix Sporeggar reputation reward: %d rows");

// [9.6.9] Set Kurenai quest reputation rewards (values from DBC are inappropriate)
$count = MyRUN("
UPDATE quest_template SET `${RewardFactionValueIdOverride}1`=2000   WHERE RewardFactionId1=978 and `${RewardFactionValueId}1`=1;
UPDATE quest_template SET `${RewardFactionValueIdOverride}1`=5000   WHERE RewardFactionId1=978 and `${RewardFactionValueId}1`=2;
UPDATE quest_template SET `${RewardFactionValueIdOverride}1`=30000  WHERE RewardFactionId1=978 and `${RewardFactionValueId}1`=4;
UPDATE quest_template SET `${RewardFactionValueIdOverride}1`=50000  WHERE RewardFactionId1=978 and `${RewardFactionValueId}1`=5;
UPDATE quest_template SET `${RewardFactionValueIdOverride}1`=70000  WHERE RewardFactionId1=978 and `${RewardFactionValueId}1`=6;
UPDATE quest_template SET `${RewardFactionValueIdOverride}1`=100000 WHERE RewardFactionId1=978 and `${RewardFactionValueId}1`=7;
");
Logs("Fix Kurenai reputation reward: %d rows" );


$creature_questrelation = is_null(MyVAL("SHOW TABLES LIKE 'creature_queststarter'")) ? 'creature_questrelation' : 'creature_queststarter';

// [9.6.9] Исправляет quest "More Dense Grinding Stones" события Darkmoon Faire
MyOP("UPDATE $creature_questrelation SET id=14832 WHERE id=14833 AND quest=7939");
Logs("Fix quest More Dense Grinding Stones, event Darkmoon Faire: %d rows");

$twoFactionFields = mysql_query("SELECT faction_A, faction_H FROM creature_template LIMIT 1");

// [9.6.9] Исправляет в Blackwind Valley невозможность атаковать всех тех Skettis, что становятся видимы лишь во время действия Elixir of Shadows
MyOP("UPDATE creature_template SET ".($twoFactionFields ? "faction_A=1862, faction_H=1862" : "faction=1862")." WHERE entry IN (21644,21649,21650,21651,21763,21787,23066,23207,21838,23067,23068,23161) and ".($twoFactionFields ? "faction_A=1860" : "faction=1860"));
Logs("Fix non-attackable Skettis (Blackwind Valley): %d rows");

// [9.6.9 - 9.7.1] Fix Quest: Fire over Skettis
// "repack\Partial Fix Daily Quest `Fires Over Skettis`.sql"

// [9.7.0.1] Fix Vakkiz the Windrager (is out of combat when is summoned)
MyOP("UPDATE creature_template SET unit_flags=unit_flags&~256 WHERE name='Vakkiz the Windrager'");
Logs("Fix Vakkiz the Windrager, out of combat when is summoned: %d rows");

// [9.7.0.1]
// "repack\Partial Fix Quest `Grim(oire) Business` (10998).sql"

// [9.6.9] Partial Fix Quest 'Evil Draws Near' (10923, Terokkar Forest); Teribus the Cursed is out of combat when is finally summoned by players
MyOP("UPDATE creature_template SET unit_flags=unit_flags&~256 WHERE entry=22441");
Logs("Fix Teribus the Cursed, out of combat when is summoned: %d rows");

// [9.7.0.1]
// "repack\Fix Quest `Creatures of Eco-Domes`.sql"

// [9.7.0.1]
// "repack\Fix Quest `Meeting at the Blackwing Coven` (10722).sql"

// Открыть двери в Blackrock Spire из Dragonspire Hall в Hall of Bindings и 2 далее
//MyOP("UPDATE gameobject SET state=0 WHERE guid IN (87839,87842,87841,87845,87844)");
//Logs("Hack, open 3 doors in Blackrock Spire: %d rows");

// Исправить на Quel'Danas фракцию всем Pit Overlord, Wrath Enforcer, Eredar Sorcerer, на такую же, что у нежити в Dead Scar, чтобы они не сражались друг с другом (из-за этого невозможно выполнить daily quest)
MyOP("UPDATE creature_template SET ".($twoFactionFields ? "faction_A=233, faction_H=233" : "faction=233")." WHERE entry IN (25030,25031,25033) and ".($twoFactionFields ? "faction_A=1963" : "faction=1963"));
Logs("Hack Quel'Danas demons and undead not to fight: %d rows");

$ChanceOrQuestChance = 'ChanceOrQuestChance';
if (mysql_query("SELECT $ChanceOrQuestChance FROM gameobject_loot_template LIMIT 1") === FALSE)  $ChanceOrQuestChance = 'Chance'; // Jeutie r1.3+

// Сделать интерактивным сундук около Malor the Zealous в Scarlet Bastion, Stratholme и сделать извлечение Medallion of Faith безусловным; однако поведение Aurius'а не скриптовано...
$count = MyRUN("
UPDATE gameobject_template SET flags=0 WHERE entry=176112;
UPDATE gameobject_loot_template SET `$ChanceOrQuestChance`=100 WHERE entry=13580 AND item=12845;
");
Logs("Enable chest near Malor the Zealous (Stratholme, Scarlet Bastion): %d rows" );

// [9.7.0.1]
// "repack\Fix Quest `Leader of the Deranged`.sql" %MYCHK%

// Уменьшить XP за Daily Quests, которые предполагается выполнять по многу раз в день - Dalaran: Jewelcrafting, Cooking, Fishing; Allerian Stronghold: Spirits of Auchindoun
MyOP("UPDATE quest_template SET RewardXPId=1 WHERE Id IN (12958,12962,12959,12961,12963,12960, 13107,13100, 13832, 11505,11506) and (Flags&4096)!=0");
Logs("Lower XP for some Daily Quests: %d rows");

}


function RevertToClassic()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;


MyOP("UPDATE creature_template SET rank=2, Health_mod=Health_mod*3, mindmg=mindmg*3, maxdmg=maxdmg*3 WHERE rank=4 AND entry IN (596,599,1063,1837,1885,3652,4066,5399,5400,8924)");
Logs("Restore/boost RareElite Classic creatures from Rare: %d creatures");

MyOP("UPDATE creature_template SET rank=1, Health_mod=Health_mod*3, mindmg=mindmg*3, maxdmg=maxdmg*3 WHERE rank=0 AND entry IN (314,397,436,594,603,619,623,624,625,626,678,679,680,709,710,723,728,730,742,743,744,745,746,813,818,871,873,875,877,879,1051,1052,1053,1054,1061,1178,1179,1180,1181,1183,1225,1364,1388,1511,1559,1725,1726,1788,1800,1801,1827,1832,1834,1891,1892,1893,1894,1895,1896,1947,2060,2061,2062,2063,2064,2065,2066,2067,2068,2091,2106,2166,2254,2255,2256,2257,2287,2304,2344,2345,2346,2416,2420,2421,2422,2558,2569,2570,2571,2583,2584,2585,2588,2590,2591,2597,2599,2607,2611,2612,2635,2641,2642,2643,2644,2645,2646,2647,2648,2681,2738,2757,2759,2763,2773,2780,2781,2782,2783,2794,2835,2892,2932,3528,3529,3530,3531,3532,3533,3630,3631,3632,3633,3634,3638,3641,3655,4050,4052,4056,4061,4064,4065,4280,4281,4282,4283,4284,4285,4328,4329,4331,4334,4345,4409,4462,4464,4465,4468,4469,4499,4654,4788,4789,4802,4803,4844,4845,4846,4851,4856,4872,5097,5157,5224,5225,5235,5243,5261,5263,5269,5401,5402,5645,5646,5647,5780,5833,5860,5861,5862,6132,6140,6208,6210,6213,6231,6522,6523,6669,6733,7040,7041,7042,7043,7044,7045,7046,7053,7091,7135,7136,7276,7584,7728,7734,7735,7872,7873,7874,7977,7995,7996,8075,8391,8400,8419,8447,8518,8636,9043,9044,9461,10377,10608,10737,10738,10741,10802,10806,10807,10882,10943,10953,10982,10987,11141,11262,11387,11388,11389,11390,11391,11440,11442,11443,11600,11602,11603,11604,11605,11657,11677,11698,11721,11722,11723,11724,11725,11726,11728,11729,11730,11731,11732,11733,11734,11777,11778,11781,11782,11785,11786,11787,11788,11896,11897,11920,11921,12262,12263,12579,12865,13078,13079,13080,13081,13086,13087,13088,13089,13096,13097,13098,13099,13316,13317,13396,13397,13534,13535,13536,13537,13538,13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554,13555,13556,13557,13696,14388,14396,14467,14621,15209,15211,15212,15215,15286,15288,15290,15307,15428,15667,15962,16033,16124)");
Logs("Restore/boost Elite Classic creatures from Normal: %d creatures");

$count = MyRUN("
UPDATE creature_template SET minlevel=35, maxlevel=35, mindmg=193, maxdmg=249 WHERE entry= 1200 AND minlevel=32; -- Morbent Fel
UPDATE creature_template SET minlevel=35, maxlevel=35, mindmg= 96, maxdmg=124 WHERE entry=24782 AND minlevel=32; -- Weakened Morbent Fel
");
Logs("Restore/boost Morbent Fel (was L35 in patch 1.6): %d creatures" );

MyOP("UPDATE creature_template SET mindmg=116, maxdmg=208 /* HGDB */ WHERE entry=5775 AND (mindmg+maxdmg)/2 < 150");
Logs("Boost melee damage for Verdan the Everliving (Wailing Caverns): %d creatures");


MyOP("UPDATE item_template SET RequiredLevel=CASE RequiredLevel WHEN 20 then 39 WHEN 40 then 59 WHEN 60 then 69 ELSE RequiredLevel END
  WHERE class=15 AND RequiredSkill=762
");
Logs("Restore Classic/TBC level requirements for every Mount item (L20/L40/L60 => L39/L59/L69): %d items");

$count = MyRUN("
UPDATE npc_trainer SET reqlevel=40, spellcost= 100*10000 WHERE spell IN (33388,33389) AND reqlevel < 40; -- Apprentice Riding
UPDATE npc_trainer SET reqlevel=60, spellcost=1000*10000 WHERE spell IN (33391,33392) AND reqlevel < 60; -- Jorneyman Riding
UPDATE npc_trainer SET reqlevel=70, spellcost=2000*10000 WHERE spell IN (34090,34092) AND reqlevel < 70; -- Expert Riding
UPDATE npc_trainer SET reqlevel=70, spellcost=5000*10000 WHERE spell IN (34091,34093) AND reqlevel <=70; -- Artisan Riding
UPDATE mail_level_reward SET level=69 WHERE level=60 AND mailTemplateId >= 282; -- L70 нельзя из-за коллизии в таблице БД, да и два письма на одном уровне не должны приходить
UPDATE mail_level_reward SET level=60 WHERE level=40 AND mailTemplateId >= 272;
UPDATE mail_level_reward SET level=40 WHERE level=20 AND mailTemplateId >= 224;
UPDATE quest_template SET MinLevel=40, Level=40 WHERE title LIKE 'Learn to Ride %';
");
Logs("Restore Classic/TBC Riding skill Level requirements (L40/L60/L70/L70): %d rows" );


$count = MyRUN("
UPDATE npc_trainer SET reqlevel=40, spellcost=  40*10000 WHERE spell= 1710 AND reqlevel < 40; -- Summon Felsteed
UPDATE npc_trainer SET reqlevel=60, spellcost= 600*10000 WHERE spell=23161 AND reqlevel < 60; -- Dreadsteed
UPDATE npc_trainer SET reqlevel=40, spellcost=  35*10000 WHERE spell IN (13820,34768) AND reqlevel < 40; -- Summon Warhorse
UPDATE npc_trainer SET reqlevel=60, spellcost= 350*10000 WHERE spell=34767 AND reqlevel < 60; -- Summon Warhorse
");
// Задания Paladin/Warlock на обретение заклинаний призывания коней пока не
// восстанавливаем: там нужны скрипты для событий в концах цепочек заданий
Logs("Change Paladin and Warlock Summon a mount spell level requirements (L20/L40 => L40/L60): %d rows" );

//MyOP("UPDATE quest_template SET MinLevel=39, Level=39 WHERE Title='Summon Felsteed'");
//Logs("'Summon Felsteed' quests tweaked (L40 => L39): %d quests");

//MyOP("UPDATE quest_template SET MinLevel=39, Level=39,RequiredRaces=0 WHERE Title='The Tome of Nobility'");
//Logs("Paladin Warhorse quests tweaked (L40 => L39, any race): %d quests");


MyOP("DELETE FROM npc_trainer WHERE spell=1066 AND reqlevel <= 20");
Logs("Remove Aquatic Form from Druid trainers, get it by quest: %d trainers");


MyOP("UPDATE npc_trainer SET reqlevel=30 WHERE spell IN (1441,783) AND reqlevel < 30");
Logs("Restore Classic level requirement for Druid Travel Form (L16 => L30): %d trainers");

MyOP("UPDATE npc_trainer SET reqlevel=20 WHERE spell IN (2645) AND reqlevel < 30");
Logs("Restore Classic level requirement for Shaman Ghost Wolf (L16 => L20): %d trainers");


MyOP("DELETE FROM npc_trainer WHERE spell IN (
/*Expert ...*/ 3465,3539,3568,3571,3812,3812,3913,4041,7416,8620, /*28896,45377,*/ 54083,54254,54257,
/*Artisan ...*/ 9786,10249,10663,10663,10769,10847,11612,11994,12181,12657,13921,18249,18261,28899,45378
) AND NOT entry IN (812,908,1218,1292,1346,1386,1458,1473,1681,1701,2114,2390,2399,2836,2856,3001,3007,3013,3137,3175,3185,3355,3357,3404,3555,3604,3965,4160,4204,4212,4254,4258,4576,4598,4611,4614,4898,5137,5174,5392,5502,5513,5566,6287,6288,6289,6290,6291,6292,6295,6297,6306,6387,7087,7088,7089,7870,7948,8128,8144,8146,8736,11017,11052,11072,11073,11074,11097,11098,11557,12025,12030,
                    30716,30710,19778,19775)
");
// Номера spell'ов и entry допустимых наставников выясняются через SELECT entry, sp.id, sp.SpellName_1 FROM dbcdata.spell AS sp JOIN npc_trainer AS nt ON sp.id=nt.spell WHERE (SpellName_1 LIKE 'Expert %' OR SpellName_1 LIKE 'Artisan %') AND NOT SpellName_1 LIKE '% Riding' ORDER BY entry, sp.SpellName_1,sp.id
// По классике не все наставники учат уровню Expert, и только единичные - Artisan (за исключением Herbalism, Skinning, Mining)
// Для Jewelcrtafting и Inscription уровень Expert оставляем у всех, т.к. даже Artisan учат в столицах, и ничего искать не надо
// По классике для Cook/First Aid/Fishing на Expert надо покупать книги, а на Artisan - выполнять задания
// Конкретные рецепты всё же остаются у множества наставников, у которых их не было в Классике
Logs("Remove non-Classic Expert/Artisan teachings from trainers: %d rows");

MyOP("
INSERT IGNORE npc_trainer (entry,spell,spellcost,reqskill,reqskillvalue,reqlevel) VALUES
-- Выясняется по ClassicDB через SELECT entry,spell,spellcost,reqskill,reqskillvalue,reqlevel /*, sp.SpellName_1*/ FROM dbcdata.spell AS sp JOIN npc_trainer AS nt ON sp.id=nt.spell WHERE (SpellName_1 LIKE 'Expert %' OR SpellName_1 LIKE 'Artisan %') AND NOT SpellName_1 LIKE '% Riding' ORDER BY entry, reqskillvalue
(812,3571,5000,182,125,0),
(812,11994,50000,182,200,0),
(908,3571,5000,182,125,0),
(908,11994,50000,182,200,0),
(1218,3571,5000,182,125,0),
(1218,11994,50000,182,200,0),
(1292,8620,5000,393,125,0),
(1292,10769,50000,393,200,35),
(1346,3913,4500,197,125,20),
(1386,3465,5000,171,125,20),
(1386,11612,45000,171,200,35),
(1458,3571,5000,182,125,0),
(1458,11994,50000,182,200,0),
(1473,3571,5000,182,125,0),
(1473,11994,50000,182,200,0),
(1681,3568,4500,186,125,0),
(1681,10249,50000,186,200,0),
(1701,3568,4500,186,125,0),
(1701,10249,50000,186,200,0),
(2114,3571,5000,182,125,0),
(2114,11994,50000,182,200,0),
(2390,3571,5000,182,125,0),
(2390,11994,50000,182,200,0),
(2399,3913,4500,197,125,20),
(2399,12181,50000,197,200,0),
(2836,3539,4500,164,125,20),
(2836,9786,50000,164,200,35),
(2856,3571,5000,182,125,0),
(2856,11994,50000,182,200,0),
(3001,3568,4500,186,125,0),
(3001,10249,50000,186,200,0),
(3007,3812,5000,165,125,20),
(3013,3571,5000,182,125,0),
(3013,11994,50000,182,200,0),
(3137,3568,4500,186,125,0),
(3137,10249,50000,186,200,0),
(3175,3568,4500,186,125,0),
(3175,10249,50000,186,200,0),
(3185,3571,5000,182,125,0),
(3185,11994,50000,182,200,0),
(3355,3539,4500,164,125,20),
(3357,3568,4500,186,125,0),
(3357,10249,50000,186,200,0),
(3404,3571,5000,182,125,0),
(3404,11994,50000,182,200,0),
(3555,3568,4500,186,125,0),
(3555,10249,50000,186,200,0),
(3604,3571,5000,182,125,0),
(3604,11994,50000,182,200,0),
(3965,3571,5000,182,125,0),
(3965,11994,50000,182,200,0),
(4160,3465,5000,171,125,20),
(4204,3571,5000,182,125,0),
(4204,11994,50000,182,200,0),
(4212,3812,5000,165,125,20),
(4254,3568,4500,186,125,0),
(4254,10249,50000,186,200,0),
(4258,3539,4500,164,125,20),
(4576,3913,4500,197,125,20),
(4598,3568,4500,186,125,0),
(4598,10249,50000,186,200,0),
(4611,3465,5000,171,125,20),
(4614,3571,5000,182,125,0),
(4614,11994,50000,182,200,0),
(4898,3571,5000,182,125,0),
(4898,11994,50000,182,200,0),
(5137,3571,5000,182,125,0),
(5137,11994,50000,182,200,0),
(5174,4041,4500,202,125,20),
(5392,3568,4500,186,125,0),
(5392,10249,50000,186,200,0),
(5502,3571,5000,182,125,0),
(5502,11994,50000,182,200,0),
(5513,3568,4500,186,125,0),
(5513,10249,50000,186,200,0),
(5566,3571,5000,182,125,0),
(5566,11994,50000,182,200,0),
(6287,8620,5000,393,125,0),
(6287,10769,50000,393,200,35),
(6288,8620,5000,393,125,0),
(6288,10769,50000,393,200,35),
(6289,8620,5000,393,125,0),
(6289,10769,50000,393,200,35),
(6290,8620,5000,393,125,0),
(6290,10769,50000,393,200,35),
(6291,8620,5000,393,125,0),
(6291,10769,50000,393,200,35),
(6292,8620,5000,393,125,0),
(6292,10769,50000,393,200,35),
(6295,8620,5000,393,125,0),
(6295,10769,50000,393,200,35),
(6297,3568,4500,186,125,0),
(6297,10249,50000,186,200,0),
(6306,8620,5000,393,125,0),
(6306,10769,50000,393,200,35),
(6387,8620,5000,393,125,0),
(6387,10769,50000,393,200,35),
(7087,8620,5000,393,125,0),
(7087,10769,50000,393,200,35),
(7088,8620,5000,393,125,0),
(7088,10769,50000,393,200,35),
(7089,8620,5000,393,125,0),
(7089,10769,50000,393,200,35),
(7870,3812,5000,165,125,20),
(7870,10663,50000,165,200,35),
(7948,3465,5000,171,125,20),
(7948,11612,45000,171,200,35),
(8128,3568,4500,186,125,0),
(8128,10249,50000,186,200,0),
(8144,8620,5000,393,125,0),
(8144,10769,50000,393,200,35),
(8146,3571,5000,182,125,0),
(8146,11994,50000,182,200,0),
(8736,4041,4500,202,125,20),
(8736,12657,45000,202,200,35),
(11017,4041,4500,202,125,20),
(11052,3913,4500,197,125,20),
(11052,12181,50000,197,200,0),
(11072,7416,5000,333,125,20),
(11073,7416,5000,333,125,20),
(11073,13921,50000,333,200,35),
(11074,7416,5000,333,125,20),
(11097,10663,50000,165,200,35),
(11098,10663,50000,165,200,35),
(11557,3913,4500,197,125,20),
(11557,12181,50000,197,200,0),
(12025,3571,5000,182,125,0),
(12025,11994,50000,182,200,0),
(12030,8620,5000,393,125,0),
(12030,10769,50000,393,200,35),

-- Выясняется через SELECT entry,spell,spellcost,reqskill,reqskillvalue,reqlevel, sp.SpellName_1 FROM dbcdata.spell AS sp JOIN npc_trainer AS nt ON sp.id=nt.spell WHERE (SpellName_1 LIKE 'Expert %' OR SpellName_1 LIKE 'Artisan %') AND (SpellName_1 LIKE '% Jewelcrafter' OR SpellName_1 LIKE '% Scribe') ORDER BY entry, sp.SpellName_1,sp.id
-- Наставников в раннем TBC, до patch 2.3 выяснить непросто

-- Expert Scribe
-- (30716, 45377, 4750, 773, 125, 20),
-- (30710, 45377, 4750, 773, 125, 20),
-- Artisan Scribe
(30716, 45378, 47500, 773, 200, 35),
(30710, 45378, 47500, 773, 200, 35),

-- Expert Jewelcrafter
-- (19778, 28896, 5000, 755, 125, 20),
-- (19775, 28896, 5000, 755, 125, 20),
-- Artisan Jewelcrafter
(19778, 28899, 50000, 755, 200, 35),
(19775, 28899, 50000, 755, 200, 35);

");
// Минус: в WotLK младшие наставники уже не направляют советами к Expert/Artisan учителям
// Expert-наставники Alchemy,Tailoring, Engineering,Blacksmithing, Leatherworking отыскиваются в одной из столиц фракции
// Expert Enchanter - Tower of Azora(Alliance) или Sun Rock Retreat(Horde)
Logs("Restore Classic Expert/Artisan profession trainers {134}: %d teachings" );


MyOP("INSERT IGNORE npc_vendor (entry, item) VALUES (3955/*Shandrina*/, 16072), (12033/*Wulan*/, 16072)");
Logs("Add Expert Cookbook to vendors in Shadowprey Village and Silverwind Refuge: %d vendors");

MyOP("INSERT IGNORE npc_vendor (entry, item) VALUES (2805/*Deneb Walker*/, 16084), (13476/*Balai Lok'Wein*/, 16084)");
Logs("Add Expert First Aid book to vendors in Stromgarde and Brackenwall Village: %d vendors");

MyOP("INSERT IGNORE npc_vendor (entry, item) VALUES (2626/*Old Man Heming*/, 16083)");
Logs("Add Expert Fishing book to vendor in Booty Bay: %d vendors");

// Задания на Artisan уровень:
// Fishing - "Nat Pagle, Angler Extreme" Dustwallow Marsh @Nat Pagle
// First Aid - "Triage" Theramore / Hammerfall
// Cooking - "Clamlette Surprise" Gadgetzan @Dirge Quikcleave

MyOP("UPDATE quest_template SET MinLevel=10, Level=-1, RewardItemId1=0, RewardItemCount1=0, RewardSpell=18248, RewardSpellCast=18249 WHERE Id=6607");
Logs("Restore Artisan Fishing quest (with non-Classic/WotLK requirement L10, Fishing 225) @Nat Pagle (Dustwallow Marsh): %d quests");

}


function RevertToTBC()
{
global $count; PrintHeader(__FUNCTION__);

MyOP(<<<EOT
UPDATE creature_template AS ct JOIN creature ON (entry=id) SET flags_extra=flags_extra|128 WHERE ct.name IN (
"Grunda Bronzewing","Wind Rider Jahubo",
"First Aid","Cooking","Fishing", "Skinning","Mining","Herbalism", "Tailoring","Leatherworking","Blacksmithing", "Engineering", "Alchemy", "Enchanting", "Jewelcrafting","Inscription",
"Tharl Stonebleeder", "Zas'Tysh", "Murky", "Gurky", "Ransin Donner", /*"Edward Cairn",*/ "Ian Drake"
)
EOT
);
Logs("Disable post-TBC NPCs, make them invisible: %d creatures");


if (IsNotRepack("Sunwell")) return;

MyOP("UPDATE creature_template JOIN creature ON entry=id SET rank=2, mindmg=mindmg*IF(rank=4, 3,1), maxdmg=maxdmg*IF(rank=4, 3,1), Health_mod=Health_mod*8 WHERE rank IN (2,4) AND minlevel>60 AND map=530 AND Health_mod < 8");
Logs("Convert Outland Rare creatures to Rare Elite, boost their Damage and Health: %d creatures");

}


function TweakGeneral()
{
global $count; PrintHeader(__FUNCTION__);

$lvl = 'lvl'; $xp_for_next_level = 'xp_for_next_level';
if (mysql_query("SELECT $lvl FROM player_xp_for_level LIMIT 1") === FALSE)
   { $lvl = 'Level'; $xp_for_next_level = 'Experience'; } // Jeutie r1.6+


// Растягивание прогрессии опыта, чтобы проходить все зоны и задания, брать
// задания более высокого уровня и рано получать за них вещи с высоким
// ItemLevel без требования RequiredLevel
// Растягивания в 10 раз на низких уровнях едва достаточно в WotLK 3.3.5a
// (где, в отличие от Classic 1.12 не 3, а 4 стартовые зоны с заданиями), дабы
// избегнуть чрезмерного прогресса, и потому Rate.XP.Explore=1 в .conf
// повышать не следует
$count = MyVAL("SELECT $xp_for_next_level FROM player_xp_for_level WHERE $lvl=1") != 400 ? 0 :
MyRUN("", "UPDATE player_xp_for_level SET $xp_for_next_level=
 IF(
  (@t := $xp_for_next_level * CASE
   WHEN $lvl <= 19 THEN 10+ (10-10)*($lvl- 1)/(19- 1) -- L1..L19  => x10
   WHEN $lvl <= 39 THEN 10- (10- 4)*($lvl-20)/(39-20) -- L20..L39 => x10..x4
   WHEN $lvl <= 57 THEN 4                             -- L40..L57 => x4
                   ELSE 10                            -- L58..L79 => x10
   END
  ) > 10000, @t - @t MOD 1000, @t - @t MOD 100
 )
");
Logs("Slow down XP/leveling progression: %d levelups" );


if (IsNotRepack("Sunwell")) return;


MyOP("UPDATE playercreateinfo_spell SET racemask=0, classmask=0 WHERE Spell IN (
   75/*Auto Shot*/,
  107/*Block*/,
  196/*One-Handed Axes*/,
  198/*One-Handed Maces*/,
  201/*One-Handed Swords*/,
  203/*Unarmed*/,
  227/*Staves*/,
  264/*Bows*/,
  266/*Guns*/,
  674/*Dual Wield - Shaman*/,
 1180/*Daggers*/,
 2481/*Find Treasure*/,
 5009/*Wands*/,
 5019/*Shoot*/,
 8737/*Mail*/,
 9077/*Leather*/,
 9116/*Shield*/,
27762/*Libram*/,
27763/*Totem*/
) ");
Logs("Allow some initial Abilities for all races and classes: %d abilities");

MyOP("DELETE FROM playercreateinfo_spell -- UPDATE playercreateinfo_spell SET racemask=16384
WHERE Spell IN (
20599, -- Diplomacy - чтобы не было соблазна переключаться на Human при сдаче заданий в мультиклассовой игре
-- Добавлено изучение у наставников классов
 5176, -- Wrath(Rank 1)
 5185, -- Healing Touch(Rank 1)
  133, -- Fireball(Rank 1)
  168, -- Frost Armor(Rank 1)
  686, -- Shadow Bolt(Rank 1)
  687, -- Demon Skin(Rank 1)
  585, -- Smite(Rank 1)
 2050, -- Lesser Heal(Rank 1)
  403, -- Lightning Bolt(Rank 1)
  331, -- Healing Wave(Rank 1)
  635, -- Holy Light(Rank 1)
 2973, -- Raptor Strike(Rank 1)
 2457, -- Battle Stance
-- Изучать у Weapon Master'а
  197, -- Two-Handed Axes - изучать у Weapon Master'а
  199, -- Two-Handed Maces - изучать у Weapon Master'а
  202, -- Two-Handed Swords - изучать у Weapon Master'а
 2567  -- Thrown - изучать у Weapon Master'а
) ");
Logs("Remove some initial Abilities from all races and classes: %d abilities");

MyOP("INSERT IGNORE npc_trainer SET entry=200001, spell=2457, spellcost=50, reqlevel=1");
// В таблице npc_trainers отрицательный entry=-200001 указывает на группу spell'ов (в этой же таблице > чем любой номер NPC entry)
Logs("Add Battle Stance to low-level Warrior trainers: %d trainers");

MyOP("
INSERT IGNORE npc_trainer (entry, spell, spellcost,reqlevel) VALUES
(200005, 5176, 10,1), -- Druid, Wrath(Rank 1)
(200005, 5185, 10,1), -- Druid, Healing Touch(Rank 1)
(200007,  133, 10,1), -- Mage, Fireball(Rank 1)
(200007,  168, 10,1), -- Mage, Fireball(Rank 1)
(200009,  686, 10,1), -- Warlock, Shadow Bolt(Rank 1)
(200009,  687, 10,1), -- Warlock, Demon Skin(Rank 1)
(200011,  585, 10,1), -- Priest, Smite(Rank 1)
(200011, 2050, 10,1), -- Priest, Lesser Heal(Rank 1)
(200018,  403, 10,1), -- Shaman, Lightning Bolt(Rank 1)
(200018,  331, 10,1), -- Shaman, Healing Wave(Rank 1)
(200003,  635, 10,1), -- Paladin, Holy Light(Rank 1)
(200014, 2973, 10,1); -- Hunter, Raptor Strike(Rank 1)
");
// Их изучение нужно, чтобы были доступны при игре всеми классами.
// Заклинателям придётся самых первых врагов одолеть ручным оружием,
// накопить около 10c и выучить поражающее заклинание первого уровня.
Logs("Add Rank 1 spells to low-level Druid, Mage, Warlock, Priest and Shaman trainers: %d trainers");


MyOP("UPDATE player_classlevelstats AS dst JOIN player_classlevelstats AS src ON (src.class=11 AND src.level=dst.level) SET dst.basemana=src.basemana WHERE dst.basemana=0 AND dst.class IN (1,4,6)");
// Это пока не позволяет полноценно пользоваться заклинаниями (т.к. в ядре нет
// пока натуральной регенерации (только MP5), и нет постоянных обновлений в
// клиенте - не визуальных, а значения UnitPower("player", 0). Зато запрещается
// неограниченное применение магии классами с нулевым запасом маны, и делается
// это корректным способом - так, что Lua-проверки на ману показывают нехватку.
// NB! Не получится запретить заклинания установкой basemana=1, т.к. всё равно
// будут прибавки от INT. Более того, 1 - то же самое что 0, из-за округления;
// те же неограниченные заклинания. Минимум ~ 20 (5% от 20 == 1) ?
Logs("Set non-zero maximum mana for classes Warrior, Rogue and Death Knight: %d rows");


MyOP("UPDATE gameobject_template SET displayid=250 WHERE displayid IN (6351,6398,6399) -- GO 180405,180431,180406,180407");
Logs("Visually replace tasteless Hallow's End Pumpkins by bubbling aura: %d gameobjects");


$count = MyVAL("SELECT DATA_TYPE='DATETIME' FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='game_event' AND COLUMN_NAME='start_time'") ? 0 :
MyRUN("
-- Переменить тип TIMESTAMP в DATETIME, чтобы всё было по локальному времени и не было ограничения 2038 годом
SET @@session.time_zone = (SELECT CONCAT(IF( (@t:=CASE WHEN (@t:=CAST(SUBSTR(CURTIME(),1,2)-SUBSTR(UTC_TIME(),1,2) AS SIGNED)) < -12 THEN @t+24 WHEN @t>13 THEN @t-24 ELSE @t END  +14 - CAST(SUBSTR(start_time,-8,2) AS SIGNED)) >= 0, CONCAT('+',@t), @t), ':00') AS TimeZone FROM game_event WHERE eventEntry=15); -- автоопределяем зону времени, соответствующую генерации БД, исходя из того, что рыболовля начинается в 14:00
ALTER TABLE game_event MODIFY start_time DATETIME NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT 'Absolute start date, the event will never start before', MODIFY end_time DATETIME NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT 'Absolute end date, the event will never start after';
SET @@session.time_zone = 'SYSTEM';
-- Исправить периоды Gurubashi Arena Booty Run - через 3 часа, начиная с 00:00
UPDATE game_event SET start_time='2005-04-19 00:00:00' WHERE description LIKE 'Gurubashi Arena%'; -- started with patch 1.4.0
-- Сделать Darkmoon Faire постоянно действующим: неделю в Mulgore, неделю в
-- Elwynn Forest (где два дня заняты приготовлениями), неделю в Terrokar Forest
UPDATE game_event SET start_time='2006-01-02 02:00:00', occurence=30240, length=10080 WHERE description='Darkmoon Faire (Mulgore)';
UPDATE game_event SET start_time='2006-01-09 02:00:00', occurence=30240, length=2880  WHERE description LIKE 'Darkmoon Faire Building (Elwynn%';
UPDATE game_event SET start_time='2006-01-11 02:00:00', occurence=30240, length=7200  WHERE description LIKE 'Darkmoon Faire (Elwynn%';
UPDATE game_event SET start_time='2006-01-18 02:00:00', occurence=30240, length=10080 WHERE description='Darkmoon Faire (Terokkar Forest)';
-- Проводить раз в два дня (вместо раза в неделю) Fishing Extravaganza Announce, Fishing Extravaganza (14:00-16:00), Fishing Extravaganza Turn-in
UPDATE game_event SET occurence=2*24*60 WHERE description LIKE 'Fishing Extravaganza%';
-- Удлинить Midsummer Fire Festival примерно в два раза, до 30 дней: с ~21 июня по 21 июля (из-за occurence=525600=365 дней дата уменьшается по прошествии лет!)
UPDATE game_event SET length=43203 WHERE description LIKE 'Midsummer Fire Festival%';
-- Удлинить в три раза Harvest Festival: 3 недели с 5 октября
UPDATE game_event SET length=30240 WHERE description LIKE 'Harvest Festival%';
-- Сократить бездарный Hallow's End до двух суток: 29-31 октября
UPDATE game_event SET start_time='2006-10-29 22:59:00', length=2880 WHERE description LIKE 'Hallow%';
-- Сделать более редким (раз в 4 часа, вместо 30 минут) событие Dalaran: Mingob
UPDATE game_event SET occurence=4*60 WHERE INSTR(description, 'Minigob');
-- Установить год начала равным прошлому году для событий, привязанных к числам месяца, иначе будут 'съезжать' их даты, т.к. период = 365 дней
UPDATE game_event SET start_time=IF(YEAR(start_time)=0,start_time, CONCAT(YEAR(CURDATE())-1,'-',MONTH(start_time),'-',DAYOFMONTH(start_time),' ',HOUR(start_time),':',MINUTE(start_time),':',SECOND(start_time))) WHERE NOT INSTR(description,'Darkmoon Faire') AND NOT INSTR(description,\"Kalu'ak\");
-- Установить год конца через 10 лет от текущей даты, дабы ничто не завершалось
UPDATE game_event SET end_time=IF(YEAR(end_time)=0,end_time, CONCAT(YEAR(CURDATE())+10,'-',MONTH(end_time),'-',DAYOFMONTH(end_time),' ',HOUR(end_time),':',MINUTE(end_time),':',SECOND(end_time)));
");
Logs("Game Event schedule modifications: %d" );


MyOP("UPDATE creature_template SET minlevel=1, maxlevel=60, Health_mod=20 WHERE entry IN (4952)");
Logs("Make Theramore Combat Dummy L1..L60 with lots of Health: %d rows");

}


function TweakItems()
{
global $count; PrintHeader(__FUNCTION__);

// MyOP("UPDATE item_template SET stackable=stackable*10 WHERE stackable > 1");
// max. stack size = 255 in WoW 1.12
// Объединять оружие (2) и доспехи (4) нельзя, т.к. объединение/разделение позволяет дублировать Durability и др. свойства (хотя это и непринципиально для Quality <= 1)
// Объединять сумки (1) нельзя, т.к. при установке пачки в банковский слот несколько штук превращаются в одну
// Псевдоконтейнеры (Trunk, Clam) объединять нельзя, т.к. раскрытие на пачке открывает только один, а уничтожает все
MyOP("UPDATE item_template SET stackable=500 WHERE stackable < 500 AND (stackable > 1 OR (stackable=1 AND NOT class IN (1,2,4)) AND spellcharges_1 IN(-1,0) AND spellcharges_2 IN(-1,0) AND spellcharges_3 IN(-1,0) AND spellcharges_4 IN(-1,0) AND spellcharges_5 IN(-1,0) AND Flags&4=0 /* not lootable */)");
Logs("Stack limits maximized for %d items");


if (IsNotRepack("Sunwell")) return;


MyOP("UPDATE item_template SET AllowableClass=AllowableClass|0x5FF WHERE AllowableClass>0 AND NOT (class=9 AND subclass=0 AND (AllowableClass & 64) AND (AllowableClass & 0x5FF & ~64)=0); -- except Horde-only Shaman items");
Logs("Remove class restriction from items: %d items");

// Выравнивание показателя armor для всех типов доспехов (Cloth, Leather, Mail,
// Plate) для одиночной мультиклассовой игры, благодаря чему лёгкие доспехи
// не лишаются смысла, повышается широта выбора и разнообразие внешнего вида.
// Более тяжёлые типы сохраняют некоторое преимущество, но оно не так велико.
// До 40-го уровня вещей включительно Cloth и Leather выравниваются на Mail.
// После 40-го уровня, когда появляется Plate, Cloth/Leather/Mail постепенно,
// в течение 41..49 уровней, подтягиваются до Plate.
// Начиная с 50-го уровня вещей все типы примерно выровнены.
// В оригинале при повышении категории тяжести доспехов на одну ступень
//   armor увеличивается примерно в 2 раза. Но есть вещи с повышенным armor,
//   поэтому используется ограничитель - минимальный armor среди всех вещей
//   такого же уровня, но максимальной категории тяжести (т.е. mail/plate)
$count = MyVAL("SELECT armor FROM item_template WHERE entry=9623/*Civinad Robes, armor 54*/") > 70 ? 0 :
MyRUN(
"SET @boosted:=0", // без SET @...= команд работает неправильно,
"SET @lim:=0",     //  кажется, предполагая строковый тип данных
"UPDATE item_template
 SET armor = CASE
     WHEN (@boosted := FLOOR(armor * POW(1.9, 3-subclass) * (CASE WHEN ItemLevel <= 40 THEN 1.0 WHEN ItemLevel < 50 THEN (1 + 0.7*(ItemLevel-40)/(50-40)) ELSE 1.7 END) )) < armor THEN armor
     WHEN (@lim := (". RetrieveArmorLimits() .") - (IF(ItemLevel < 40, 3, 4)-CAST(subclass AS SIGNED)) ) < armor THEN armor
     WHEN @lim < @boosted THEN @lim
     ELSE @boosted
 END
 WHERE InventoryType IN (1,3,5,6,7,8,9,10,20) AND class=4 AND (subclass IN (1,2) OR subclass=3 AND ItemLevel >= 40)"
);
Logs("Boost armor of Cloth/Leather/[Mail] items to match Mail/Plate: %d items" );


// Помещать отмычку, расходные материалы разбойника, инженерный порох,
// кристаллы чернокнижника, некоторые реагенты, стрелы и пули, ювелирные статуи
// в сумку для ключей (32 места в WotLK).
// В отличие от WoW 1.12 BagFamily является маской, а не индексом, и потому
// можно указывать несколько видов особых сумок, куда можно положить вещь.
// Если тотемы entry IN (5178,5177,5176,5175) перемещать в Keyring, то
// пропадает иконка тотема из интерфейса, да и через Spellbook ставить тотемы
// уже нельзя; после перемещения их обратно в сумки всё восстанавливается.
MyOP(<<<EOT
UPDATE item_template SET BagFamily=BagFamily|256/*Keys*/ WHERE
 name IN ("Thieves' Tools", "Flash Powder","Blinding Powder", "Small Seaforium Charge","Large Seaforium Charge","Powerful Seaforium Charge", "Light Feather","Shiny Fish Scales","Rune of Teleportation","Rune of Portals")
 OR class=0 AND subclass=8 AND (name LIKE '% Sharpening Stone' OR name LIKE '% Weightstone' OR name LIKE '% Poison%')
 OR class=15 AND BagFamily=4 -- Soul Shard
 OR class=6 AND BagFamily IN (1,2) -- Arrows, Bullets
 OR class=0 AND subclass=0 AND spellcategory_1=1153 AND name LIKE '% Stone Statue' -- Jewelcrafting Healing statues
 OR class=0 AND subclass=4 AND spellcategory_1=1229 -- Scroll of Recall I, II, III
 OR class=2 AND subclass=20 -- all Fishing Poles
EOT
);
Logs("Keyring as special container for Thieves' Tools, Soul Shards, Arrows, Bullets etc.: %d items");

/*
// Разрешить хранить любые вещи в колчанах и мешках для пуль. Уменьшение кол-ва
// носимых вещей неприемлемо в мультиклассовой игре. Особого преимущества перед
// обычными сумками по вместительности нет. Вспомогательные персонажи низкого
// уровня не смогут использовать, скажем, Heavy Quiver вместо Runecloth Bag
// из-за требования Required Level 30.
// В отличие от WoW 1.12 в 3.3.5a нет прибавки скорости стрельбы от
// экипированного колчана, поэтому нет большого смысла пользоваться ими.
// Из-за побочного эффекта колчаны можно помещать в Mining-сумки (бит.маска 1024).
// Возможно, надо бы в ядре запретить помещение колчанов в банки.
MyOP("UPDATE item_template SET BagFamily=BagFamily|1024 WHERE class=11 AND subclass IN (2,3)");
Logs("Enable any items in Quivers and Ammo Pouches (requires .cpp patch): %d items");
*/

// Уравнять цены покупки и продажи на табарды, чтобы можно было купить поносить на время, а потом продать без потерь
MyOP("UPDATE item_template SET SellPrice=0.8*BuyPrice WHERE InventoryType=19 AND BuyPrice>0");
Logs("Equal Sell and Buy prices for tabards from vendors: %d items");

// Увеличение времени пополнения товаров
MyOP("UPDATE npc_vendor AS nv JOIN item_template AS it ON item=it.entry SET incrtime=24*3600 WHERE incrtime<24*3600 AND nv.maxcount>0 AND incrtime>0 AND NOT (class=0 AND subclass=8/*Dark Iron Ale Mug, Flares*/)");
Logs("1-day renewal period for almost all LIMITED stacks of items sold by vendors: %d items");


MyOP("UPDATE quest_template SET RequiredRaces=0 WHERE Id IN (8185,8188)"); // 
Logs("Remove race restrictions from Paladin \"Syncretist's Sigil\" and Shaman \"Vodouisant's Vigilant Embrace\" quests (NPC Zanza, ZG): %d quests");


MyOP("UPDATE item_template SET spellcategorycooldown_1=3600000 WHERE entry IN (37118,44314,44315) AND spellcategorycooldown_1 < 3600000");
// Поскольку Hearthstone восстанавливается за 2 часа (правка spell.bdc), свитки не должны быть всего лишь по 20 минут
// Если уровень свитка слишком низкий по сравнению с уровнем персонажа, то происходит перемещение в случайные поселения
Logs("Increase cooldown of Scroll of Recall I/II/III from 20 min to 1 hour: %d items");

}


function TweakQuests()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;


MyOP("UPDATE quest_template SET RequiredClasses=0 WHERE RequiredClasses!=0");
Logs("Remove quest class restrictions: %d quests"); // 1109 for WotLK SunwellCore

MyOP("UPDATE quest_template SET RequiredRaces = RequiredRaces | 0x2B2 WHERE NOT (RequiredRaces & 0x2B2) IN (0, 0x2B2); -- AND NOT Title IN (\"Seek Huntress Kella Nightbow\",\"The Hunter's Path\",\"Taming the Beast\")");
Logs("Remove Horde quest race restrictions: %d quests");

MyOP("UPDATE quest_template SET RequiredRaces = RequiredRaces | 0x44D WHERE NOT (RequiredRaces & 0x44D) IN (0, 0x44D); -- AND NOT Title IN (\"Seek the Farstriders\",\"The Hunter's Path\",\"Taming the Beast\")");
Logs("Remove Alliance quest race restrictions: %d quests");


MyOP("UPDATE quest_template SET ExclusiveGroup=0 WHERE ExclusiveGroup IN (5623, 5649)");
Logs("Non-Exclusive L4/L5 Priest quests for Alliance{3} and Horde{3}: %d quests");

MyOP("UPDATE quest_template SET ExclusiveGroup=0 WHERE ExclusiveGroup IN (1638, 1505)");
Logs("Non-Exclusive L10 Warrior quests for Alliance{4} and Horde{2}: %d quests");

MyOP("UPDATE quest_template SET ExclusiveGroup=0 WHERE ExclusiveGroup IN (2205, 1859)");
Logs("Non-Exclusive L10 Rogue quests for Alliance{3} and Horde{3}: %d quests");

MyOP("UPDATE quest_template SET ExclusiveGroup=0 WHERE ExclusiveGroup IN (1860, 1881)");
Logs("Non-Exclusive L10 Mage quests for Alliance{3} and Horde{3}: %d quests");

// Hunter, Shaman, Warlock, Druid по своим расо-зависимым заданиям получают
// новые способности, а потому нелогично делать их одновременно доступными.

MyOP("UPDATE quest_template SET ExclusiveGroup=1473 WHERE Id=9529");
Logs("Make Blood Elf Warlock L10 quest (Summon Voidwalker) exclusive with equivalent Orc and Undead quests: %d quests");

MyOP("UPDATE quest_template SET ExclusiveGroup=6061 WHERE Id IN (6061,6062,6063,6064,9484,9591); -- Taming the Beast #1/3");
Logs("Make first part of \"Taming the Beast\" quest chain exclusive for Alliance{3} and Horde{3}: %d quests");


$count = MyRUN("
UPDATE quest_template SET RewardFactionId1=509 WHERE RewardFactionId1=72  AND Title='Additional Runecloth' -- Stormwind => The League of Arathor
UPDATE quest_template SET RewardFactionId1=730 WHERE RewardFactionId1=47  AND Title='Additional Runecloth' -- Ironforge => Stormpike Guard
UPDATE quest_template SET RewardFactionId1=890 WHERE RewardFactionId1=69  AND Title='Additional Runecloth' -- Darnassus => Silverwing Sentinels
UPDATE quest_template SET RewardFactionId1=909 WHERE RewardFactionId1=54  AND Title='Additional Runecloth' -- Gnomeregan Exiles => Darkmoon Faire
UPDATE quest_template SET RewardFactionId1=889 WHERE RewardFactionId1=76  AND Title='Additional Runecloth' -- Orgrimmar => Warsong Outriders
UPDATE quest_template SET RewardFactionId1=729 WHERE RewardFactionId1=68  AND Title='Additional Runecloth' -- Undercity => Frostwolf Clan
UPDATE quest_template SET RewardFactionId1=510 WHERE RewardFactionId1=530 AND Title='Additional Runecloth' -- Darkspear Trolls => The Defilers
UPDATE quest_template SET RewardFactionId1=909 WHERE RewardFactionId1=81  AND Title='Additional Runecloth' -- Thunder Bluff => Darkmoon Faire
");
// Exodar и Silvermoon остаются "при своих"
Logs("Change Additional Runecloth donation quests Reputation to BGs and Darkmoon Faire: %d quests" );


$count = MyRUN("
UPDATE quest_template SET ExclusiveGroup = 3630 WHERE Id IN (3630,3632,3634,3635,3637);  -- Gnomish + Goblin Engineering
UPDATE quest_template SET ExclusiveGroup = 0 WHERE Id IN (3638,3640,3642);  -- 'The Pledge of Secrecy' Gnomish/Goblin quests
UPDATE quest_template SET ExclusiveGroup = 0 WHERE Id IN (5143,5148, 5144,5146, 5141,5145); -- Tribal+Elemental+Dragonscale Leatherworking
UPDATE quest_template SET ExclusiveGroup = 0 WHERE Id IN (5283,5301, 5284,5302); -- Armorsmith + Weaponsmith Blacksmithing
UPDATE quest_template SET ExclusiveGroup = 0 WHERE Id IN (5306,5305,5307); -- Master Axesmith/Hammersmith/Swordsmith
");
Logs("Make prof. specialization quests mutually non-exclusive: %d quests" );


MyOP("UPDATE quest_template SET SpecialFlags=SpecialFlags&~1 WHERE Title='The Battle for Arathi Basin!'");
Logs("Make quests \"The Battle for Arathi Basin!\" non-repeatable: %d quests");

$count = MyRUN("
DELETE FROM creature_queststarter WHERE id=15022;
DELETE FROM creature_questender   WHERE id=15022;
");
Logs("Remove quests \"Cut Arathor Supply Lines\" and \"More Resource Crates\" from Deathstalker Mortis: %d quests" );

}


function TweakOnKillReputations()
{
global $count; PrintHeader(__FUNCTION__);

MyOP("
REPLACE creature_onkill_reputation (creature_id, RewOnKillRepFaction1, MaxStanding1, RewOnKillRepValue1) VALUES
-- League of Arathor onkill Reputation
(2618,  509, 3, 10),  -- Hammerfall Peon L33-34
(2619,  509, 3, 20),  -- Hammerfall Grunt L34-35
(2733,  509, 3, 50),  -- Apothecary Jorell L36
(2621,  509, 5, 80),  -- Hammerfall Guardian L50
(15128, 509, 5, 100), -- Defiler Elite L55
(15021, 509, 5, 150), -- Deathmaster Dwire L62
(15022, 509, 5, 150), -- Deathstalker Mortis L62
(15126, 509, 5, 100), -- Rutherford Twing L55 QM
(14990, 509, 7, 50),  -- Defilers Emissary
-- Defilers onkill Reputation
(2582,  510, 3, 10),  -- Dabyrie Laborer L30-31
(2581,  510, 3, 20),  -- Dabyrie Militia L31-32
(4479,  510, 3, 30),  -- Fardel Dabyrie L33
(4481,  510, 3, 30),  -- Marcel Dabyrie L34
(4480,  510, 3, 30),  -- Kenata Dabyrie L35
(2738,  510, 4, 20),  -- Stromgarde Cavalryman L36-37
(2584,  510, 4, 20),  -- Stromgarde Defender L38-39
(2583,  510, 4, 20),  -- Stromgarde Troll Hunter L37-38
(2585,  510, 4, 20),  -- Stromgarde Vindicator L39-40
(10696, 510, 4, 20),  -- Refuge Pointe Defender L41-45
(15130, 510, 4, 20),  -- League of Arathor Elite L40
(14983, 510, 5, 150), -- Field Marshal Oslight
(14984, 510, 5, 100), -- Sergeant Maclear L62
(15127, 510, 5, 150), -- Samuel Hawke L63 QM
(14991, 510, 7, 50),  -- League of Arathor Emissary
-- Silverwing Sentinels onkill Reputation
(11656, 890, 3, 10),  -- Warsong Peon L26-27
(11682, 890, 3, 20),  -- Warsong Grunt L29-30
(12863, 890, 3, 20),  -- Warsong Runner L29
(12862, 890, 3, 20),  -- Warsong Scout L28
(11683, 890, 3, 20),  -- Warsong Shaman L28-29
(11684, 890, 3, 50),  -- Warsong Shredder L27
(11681, 890, 3, 20),  -- Horde Deforester L27
(11680, 890, 3, 20),  -- Horde Scout L26-28
(14718, 890, 3, 50),  -- Horde Laborer L26
(14717, 890, 5, 100), -- Horde Elite L55
(14781, 890, 5, 150), -- Captain Shatterskull L55
(14754, 890, 5, 100), -- Kelm Hargunth L55 QM
(15105, 890, 7, 50),  -- Warsong Emissary L30
-- Warsong Outriders onkill Reputation
(12896, 889, 3, 20),  -- Silverwing Sentinel L22-23
(12897, 889, 3, 20),  -- Silverwing Warrior L21-22
(14715, 889, 5, 100), -- Silverwing Elite L55
(14733, 889, 5, 50),  -- Sentinel Farsong L55
(14753, 889, 5, 100), -- Illiyana Moonblaze L55 QM
(15102, 889, 7, 50),  -- Silverwing Emissary L22
-- the next two can be grinded in BG even in single player
-- Stormpike Guard Reputation
(14285, 730, 4, 12), -- Frostwolf Battleguard L61
(13840, 730, 4, 15), -- Warmaster Laggrond L59
(13817, 730, 4, 10), -- Voggah Deathgrip L61
(13219, 730, 4, 10), -- Jekyll Flandring L58 QM
(15106, 730, 7, 10), -- Frostwolf Emissary L55
-- Frostwolf Clan Reputation
(14284, 729, 4, 10), -- Stormpike Battleguard L59
(16392, 729, 4, 15), -- Captain Armando Ossex L60
(13777, 729, 4, 10), -- Sergeant Durgen Stormpike L58
(13841, 729, 4, 15), -- Lieutenant Haggerdin L61
(13217, 729, 4, 10), -- Thanthaldis Snowgleam L58 QM
(15103, 729, 7, 10); -- Stormpike Emissary L55
"); // all Emissaries are Dishonorable Kills
Logs("Set onkill reputation rewards as replacement of AB, WSG and addition to AV Battlegrounds: %d creatures");


$count = 0;
$res = MyOP("SELECT entry,name,rank,minlevel,maxlevel,Health_mod,faction FROM creature_template WHERE faction IN (1214,1215,1216,1217) AND (SELECT DISTINCT map FROM creature WHERE id=entry LIMIT 1) IS NULL");
while($obj = mysql_fetch_object($res)) {
  MyOP("INSERT IGNORE creature_onkill_reputation SET creature_id=$obj->entry, RewOnKillRepFaction1=".($obj->faction >= 1216 ? 729:730).", MaxStanding1=".($obj->rank==0 ? 4 : ($obj->minlevel <= 60 ? 5 : ($obj->entry != 11948/*Vanndar Stormpike*/ && $obj->entry != 11946/*Drek'Thar*/ ? 6 : 6))).", RewOnKillRepValue1=".($obj->rank==0 ? ($obj->Health_mod < 2 ? 10:15):($obj->minlevel <= 60 ? 20:50)));
  $count += mysql_affected_rows();
}
Logs("Set onkill reputation rewards for Alterac Valley enemies: %d creatures" );


MyOP("UPDATE creature_onkill_reputation SET RewOnKillRepValue1=IF(RewOnKillRepValue1 > 0 AND RewOnKillRepValue1 <= 400, 2*RewOnKillRepValue1, RewOnKillRepValue1), RewOnKillRepValue2=IF(RewOnKillRepValue2 > 0 AND RewOnKillRepValue2 <= 400, 2*RewOnKillRepValue2, RewOnKillRepValue2)");
Logs("Apply limited 2x positive onkill_reputation gain rate: %d creatures");

}


function TweakLoot()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;


MyOP("UPDATE item_loot_template SET ChanceOrQuestChance=CASE INTERVAL(ChanceOrQuestChance,3.1,6,6.1,10,10.1,11.1) WHEN 1 then 3 WHEN 3 then 3 WHEN 5 then 6 WHEN 6 Then 10 ELSE ChanceOrQuestChance END WHERE item=34109 AND groupid=0");
Logs("Reduce chances to fish Weather-Beaten Journal 5/11/43/50% => 3/6/10%: %d loots");


MyOP("INSERT IGNORE creature_loot_template (entry,item,ChanceOrQuestChance) VALUES (12056, 17782, 0.02)");
Logs("Add Talisman of Binding Shard (legendary) as 0.02%% chance drop to Baron Geddon loot table (Molten Core): %d loots");


// ПОСТ-ОБРАБОТКА

if (! FIRST_RUN) return;

$res = MyOP("SELECT ct.entry,
 (SELECT SUM(ChanceOrQuestChance) FROM creature_loot_template WHERE entry=ct.lootid AND mincountOrRef<0 AND ChanceOrQuestChance>0) AS sumchance
 FROM creature_template AS ct WHERE ct.rank IN (2,4) AND  ct.lootid!=0 AND
  (SELECT clt.entry FROM creature_loot_template AS clt JOIN item_template AS it ON clt.item=it.entry AND mincountOrRef>0
   WHERE clt.entry=ct.lootid AND (ChanceOrQuestChance=0  OR  quality >= 3  OR  ChanceOrQuestChance>=3 AND class IN (2,4) AND (quality>=2 OR ct.minlevel<=10 AND quality=1))
   LIMIT 1) IS NULL
");
$crea_sumchance = array();
while($row = mysql_fetch_object($res))
  if ($row->sumchance !== null)  $crea_sumchance[$row->entry] = $row->sumchance;
$count = 0;
foreach($crea_sumchance AS $entry => $sumchance) {
  if ($sumchance >= 20) continue;
  MyOP(
    "UPDATE creature_loot_template SET ChanceOrQuestChance = ChanceOrQuestChance * "
    .($sumchance <= 3 ? "15" : ($sumchance <= 5 ? "10" : ($sumchance <= 8 ? "8" : "5")))
    ." WHERE entry=$entry AND mincountOrRef<0 AND ChanceOrQuestChance>0"
  );
  $count += mysql_affected_rows();
}
unset($crea_sumchance);
Logs("Ensure boosted chances for generic loot from Rare creatures without specific loot: %d loot groups" );

}


function TweakGameobjectRespawnTimes()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;


MyOP(<<<EOT
UPDATE gameobject SET spawntimesecs=spawntimesecs+3600 WHERE spawntimesecs > 0 AND spawntimesecs < 3600
AND id IN (SELECT entry FROM gameobject_template WHERE name IN (
"Burial Chest","Primitive Chest",
"Practice Lockbox","Buccaneer's Strongbox", "Waterlogged Footlocker","Battered Footlocker","Mossy Footlocker","Dented Footlocker","Scarlet Footlocker"
))
EOT
);
Logs("Increase respawn time of Footlockers (1+ hours): %d gameobjects");

MyOP(<<<EOT
UPDATE gameobject SET spawntimesecs=20*60+1+ROUND(spawntimesecs*RAND(guid))
WHERE spawntimesecs > 0 AND spawntimesecs <= 20*60 AND id IN (SELECT entry FROM gameobject_template WHERE  name IN (
"Food Crate", "Barrel of Milk", "Barrel of Melon Juice", "Barrel of Sweet Nectar",
"Half-Buried Bottle" -- might begin Quest
))
EOT
);
Logs("Increase respawn time of Food Crates etc (20 minutes minimum): %d gameobjects");

MyOP(<<<EOT
UPDATE gameobject SET spawntimesecs=IF( map IN ($GLOBALS[InstancedMaps]),
 IF(spawntimesecs < 100000, 100000+spawntimesecs, spawntimesecs),
 IF(spawntimesecs <=2*3600, 2*3600+1+ROUND(spawntimesecs*RAND(guid)), spawntimesecs) )
WHERE spawntimesecs > 0 AND id IN (SELECT entry FROM gameobject_template WHERE name IN (
"Giant Clam", "Weapon Crate", "Armor Crate",
"Battered Chest", "Tattered Chest", "Solid Chest", "Large Battered Chest", "Large Solid Chest", "Large Iron Bound Chest", "Large Mithril Bound Chest",
"Fel Iron Chest", "Adamantite Bound Chest", "Heavy Fel Iron Chest", "Bound Fel Iron Chest", "Solid Fel Iron Chest", "Bound Adamantite Chest", "Solid Adamantite Chest",
"Box of Assorted Parts", "Blacksmithing Plans", "Supply Crate", "Old Treasure Chest",
"Black Lotus",
"Muddy Churning Waters", "Jinxed Hoodoo Pile", "Hakkari Thorium Vein", "Dark Iron Deposit",
-- quest GO in instances
"Artificial Extrapolator", "Spire Spider Egg"
))
EOT
);
// в подземельях эти объекты не должны восстанавливаться вообще (выставляем слишком большое время)
Logs("Increase respawn time of Treasure Chests, unusual Resources or Quest objects (2 hours overworld/inf.instances): %d gameobjects");

MyOP(<<<EOT
UPDATE gameobject SET spawntimesecs=IF( map IN ($GLOBALS[InstancedMaps]),
 IF(spawntimesecs <  5*900, 5*IF(spawntimesecs < 900, 900, spawntimesecs), spawntimesecs),
 IF(spawntimesecs <=2*3600, 2*3600+1+ROUND(spawntimesecs*RAND(guid)), spawntimesecs))
WHERE spawntimesecs > 0 AND id IN (SELECT entry FROM gameobject_template WHERE name IN (
"Floating Debris", "Floating Wreckage", "Schooner Wreckage", "Waterlogged Wreckage", "Bloodsail Wreckage",
"Copper Vein", "Tin Vein", "Silver Vein", "Ooze Covered Silver Vein", "Iron Deposit", "Ooze Covered Iron Deposit", "Gold Vein", "Ooze Covered Gold Vein", "Mithril Deposit", "Ooze Covered Mithril Deposit", "Small Thorium Vein", "Ooze Covered Thorium Vein", "Rich Thorium Vein", "Ooze Covered Rich Thorium Vein", "Truesilver Deposit", "Ooze Covered Truesilver Deposit",
"Fel Iron Deposit", "Adamantite Deposit", "Rich Adamantite Deposit", "Khorium Vein", "Nethercite Deposit",
"Cobalt Deposit", "Rich Cobalt Deposit", "Saronite Deposit", "Rich Saronite Deposit", "Pure Saronite Deposit", "Titanium Vein",
"Peacebloom", "Silverleaf", "Earthroot", "Mageroyal", "Swiftthistle", "Bloodthistle", "Briarthorn", "Stranglekelp", "Bruiseweed", "Wild Steelbloom", "Grave Moss", "Kingsblood", "Liferoot", "Fadeleaf", "Goldthorn", "Khadgar's Whisker", "Wintersbite", "Firebloom", "Purple Lotus", "Arthas' Tears", "Sungrass", "Blindweed", "Ghost Mushroom", "Gromsblood", "Golden Sansam", "Dreamfoil", "Mountain Silversage", "Plaguebloom", "Icecap",
"Cleansed Songflower", "Cleansed Windblossom", "Cleansed Night Dragon", "Cleansed Whipper Root",
"Blue Power Crystal", "Green Power Crystal", "Red Power Crystal", "Yellow Power Crystal", "Un'Goro Dirt Pile",
"Full Jug",
"Takk's Nest", -- not in Classic
-- Alliance overworld quest GO
"Sack of Oats", "Mathystra Relic", "Incendicite Mineral Vein", "Wildkin Feather", "Thaurissan Relic", "Moontouched Feather",
-- Horde overworld quest GO
"Gnomish Toolbox", "Tainted Soil Sample", "Tirisfal Pumpkin", "Stolen Supply Sack", "Taillasher Eggs", "Ju-Ju Heap", "Gaea Seed", "Gaea Dirt Mound", "Giant Softshell Clam", "Horde Supply Crate", "Laden Mushroom", "Tool Bucket", "Troll Chest",
"Unstable Mana Crystal Crate", "Weapon Container", "Captain Kelisendra's Cargo", "Glistening Mud", -- not in Classic
-- Neutral overworld quest GO
"Sack of Meat", "Gahz'ridian", "Azsharite Formation", "Small Lockbox", "Volcanic Ash", "Rocket Car Rubble", "Calcified Elven Gem", "Deepmoss Eggs",
"Zeppelin Cargo", "Ogre Remains" -- not in Classic
)
OR type=25 -- any fishing school / wreckage / etc.
)
EOT
);
// есть много по 1 минуте и 3 минуты, что слишком мало
Logs("Increase respawn time of resources and quest GO (2 hours overworld/x5 instances): %d gameobjects");

}


function TweakCreatureAllocation()
{
global $count; PrintHeader(__FUNCTION__);

// Увеличить кол-во существ, чтобы их было достаточно для выполнения заданий без ожидания возрождения

MyOP("UPDATE creature SET id=1023 WHERE guid IN (10968,11031) AND id=1022");
Logs("Convert 2 Mottled Scytheclaw to Mottled Razormaw (14+9 => 12+11; 11 required for quest): %d guids");

MyOP("UPDATE creature SET id=2240 WHERE guid IN (16756) AND id=2241");
Logs("Convert 1 Syndicate Thief to Syndicate Footpad (12 required for quest): %d guids");

MyOP("UPDATE creature SET id=4025 WHERE guid IN (31913) AND id=4026");
Logs("Convert 1 Bloodfury Windcaller to Bloodfury Ambusher (7 required for quest): %d guids");


MyOP("UPDATE creature_template SET flags_extra=flags_extra&~2 WHERE entry IN (80)");
Logs("Fix/remove wrong NO_AGGRO flag from Kobold Laborer: %d creatures");


if (IsNotRepack("Sunwell")) return;


// Сделать враждебными часть существ в стартовых зонах
MyOP("UPDATE creature_template SET faction=14 WHERE entry IN (
-- Blood Elf
15372, -- Springpaw Lynx -- имя отображается красным, но не нападает, т.к. NO_AGGRO
15294, -- Feral Tender
15273, -- Arcane Wraith
15298, -- Tainted Arcane Wraith
15367, -- Felendren the Banished
   -- 15649, -- Feral Dragonhawk Hatchling -- есть рядом со стражниками
-- Undead
1513, -- Mangy Duskbat
1509, -- Ragged Scavenger
1919, -- Samuel Fipps
1918, -- Karrel Grayves
1917, -- Daniel Ulfman
1916, -- Stephen Bhartec
1506, -- Scarlet Convert
1507, -- Scarlet Initiate
1667, -- Meven Korgal
1504, -- Young Night Web Spider
1505, -- Night Web Spider
1688, -- Night Web Matriarch
-- Orc, Troll
3124, -- Scorpid Worker
3101, -- Vile Familiar
3102, -- Felstalker
3281, -- Sarkoth
-- Tauren
2961, -- Mountain Cougar
2966, -- Battleboar
2952, -- Bristleback Quilboar
2953, -- Bristleback Shaman
2954, -- Bristleback Battleboar
3229, -- 'Squealer' Thornmantle
8554, -- Chief Sharptusk Thornmantle
-- Draenei
16537, -- Mutated Owlkin
16517, -- Mutated Root Lasher
16516, -- Volatile Mutation
-- Night Elf
1989, -- Grellkin
-- Human
257, -- Kobold Worker
80, -- Kobold Laborer
38, -- Defias Thug
103, -- Garrick Padfoot
-- Dwarf, Gnome
724, -- Burly Rockjaw Trogg
706, -- Frostmane Troll Whelp
808 -- Grik'nir the Cold
) ");
Logs("Make some creatures Hostile in starting zones: %d creatures");

}


function TweakCreatureRespawnTimes()
{
global $count; PrintHeader(__FUNCTION__);

MyOP("UPDATE creature SET spawntimesecs=IF(spawntimesecs<100000,spawntimesecs+100000,spawntimesecs) WHERE map IN (33,34,36,43,47,48,70,90,109,129,189,209,229,230,269,289,329,349,389,429,540,542,543,545,546,547,552,553,554,555,556,557,558,560,574,575,576,578,585,595,599,600,601,602,604,608,619,632,650,658,668) AND (SELECT type FROM creature_template WHERE entry=id) IN (1,2,3,4,5,6,7,9,10) AND NOT id IN (3678/*Disciple of Naralex*/)");
Logs("Increase respawn times in 5-man Instances: %d creatures");

MyOP("UPDATE creature SET spawntimesecs=IF(spawntimesecs< 10000,spawntimesecs+ 10000,spawntimesecs) WHERE map IN (249,309,409,469,509,531,532,533,534,544,548,550,564,565,568,580,603,615,616,624,631,649,724) AND (SELECT type FROM creature_template WHERE entry=id) IN (1,2,3,4,5,6,7,9,10)");
Logs("Increase respawn times in Raid Instances: %d creatures");


if (IsNotRepack("Sunwell")) return;

MyOP("UPDATE creature JOIN creature_template ON entry=id SET spawntimesecs=14*24*60*60 WHERE entry IN (14454/*The Windreaver*/, 14457/*Princess Tempestria*/, 14461/*Baron Charr*/, 14464/*Avalanchion*/) AND spawntimesecs > 0");
// Если поддерживается сдвиг времён восстановления при запуске, надо ставить 7 дней, иначе 14 дней
Logs("Increase respawn time of 4 leaders of Elemental Invasions, ~2-3 days => 14 days: %d guids");


MyOP("UPDATE creature JOIN creature_template ON entry=id SET spawntimesecs=ROUND(24 + 24*RAND(guid))*IF(id = 14479/*Twilight Lord Everun*/, 3600/10, 3600) WHERE rank in (2,4) AND spawntimesecs < 24*3600 AND spawntimesecs>0");
Logs("Respawn time 24..48 hours for classic Rare creatures: %d guids");

MyOP("UPDATE creature JOIN creature_template ON entry=id SET spawntimesecs=ROUND(10 + 6*RAND(guid))*3600 WHERE RacialLeader!=0 AND spawntimesecs < 10*3600 AND spawntimesecs>0");
Logs("Respawn time 10..16 hours for Racial Leaders (high rank Honor farm limit): %d guids");

MyOP("UPDATE creature JOIN creature_template ON entry=id SET spawntimesecs=ROUND(22 + 2*RAND(guid))*3600 WHERE entry IN (5319,5317,5320,5312,12497, 12475,12476,12474,5314,12498, 12479,12478,12477,5718,12496) AND spawntimesecs < 22*3600 AND spawntimesecs>0");
Logs("Respawn time 22..24 hours for minion dragons around Nightmare Portals (Hinterlands,Ashenvale,Feralas): %d guids");

}


function TweakCreatureDmgHP()
{
global $count; PrintHeader(__FUNCTION__);

if (IsNotRepack("Sunwell")) return;
if (! FIRST_RUN) return;

$pet_entries = array();
$res = MYOP("SELECT DISTINCT creature_entry FROM pet_levelstats");
while($obj = mysql_fetch_object($res))  $pet_entries[] = $obj->creature_entry;


$res = MyOP("SELECT DISTINCT id,map FROM creature ORDER BY map ASC");

while($obj = mysql_fetch_object($res)) {
  if (isset($crea_map[$obj->id])) {
      $cname = MyVAL("SELECT name FROM creature_template WHERE entry=$obj->id AND NOT (flags_extra & 128) AND NOT (unit_flags IN (0x82040300)) AND (type!=8/*critter*/ OR Health_mod > 1)");
      if ($cname !== null)
         echo "WARNING! Creature \"$cname\" collision for maps ".$crea_map[$obj->id]." and $obj->map\n";
  }
  $crea_map[$obj->id] = $obj->map;
}


$res = MyOP("
  SELECT entry,name,rank,mindmg,maxdmg,minrangedmg,maxrangedmg,Health_mod,minlevel,maxlevel
  FROM creature_template
  WHERE NOT (flags_extra & 128) AND NOT (unit_flags IN (0x82040300))
  ORDER BY name ASC
");
// ORDER BY (mindmg+maxdmg)/2/maxlevel ASC
// ... and (mindmg+maxdmg)/2/IF(minlevel<maxlevel,maxlevel,minlevel) > 5

$nTotal = 0;
$nTweaked = 0;

while($obj = mysql_fetch_object($res)) {

++$nTotal;

$health_div = 1;
$dmg_div = 1;
$map = isset($crea_map[$obj->entry]) ? $crea_map[$obj->entry] : -1;

if (in_array($obj->entry, array(
    7846/*Teremus the Devourer*/,1284/*Archbishop Benedictus*/,12126/*Lord Tirion Fordring*/,14941/*High Priestess Jeklik Transform Visual*/,15382/*Fandral Staghelm(not used)*/,15410/*Anachronos Dragon Form*/,15411/*Arygos Dragon Form*/,15412/*Caelestrasz Dragon Form*/,15413/*Merithra Dragon Form*/,15427/*Merithra's Wake*/,15507/*Buru the Gorger Transform Visual*/,15633/*Tyrande(not used)*/,16387/*Atiesh*/,
    11447/*Mushgog*/,11497/*The Razza*/,11498/*Skarr the Unbreakable*/,
    5764/*Guardian of Blizzard*/,10942/*Nessy*/
    )))
    // неизменяемые существа: 1) ранга BOSS, 2) RareElite, 3) прочие
    continue;
elseif (in_array($map, array(33,34,36,43,47,48,70,90,109,129,189,209,230,269,289,329,349,389,429,540,542,543,545,546,547,552,553,554,555,556,557,558,560,574,575,576,578,585,595,599,600,601,602,604,608,619,632,650,658,668, 229))
        or in_array($obj->entry, array(
        11121/*Black Guard Swordsmith*/,10813/*Balnazzar*/,10439/*Ramstein the Gorger*/,
        1853/*Darkmaster Gandling*/,
        16042/*Lord Valthalak*/,10339/*Gyth*/,10429/*Warchief Rend Blackhand*/,15776/*Christmas Warchief Rend Blackhand*/,15796/*Christmas Goraluk Anvilcrack*/
       ))) {
    // 5-man dungeons incl. Blackrock Spire(229)
    continue;
}
elseif (in_array($map, array(532,568))) { // 10-man TBC raids (Karazhan, Zul'Aman)
    $health_div = ($obj->rank == 3) ?  2 : 1;
    $dmg_div    = ($obj->rank == 3) ?  2 : 1;
    printf("raid(10) %s: %s\n", rankstr($obj->rank), $obj->name);
}
elseif (in_array($map, array(309,509))
        or in_array($obj->entry, array(
        14515/*High Priestess Arlokk*/ /*,15101 Zulian Prowler*/ /*,15068 Zulian Guardian*/,14986/*Shade of Jin'do*/,14988/*Ohgan*/,15082/*Gri'lek*/,15083/*Hazza'rah*/,15084/*Renataki*/,15085/*Wushoolay*/,15114/*Gahz'ranka*/,15041/*Spawn of Mar'li*/,14965/*Frenzied Bloodseeker Bat*/,14884/*Parasitic Serpent*/,15146/*Mad Voidwalker*/,
        15934/*Hive'Zara Hornet*/,15521/*Hive'Zara Hatchling*/,/*15555 Hive'Zara Larva,*/ 15527/*Mana Fiend*/
        )) ) {
    // 20-man Classic raids (Zul'Gurub, AQ20 Ruins of Ahn'Qiraj)
    $health_div = ($obj->rank == 3) ?  4 : 1;
    $dmg_div    = ($obj->rank == 3) ?  2 : 2;
    printf("raid(20) %s: %s\n", rankstr($obj->rank), $obj->name);
}
elseif (in_array($map, array(534,544,548,550,564,565,580))) { // 25-man TBC raids
    $health_div = ($obj->rank == 3) ?  5 : 2;
    $dmg_div    = ($obj->rank == 3) ?  3 : 2;
    printf("raid(25) %s: %s\n", rankstr($obj->rank), $obj->name);
}
elseif (in_array($map, array(249,409,469,531,533)) or in_array($obj->entry, array(
        11262/*Onyxian Whelp*/,
        12018/*Majordomo Executus*/,11502/*Ragnaros*/,12265/*Lava Spawn*/,12143/*Son of Flame*/,
        11583/*Nefarian*/,14101/*Enraged Felguard*/, 14261/*Blue Drakonid*/,14262/*Green Drakonid*/,14263/*Bronze Drakonid*/,14264/*Red Drakonid*/,14265/*Black Drakonid*/,14302/*Chromatic Drakonid*/,14605/*Bone Construct*/,
        15517/*Ouro*/,15630/*Spawn of Fankriss*/,15622/*Vekniss Borer*/,15621/*Yauj Brood*/,
        15989/*Sapphiron*/,16775/*Spirit of Mograine*/,16776/*Spirit of Blaumeux*/,16777/*Spirit of Zeliek*/,16778/*Spirit of Korth'azz*/,16441/*Guardian of Icecrown*/,16783/*Plague Slime (Blue)*/,16784/*Plague Slime (Red)*/,16785/*Plague Slime (Green)*/,16127/*Spectral Trainee*/,16148/*Spectral Deathknight*/,16149/*Spectral Horse*/,16150/*Spectral Rider*/,16124/*Unrelenting Trainee*/,16125/*Unrelenting Deathknight*/,16126/*Unrelenting Rider*/,
        15302/*Shade of Taerar*/ /*,15260 Demented Druid Spirit*/
       ))) {
    // 40-man Classic raids (Onyxia, MC, BWL, AQ40, Naxxramas)
    $health_div = ($obj->rank == 3) ? 10 : 5;
    $dmg_div    = ($obj->rank == 3) ?  3 : 2;
    printf("raid(40) %s: %s\n", rankstr($obj->rank), $obj->name);
}
elseif (in_array($obj->entry, array(11664/*Flamewaker Elite*/,11663/*Flamewaker Healer*/) )) {
    // 40-man Classic raids - weaken too strong
    $health_div = 10;
    $dmg_div    = 2;
    printf("raid(40) further weaken halving HP %s: %s\n", rankstr($obj->rank), $obj->name);
}
elseif (in_array($map, array(603,615,616,624,631,649,724))) { // 10/25-man WotLK raids
    $health_div = ($obj->rank == 3) ?  4 : 2;
    $dmg_div    = ($obj->rank == 3) ?  2 : 1;
    printf("raid(10/25) %s: %s\n", rankstr($obj->rank), $obj->name);
}
elseif (in_array($obj->entry, $pet_entries)) {
    $dmg_div = 0.5;
    echo "pet dmg-boost: $obj->name\n";
}
elseif ($map == -1 and in_array($obj->entry, array(14460,14462,14458,14455 /*elemental invaders*/,
        698/*Bloodscalp Tiger*/,756/*Skullsplitter Panther*/,10979/*Scarlet Hound*/,6412/*Skeleton[by Sylvanas]*/))) {
    $dmg_div = 0.5;
    echo "mapless dmg-boost: $obj->name\n";
}
elseif ($map == -1) {
    if ($obj->rank != 3 or $obj->maxlevel < 60 or $obj->Health_mod < 7)
        continue;

    printf("mapless %s: %s, HP* %.3f", rankstr($obj->rank), $obj->name, $obj->Health_mod);
    if ($obj->Health_mod > 10)  {
        $health_div = $obj->Health_mod / (10 + sqrt($obj->Health_mod-10));
        printf(" =>%.3f", $obj->Health_mod / $health_div);
    }
    if (!in_array($obj->entry, array(
        15305/*Lord Skwol*/,15204/*High Marshal Whirlaxis*/,15203/*Prince Skaldrenox*/,15205/*Baron Kazum*/,
        14435/*Prince Thunderaan*/
        ))) {
        $dmg_div = 2;
        $avdmg = ($obj->mindmg + $obj->maxdmg)/2;
        printf("  DMG %d => %d", $avdmg, $avdmg / $dmg_div);
    }
    echo "\n";
}
elseif (in_array($obj->rank, array(0,2,4)) and $obj->maxdmg < 20*$obj->maxlevel) {
    // 1) удвоить урон от несильных статических неэлитных существ в
    // верхнем мире, но так, что оно всё равно остаётся меньше, чем от элитных;
    // также и количество жизни у них по-прежнему меньше
    // 2) удвоить урон от Rare и Rare Elite существ; поскольку многие
    // неэлитные Rare обладают повышенными показателями, то они могут стать
    // сильнее регулярных элитных
    $dmg_div = 0.5;
    echo "overworld dmg-boost: $obj->name\n";
}
elseif ($obj->rank == 3 or $obj->Health_mod > 20) { // overworld Boss or Boss-like uber-Elite
    printf("overworld %s: %s, HP* %d", $obj->rank==3 ? "BOSS":"BOSS-LIKE", $obj->name, $obj->Health_mod);
    if ($obj->Health_mod > 20) {
        $health_div = $obj->Health_mod / (20 + sqrt($obj->Health_mod-20));
        printf(" =>%d", $obj->Health_mod / $health_div);
    }
    if ($obj->rank == 3 and !in_array($obj->entry, array(
       15192/*Anachronos*/,
       3516/*Arch Druid Fandral Staghelm*/,7937/*High Tinker Mekkatorque*/,1748/*Highlord Bolvar Fordragon*/,2784/*King Magni Bronzebeard*/,7999/*Tyrande Whisperwind*/,
       1284/*Archbishop Benedictus*/,4968/*Lady Jaina Proudmoore*/,
       3057/*Cairne Bloodhoof*/,10181/*Lady Sylvanas Windrunner*/,4949/*Thrall*/,10540/*Vol'jin*/,
       )))
        $dmg_div = 2;
    echo "\n";
}
else continue;

$affected = 0;

$obj->Health_mod /= $health_div;

/*
// изменённые значения величин урона приходилось записывать в БД раньше,
// а теперь в cMangos-ядре dmg_multiplier трактуется как универсальный
// множитель для наносимого существами физического и магического урона
$obj->mindmg = max(1, intval($obj->mindmg / $dmg_div));
$obj->maxdmg = max(1, intval($obj->maxdmg / $dmg_div));
$obj->minrangedmg = max(1, intval($obj->minrangedmg / $dmg_div));
$obj->maxrangedmg = max(1, intval($obj->maxrangedmg / $dmg_div));
*/

MyOP("
 UPDATE creature_template
 SET Health_mod=$obj->Health_mod,
     dmg_multiplier=1.0/$dmg_div /* mindmg=$obj->mindmg,maxdmg=$obj->maxdmg, minrangedmg=$obj->minrangedmg,maxrangedmg=$obj->maxrangedmg */,
     mingold=mingold/$health_div, maxgold=maxgold/$health_div
 WHERE entry=$obj->entry
");
$affected += mysql_affected_rows();

if ($affected > 0)  ++$nTweaked;

}
Logs("%d of %d creatures tweaked", $nTweaked, $nTotal);

}


///////////////////////// MAIN CODE BLOCK

$countTotal = 0;

FixGeneral();
FixGameobjects();
FixGameobjectAllocation();
FixQuests();
FixLoot();
FixCreatures();
FixMissingCreatures();
FixAndTweakJeutie();
RevertToClassic();
RevertToTBC();
TweakGeneral();
TweakItems();
TweakQuests();
TweakOnKillReputations(); // репутация за BG-фракции в WotLK (vs Classic) утрачивает смысл, т.к. вещи продаются за Honor
TweakLoot();
TweakGameobjectRespawnTimes();
TweakCreatureAllocation();
TweakCreatureRespawnTimes();
TweakCreatureDmgHP();

printf("\nPatches {%d} applied in %.2f seconds\n", $countTotal, microtime(true) - $startTime);
// Поиск ненулевых исходов (?<!:): (?=[1-9])

?>
