diff options
23 files changed, 5713 insertions, 1815 deletions
diff --git a/sql/updates/world/2012_02_21_00_world_conditions.sql b/sql/updates/world/2012_02_21_00_world_conditions.sql new file mode 100644 index 00000000000..54685868186 --- /dev/null +++ b/sql/updates/world/2012_02_21_00_world_conditions.sql @@ -0,0 +1,3592 @@ +CREATE TABLE `temp_convert_spells` +( + `id` INT(11), + `effMask` INT(11), + `onlyPlayers` TINYINT(3), + PRIMARY KEY (`id`) +); + +INSERT INTO `temp_convert_spells` VALUES +(46174,1,0), +(78002,1,1), +(78001,1,1), +(78000,1,1), +(77999,1,1), +(77984,1,1), +(76379,1,0), +(76098,1,0), +(76092,1,0), +(75920,1,1), +(75767,1,1), +(75765,1,1), +(75396,1,0), +(75389,1,1), +(75364,1,0), +(75319,1,0), +(75313,1,0), +(75244,1,0), +(75197,1,0), +(75195,1,0), +(75181,1,0), +(75107,1,0), +(75100,1,0), +(75078,1,0), +(75053,1,0), +(75018,1,0), +(74977,1,0), +(74903,1,0), +(74801,1,1), +(74758,1,0), +(74735,1,0), +(74549,1,0), +(74548,1,0), +(74486,1,0), +(74455,1,0), +(74444,1,0), +(74313,1,0), +(74285,1,0), +(74219,1,0), +(74182,1,0), +(74148,1,0), +(74098,1,0), +(74090,1,1), +(74086,1,1), +(74074,1,0), +(74033,1,0), +(73980,1,0), +(73955,1,0), +(73953,1,0), +(73886,1,0), +(73846,1,1), +(73845,1,1), +(73844,1,1), +(73843,1,1), +(73837,1,0), +(73836,1,0), +(73835,1,0), +(73787,1,0), +(73786,1,0), +(73785,1,0), +(73725,1,0), +(73659,1,0), +(73650,1,1), +(73582,1,0), +(73556,1,0), +(73555,1,0), +(73548,1,0), +(73331,1,1), +(73288,1,0), +(73165,1,0), +(73164,1,1), +(73159,1,1), +(73129,1,0), +(73128,1,0), +(73082,1,0), +(73071,1,0), +(73035,1,0), +(72959,1,1), +(72934,1,1), +(72928,1,1), +(72900,1,1), +(72830,1,1), +(72748,1,0), +(72747,1,0), +(72746,1,0), +(72745,1,0), +(72728,1,0), +(72706,1,1), +(72618,1,0), +(72595,1,1), +(72527,1,0), +(72479,1,1), +(72431,1,1), +(72429,1,1), +(72401,1,0), +(72347,1,0), +(72346,1,1), +(72280,1,0), +(72279,1,0), +(72278,1,0), +(72262,1,0), +(72260,1,0), +(72257,1,1), +(72209,1,0), +(72202,1,0), +(72099,1,0), +(72033,1,0), +(72032,1,0), +(72031,1,0), +(71952,1,0), +(71949,1,1), +(71948,1,0), +(71946,1,0), +(71848,1,0), +(71811,1,0), +(71809,1,0), +(71753,1,1), +(71693,1,0), +(71620,1,0), +(71617,1,0), +(71599,1,0), +(71538,1,1), +(71536,1,1), +(71520,1,0), +(71440,1,0), +(71415,1,0), +(71412,1,0), +(71365,1,0), +(71352,1,1), +(71322,1,0), +(71310,1,0), +(71308,1,0), +(71306,1,0), +(71281,1,0), +(71272,1,0), +(71189,1,0), +(71082,1,0), +(71081,1,0), +(71080,1,0), +(71079,1,0), +(71078,1,0), +(71075,1,0), +(71070,1,0), +(71032,1,0), +(71024,1,0), +(70995,1,0), +(70983,1,0), +(70966,1,1), +(70939,1,0), +(70936,1,0), +(70933,1,0), +(70931,1,0), +(70921,1,0), +(70881,1,0), +(70861,1,0), +(70860,1,0), +(70859,1,0), +(70858,1,0), +(70857,1,0), +(70856,1,0), +(70792,1,0), +(70790,1,0), +(70784,1,0), +(70781,1,0), +(70743,1,0), +(70713,1,1), +(70643,1,0), +(70639,1,0), +(70638,1,1), +(70636,1,1), +(70635,1,0), +(70623,1,1), +(70614,1,0), +(70611,1,0), +(70602,1,0), +(70595,1,0), +(70588,1,0), +(70586,1,0), +(70572,1,0), +(70569,1,0), +(70527,1,1), +(70525,1,0), +(70488,1,0), +(70485,1,0), +(70471,1,0), +(70466,1,0), +(70464,1,0), +(70444,1,0), +(70443,1,1), +(70403,1,0), +(70397,1,0), +(70383,1,0), +(70374,1,0), +(70366,1,0), +(70360,1,0), +(70338,1,0), +(70331,1,1), +(70299,1,0), +(70293,1,0), +(70290,1,0), +(70267,1,0), +(70266,1,0), +(70265,1,0), +(70246,1,0), +(70225,1,0), +(70224,1,0), +(70143,1,0), +(70130,1,0), +(70104,1,0), +(70100,1,0), +(70098,1,0), +(70079,1,0), +(70078,1,0), +(70053,1,0), +(70041,1,0), +(70040,1,0), +(70021,1,0), +(69960,1,0), +(69959,1,0), +(69922,1,0), +(69907,1,0), +(69886,1,0), +(69857,1,0), +(69843,1,0), +(69801,1,0), +(69798,1,0), +(69796,1,0), +(69784,1,0), +(69782,1,0), +(69768,1,0), +(69753,1,0), +(69705,1,0), +(69682,1,0), +(69614,1,0), +(69610,1,0), +(69601,1,0), +(69600,1,0), +(69593,1,0), +(69553,1,0), +(69538,1,0), +(69508,1,0), +(69431,1,0), +(69372,1,0), +(69347,1,0), +(69298,1,1), +(69171,1,0), +(69125,1,0), +(69101,1,0), +(69098,1,0), +(69097,1,0), +(69048,1,1), +(69039,1,0), +(69016,1,0), +(68957,1,0), +(68922,1,0), +(68919,1,0), +(68901,1,0), +(68881,1,0), +(68880,1,0), +(68861,1,0), +(68847,1,0), +(68842,1,0), +(68798,1,0), +(68663,1,0), +(68644,1,0), +(68617,1,0), +(68616,1,0), +(68614,1,0), +(68515,1,1), +(68471,1,1), +(68470,1,1), +(68401,1,0), +(68400,1,0), +(68360,1,0), +(68359,1,0), +(68358,1,0), +(68206,1,1), +(68198,1,1), +(68197,1,1), +(68193,1,1), +(68186,1,1), +(67888,1,0), +(67864,1,0), +(67857,1,0), +(67856,1,0), +(67855,1,0), +(67804,1,0), +(67757,1,0), +(67756,1,0), +(67755,1,0), +(67748,1,0), +(67732,1,0), +(67715,1,0), +(67705,1,0), +(67551,1,1), +(67547,1,0), +(67482,1,0), +(67400,1,0), +(67397,1,0), +(67369,1,0), +(67335,1,0), +(67328,1,0), +(67163,1,0), +(67162,1,0), +(67161,1,0), +(67160,1,0), +(67159,1,0), +(67158,1,0), +(66986,1,1), +(66810,1,1), +(66798,1,0), +(66785,1,0), +(66774,1,0), +(66718,1,1), +(66665,1,0), +(66637,1,0), +(66636,1,0), +(66630,1,0), +(66551,1,0), +(66550,1,0), +(66513,1,0), +(66512,1,0), +(66508,1,0), +(66401,1,0), +(66391,1,0), +(66390,1,0), +(66387,1,0), +(66386,1,0), +(66385,1,0), +(66384,1,0), +(66383,1,0), +(66382,1,0), +(66379,1,0), +(66357,1,0), +(66356,1,0), +(66355,1,0), +(66354,1,0), +(66353,1,0), +(66352,1,0), +(66350,1,0), +(66349,1,0), +(66348,1,0), +(66345,1,0), +(66339,1,0), +(66332,1,0), +(66314,1,1), +(66312,1,1), +(66287,1,0), +(66256,1,0), +(66193,1,0), +(66181,1,0), +(66153,1,0), +(66152,1,0), +(66141,1,0), +(66140,1,0), +(66135,1,1), +(66133,1,0), +(66132,1,0), +(65872,1,0), +(65861,1,0), +(65719,1,0), +(65718,1,0), +(65699,1,0), +(65685,1,0), +(65652,1,0), +(65614,1,0), +(65613,1,0), +(65611,1,0), +(65594,1,1), +(65589,1,0), +(65588,1,0), +(65587,1,0), +(65509,1,0), +(65357,1,0), +(65354,1,0), +(65350,1,0), +(65349,1,0), +(65346,1,1), +(65312,1,1), +(65311,1,1), +(65265,1,0), +(65258,1,0), +(65238,1,0), +(65224,1,0), +(65206,1,0), +(65200,1,0), +(65192,1,0), +(65184,1,1), +(65140,1,0), +(65109,1,0), +(65061,1,0), +(65042,1,0), +(65040,1,1), +(65034,1,0), +(65016,1,0), +(65015,1,0), +(64996,1,0), +(64995,1,0), +(64898,1,0), +(64887,1,0), +(64886,1,0), +(64880,1,0), +(64828,1,0), +(64799,1,0), +(64767,1,0), +(64623,1,0), +(64620,1,0), +(64619,1,0), +(64618,1,0), +(64597,1,0), +(64543,1,0), +(64539,1,0), +(64503,1,0), +(64499,1,0), +(64480,1,0), +(64475,1,0), +(64474,1,0), +(64466,1,0), +(64465,1,0), +(64463,1,0), +(64449,1,0), +(64444,1,0), +(64425,1,0), +(64414,1,0), +(64402,1,0), +(64397,1,0), +(64320,1,0), +(64229,1,0), +(64225,1,0), +(64224,1,0), +(64201,1,0), +(64185,1,0), +(64184,1,0), +(64183,1,0), +(64173,1,0), +(64172,1,0), +(64098,1,0), +(64069,1,0), +(64063,1,0), +(64061,1,0), +(64059,1,1), +(64032,1,0), +(64031,1,0), +(64030,1,0), +(64029,1,0), +(64028,1,0), +(64027,1,0), +(64026,1,0), +(64025,1,0), +(64024,1,0), +(64014,1,0), +(63984,1,0), +(63979,1,0), +(63947,1,0), +(63886,1,0), +(63882,1,0), +(63820,1,0), +(63813,1,0), +(63812,1,0), +(63764,1,0), +(63763,1,0), +(63762,1,0), +(63761,1,0), +(63749,1,0), +(63747,1,1), +(63745,1,1), +(63744,1,0), +(63702,1,0), +(63676,1,0), +(63659,1,0), +(63658,1,0), +(63657,1,0), +(63629,1,0), +(63628,1,0), +(63576,1,0), +(63524,1,0), +(63499,1,0), +(63446,1,0), +(63445,1,0), +(63444,1,0), +(63443,1,0), +(63442,1,0), +(63441,1,0), +(63440,1,0), +(63439,1,0), +(63438,1,0), +(63352,1,0), +(63348,1,0), +(63322,1,1), +(63274,1,0), +(63255,1,0), +(63238,1,0), +(63109,1,0), +(63037,1,0), +(63013,1,0), +(63001,1,0), +(62990,1,0), +(62978,1,0), +(62976,1,0), +(62943,1,0), +(62911,1,0), +(62909,1,0), +(62906,1,0), +(62888,1,0), +(62883,1,0), +(62882,1,0), +(62834,1,0), +(62809,1,0), +(62797,1,1), +(62778,1,0), +(62731,1,0), +(62727,1,0), +(62711,1,0), +(62708,1,0), +(62706,1,0), +(62701,1,0), +(62669,1,0), +(62646,1,0), +(62603,1,0), +(62584,1,0), +(62577,1,0), +(62567,1,0), +(62533,1,0), +(62525,1,0), +(62524,1,0), +(62521,1,0), +(62509,1,0), +(62505,1,0), +(62496,1,0), +(62488,1,0), +(62485,1,0), +(62484,1,0), +(62483,1,0), +(62480,1,0), +(62464,1,0), +(62378,1,0), +(124,1,0), +(2222,1,0), +(3730,1,0), +(4020,1,0), +(4338,1,0), +(5249,1,0), +(5251,1,0), +(5432,1,0), +(5555,1,0), +(6636,1,0), +(6672,1,0), +(6755,1,0), +(6955,1,0), +(6967,1,0), +(7022,1,0), +(7035,1,0), +(7036,1,0), +(7277,1,0), +(7393,1,0), +(7670,1,0), +(7769,1,0), +(8283,1,0), +(8593,1,0), +(8596,1,0), +(9002,1,0), +(9003,1,0), +(9004,1,0), +(9012,1,0), +(9082,1,0), +(9095,1,0), +(9455,1,0), +(9457,1,0), +(9712,1,0), +(9976,1,0), +(10113,1,0), +(10137,1,0), +(10252,1,0), +(10258,1,0), +(10259,1,0), +(10260,1,0), +(10345,1,0), +(10604,1,0), +(10727,1,0), +(10747,1,0), +(11195,1,0), +(11402,1,0), +(11440,1,0), +(11513,1,0), +(11637,1,0), +(11757,1,0), +(11893,1,0), +(12134,1,0), +(12158,1,0), +(12159,1,0), +(12347,1,0), +(12512,1,0), +(12564,1,0), +(12613,1,0), +(12623,1,0), +(12699,1,0), +(12709,1,0), +(12774,1,0), +(12938,1,0), +(13461,1,0), +(13727,1,0), +(13821,1,0), +(13951,1,0), +(13982,1,0), +(14250,1,0), +(14292,1,0), +(14806,1,0), +(14813,1,0), +(14928,1,0), +(15252,1,0), +(15281,1,0), +(15591,1,0), +(15658,1,0), +(15746,1,0), +(15958,1,0), +(16007,1,0), +(16032,1,0), +(16037,1,0), +(16053,1,0), +(16068,1,0), +(16069,1,0), +(16070,1,0), +(16074,1,0), +(16378,1,0), +(16381,1,0), +(16404,1,0), +(16556,1,0), +(16558,1,0), +(16637,1,0), +(16786,1,0), +(16807,1,0), +(17048,1,0), +(17166,1,0), +(17190,1,0), +(17202,1,0), +(17272,1,0), +(17278,1,0), +(17279,1,0), +(17471,1,0), +(17536,1,0), +(17616,1,0), +(17618,1,0), +(17652,1,0), +(17671,1,0), +(17675,1,0), +(17676,1,0), +(17677,1,0), +(17678,1,0), +(17698,1,0), +(17748,1,0), +(18110,1,0), +(18655,1,0), +(18666,1,0), +(18811,1,0), +(18969,1,0), +(19032,1,0), +(19096,1,0), +(19571,1,0), +(19593,1,0), +(19721,1,0), +(19749,1,0), +(19770,1,0), +(19773,1,0), +(19952,1,0), +(20358,1,0), +(20465,1,0), +(20619,1,0), +(21052,1,0), +(21075,1,0), +(21076,1,0), +(21391,1,0), +(21556,1,0), +(21566,1,0), +(21885,1,0), +(21950,1,0), +(22096,1,0), +(22203,1,0), +(22205,1,0), +(22393,1,0), +(22458,1,0), +(22860,1,0), +(22906,1,0), +(22966,1,0), +(23014,1,0), +(23016,1,0), +(23018,1,0), +(23019,1,0), +(23168,1,0), +(23328,1,0), +(23360,1,0), +(23389,1,0), +(23394,1,0), +(23415,1,0), +(23642,1,0), +(23951,1,0), +(23974,1,0), +(24062,1,0), +(24083,1,0), +(24172,1,0), +(24207,1,0), +(24217,1,0), +(24311,1,0), +(24322,1,0), +(24323,1,0), +(24391,1,0), +(24734,1,0), +(24744,1,0), +(24756,1,0), +(24758,1,0), +(24760,1,0), +(24763,1,0), +(24765,1,0), +(24768,1,0), +(24770,1,0), +(24772,1,0), +(24784,1,0), +(24786,1,0), +(24788,1,0), +(24789,1,0), +(24790,1,0), +(24804,1,0), +(24933,1,0), +(25030,1,0), +(25031,1,0), +(25032,1,0), +(25099,1,0), +(25145,1,0), +(25149,1,0), +(25150,1,0), +(25158,1,0), +(25201,1,0), +(25715,1,0), +(25727,1,0), +(25745,1,0), +(25822,1,0), +(25823,1,0), +(25896,1,0), +(26235,1,0), +(26344,1,0), +(26345,1,0), +(26346,1,0), +(26347,1,0), +(26348,1,0), +(26349,1,0), +(26351,1,0), +(26352,1,0), +(26353,1,0), +(26354,1,0), +(26355,1,0), +(26356,1,0), +(26462,1,0), +(26522,1,1), +(26608,1,0), +(26687,1,1), +(26879,1,0), +(27583,1,0), +(27651,1,0), +(27663,1,0), +(27745,1,0), +(27885,1,0), +(27886,1,0), +(27892,1,0), +(27893,1,0), +(27894,1,0), +(27928,1,0), +(27929,1,0), +(27935,1,0), +(27936,1,0), +(28018,1,0), +(28032,1,0), +(28056,1,0), +(28078,1,0), +(28087,1,0), +(28096,1,0), +(28111,1,0), +(28159,1,0), +(28278,1,0), +(28281,1,0), +(28309,1,0), +(28326,1,0), +(28338,1,0), +(28339,1,0), +(28365,1,0), +(28366,1,0), +(28367,1,0), +(28374,1,0), +(28392,1,0), +(28404,1,0), +(28441,1,0), +(28605,1,0), +(28697,1,0), +(28731,1,0), +(28732,1,0), +(28861,1,0), +(29070,1,0), +(29072,1,0), +(29120,1,0), +(29121,1,0), +(29122,1,0), +(29172,1,0), +(29173,1,0), +(29176,1,0), +(29328,1,1), +(29339,1,0), +(29340,1,0), +(29428,1,0), +(29437,1,0), +(29456,1,0), +(29457,1,0), +(29458,1,0), +(29459,1,0), +(29461,1,0), +(29531,1,0), +(29534,1,0), +(29612,1,0), +(29705,1,0), +(29726,1,0), +(29727,1,0), +(29769,1,0), +(29770,1,0), +(29846,1,1), +(29962,1,0), +(29966,1,0), +(29967,1,0), +(29969,1,0), +(29970,1,0), +(29972,1,0), +(29989,1,0), +(30012,1,0), +(30065,1,0), +(30107,1,0), +(30166,1,0), +(30207,1,0), +(30221,1,0), +(30232,1,0), +(30273,1,0), +(30410,1,0), +(30417,1,0), +(30418,1,0), +(30425,1,0), +(30427,1,0), +(30460,1,0), +(30462,1,0), +(30469,1,0), +(30477,1,0), +(30541,1,0), +(30544,1,0), +(30571,1,1), +(30572,1,0), +(30625,1,0), +(30631,1,1), +(30656,1,0), +(30662,1,0), +(30676,1,0), +(30690,1,0), +(30735,1,0), +(30738,1,0), +(30745,1,0), +(30751,1,0), +(30762,1,0), +(30763,1,0), +(30764,1,0), +(30765,1,0), +(30766,1,0), +(30834,1,0), +(30835,1,0), +(30875,1,0), +(30876,1,0), +(30951,1,0), +(30952,1,0), +(30964,1,0), +(30968,1,0), +(30970,1,0), +(30974,1,0), +(30985,1,0), +(30988,1,0), +(31115,1,0), +(31225,1,0), +(31315,1,0), +(31324,1,0), +(31326,1,0), +(31329,1,0), +(31336,1,0), +(31346,1,0), +(31411,1,0), +(31412,1,0), +(31413,1,0), +(31414,1,0), +(31474,1,0), +(31515,1,0), +(31532,1,0), +(31537,1,0), +(31550,1,0), +(31611,1,0), +(31628,1,0), +(31630,1,0), +(31631,1,0), +(31702,1,0), +(31727,1,0), +(31736,1,0), +(31749,1,0), +(31781,1,0), +(31793,1,0), +(31799,1,0), +(31806,1,0), +(31889,1,0), +(31902,1,0), +(31936,1,0), +(31979,1,0), +(31993,1,0), +(32040,1,0), +(32042,1,0), +(32045,1,0), +(32051,1,0), +(32052,1,0), +(32087,1,0), +(32111,1,0), +(32127,1,0), +(32146,1,0), +(32163,1,0), +(32164,1,0), +(32227,1,0), +(32228,1,0), +(32251,1,0), +(32260,1,0), +(32286,1,0), +(32301,1,0), +(32303,1,0), +(32312,1,0), +(32373,1,0), +(32396,1,0), +(32560,1,0), +(32573,1,0), +(32589,1,0), +(32622,1,0), +(32623,1,0), +(32638,1,0), +(32668,1,0), +(32708,1,1), +(32760,1,0), +(32838,1,0), +(32890,1,0), +(32928,1,0), +(32929,1,0), +(32930,1,0), +(32953,1,0), +(32958,1,0), +(32974,1,0), +(32976,1,0), +(32979,1,0), +(33067,1,0), +(33270,1,1), +(33329,1,0), +(33332,1,0), +(33336,1,0), +(33337,1,0), +(33423,1,0), +(33424,1,0), +(33425,1,0), +(33531,1,0), +(33532,1,0), +(33618,1,0), +(33644,1,0), +(33655,1,0), +(33669,1,0), +(33710,1,0), +(33716,1,1), +(33742,1,0), +(33744,1,0), +(33796,1,0), +(33805,1,0), +(33806,1,0), +(33809,1,0), +(33822,1,0), +(33831,1,0), +(33838,1,0), +(33861,1,0), +(33862,1,0), +(33918,1,0), +(33924,1,0), +(33937,1,0), +(33981,1,0), +(34011,1,0), +(34013,1,0), +(34016,1,0), +(34019,1,0), +(34023,1,0), +(34024,1,0), +(34062,1,0), +(34063,1,0), +(34076,1,0), +(34119,1,0), +(34154,1,0), +(34156,1,0), +(34209,1,0), +(34211,1,0), +(34212,1,0), +(34221,1,0), +(34239,1,0), +(34254,1,0), +(34330,1,0), +(34332,1,0), +(34367,1,0), +(34378,1,0), +(34393,1,0), +(34397,1,0), +(34430,1,0), +(34516,1,0), +(34526,1,0), +(34536,1,0), +(34581,1,0), +(34583,1,0), +(34613,1,0), +(34627,1,0), +(34646,1,0), +(34662,1,0), +(34742,1,0), +(34806,1,0), +(34874,1,0), +(34893,1,0), +(34946,1,0), +(35016,1,0), +(35040,1,0), +(35063,1,0), +(35097,1,0), +(35113,1,0), +(35137,1,0), +(35140,1,0), +(35141,1,0), +(35155,1,0), +(35160,1,0), +(35162,1,0), +(35170,1,0), +(35176,1,0), +(35190,1,0), +(35245,1,0), +(35262,1,0), +(35282,1,0), +(35301,1,0), +(35372,1,0), +(35413,1,0), +(35427,1,0), +(35515,1,0), +(35516,1,0), +(35598,1,0), +(35600,1,0), +(35673,1,0), +(35682,1,0), +(35724,1,0), +(35746,1,0), +(35756,1,0), +(35770,1,0), +(35771,1,0), +(35772,1,0), +(35782,1,0), +(35930,1,0), +(35941,1,1), +(35956,1,1), +(35960,1,0), +(35961,1,0), +(35962,1,0), +(36000,1,0), +(36035,1,0), +(36089,1,0), +(36090,1,0), +(36103,1,0), +(36167,1,0), +(36174,1,0), +(36196,1,0), +(36197,1,0), +(36198,1,0), +(36201,1,0), +(36220,1,0), +(36239,1,0), +(36241,1,0), +(36243,1,0), +(36290,1,0), +(36291,1,0), +(36293,1,0), +(36327,1,0), +(36330,1,0), +(36378,1,0), +(36384,1,0), +(36431,1,0), +(36452,1,0), +(36455,1,1), +(36456,1,0), +(36514,1,0), +(36544,1,0), +(36639,1,0), +(36651,1,0), +(36652,1,0), +(36692,1,0), +(36709,1,0), +(36717,1,1), +(36779,1,0), +(36795,1,0), +(36802,1,0), +(36803,1,0), +(36804,1,0), +(36823,1,0), +(36852,1,0), +(36854,1,0), +(36856,1,0), +(36857,1,0), +(36858,1,0), +(36859,1,0), +(36871,1,0), +(36878,1,0), +(36884,1,0), +(36896,1,0), +(36951,1,0), +(36953,1,0), +(36969,1,0), +(36995,1,0), +(37013,1,0), +(37017,1,0), +(37032,1,0), +(37033,1,0), +(37034,1,0), +(37035,1,0), +(37051,1,0), +(37052,1,0), +(37053,1,0), +(37055,1,0), +(37056,1,0), +(37071,1,0), +(37072,1,0), +(37103,1,0), +(37142,1,0), +(37143,1,0), +(37144,1,0), +(37146,1,0), +(37147,1,0), +(37148,1,0), +(37149,1,0), +(37150,1,0), +(37151,1,0), +(37152,1,0), +(37153,1,0), +(37199,1,0), +(37220,1,0), +(37226,1,0), +(37229,1,0), +(37235,1,0), +(37281,1,0), +(37285,1,0), +(37337,1,0), +(37339,1,0), +(37345,1,0), +(37348,1,0), +(37388,1,0), +(37406,1,0), +(37408,1,1), +(37413,1,0), +(37422,1,0), +(37427,1,0), +(37428,1,0), +(37448,1,1), +(37449,1,1), +(37453,1,0), +(37454,1,0), +(37459,1,0), +(37461,1,0), +(37465,1,0), +(37469,1,0), +(37471,1,0), +(37472,1,0), +(37474,1,0), +(37476,1,0), +(37498,1,0), +(37502,1,0), +(37573,1,0), +(37626,1,0), +(37645,1,0), +(37689,1,0), +(37697,1,0), +(37712,1,0), +(37720,1,0), +(37748,1,0), +(37755,1,0), +(37775,1,0), +(37784,1,0), +(37824,1,0), +(37842,1,0), +(37843,1,0), +(37848,1,0), +(37849,1,1), +(37853,1,0), +(37868,1,0), +(37893,1,0), +(37895,1,0), +(37918,1,0), +(37934,1,0), +(37936,1,0), +(37964,1,0), +(37984,1,0), +(38003,1,0), +(38014,1,0), +(38015,1,0), +(38017,1,0), +(38020,1,0), +(38053,1,0), +(38054,1,0), +(38072,1,0), +(38073,1,0), +(38112,1,0), +(38121,1,0), +(38123,1,0), +(38126,1,0), +(38128,1,0), +(38130,1,0), +(38202,1,0), +(38250,1,0), +(38269,1,0), +(38360,1,0), +(38444,1,0), +(38451,1,0), +(38452,1,0), +(38455,1,0), +(38469,1,0), +(38482,1,0), +(38508,1,0), +(38530,1,0), +(38629,1,0), +(38632,1,0), +(38691,1,0), +(38711,1,0), +(38722,1,0), +(38736,1,0), +(38738,1,0), +(38762,1,0), +(38802,1,0), +(38829,1,1), +(38966,1,0), +(38968,1,0), +(39010,1,0), +(39011,1,0), +(39043,1,0), +(39073,1,0), +(39094,1,0), +(39124,1,0), +(39126,1,0), +(39140,1,0), +(39141,1,0), +(39184,1,0), +(39185,1,0), +(39189,1,0), +(39190,1,0), +(39206,1,0), +(39211,1,0), +(39216,1,0), +(39219,1,0), +(39221,1,0), +(39248,1,0), +(39334,1,0), +(39335,1,0), +(39338,1,0), +(39341,1,0), +(39342,1,0), +(39344,1,0), +(39350,1,0), +(39352,1,0), +(39353,1,0), +(39354,1,0), +(39355,1,0), +(39356,1,0), +(39357,1,0), +(39358,1,0), +(39359,1,0), +(39360,1,0), +(39361,1,0), +(39362,1,0), +(39395,1,0), +(39495,1,0), +(39497,1,1), +(39552,1,0), +(39559,1,0), +(39583,1,0), +(39601,1,0), +(39635,1,0), +(39678,1,0), +(39687,1,0), +(39690,1,0), +(39691,1,0), +(39692,1,0), +(39696,1,0), +(39758,1,0), +(39834,1,1), +(39849,1,0), +(39851,1,1), +(39852,1,1), +(39853,1,1), +(39854,1,1), +(39873,1,0), +(39899,1,0), +(39914,1,0), +(39915,1,0), +(39919,1,0), +(39921,1,0), +(39923,1,1), +(39930,1,0), +(39938,1,0), +(39939,1,0), +(39940,1,0), +(39974,1,0), +(39977,1,0), +(39978,1,0), +(39985,1,0), +(39989,1,0), +(39993,1,0), +(39999,1,0), +(40085,1,0), +(40094,1,0), +(40106,1,0), +(40110,1,0), +(40112,1,1), +(40136,1,0), +(40147,1,0), +(40153,1,0), +(40156,1,0), +(40160,1,0), +(40187,1,0), +(40189,1,0), +(40190,1,0), +(40224,1,0), +(40281,1,0), +(40287,1,0), +(40288,1,0), +(40289,1,0), +(40309,1,0), +(40350,1,0), +(40359,1,0), +(40382,1,0), +(40383,1,0), +(40397,1,0), +(40437,1,0), +(40439,1,0), +(40454,1,0), +(40490,1,0), +(40494,1,0), +(40498,1,0), +(40499,1,0), +(40512,1,0), +(40520,1,0), +(40521,1,0), +(40523,1,0), +(40532,1,0), +(40547,1,0), +(40607,1,0), +(40638,1,0), +(40693,1,0), +(40704,1,0), +(40707,1,0), +(40708,1,0), +(40709,1,0), +(40710,1,0), +(40711,1,0), +(40712,1,0), +(40713,1,0), +(40715,1,0), +(40730,1,1), +(40738,1,0), +(40750,1,0), +(40761,1,0), +(40788,1,0), +(40821,1,0), +(40824,1,0), +(40825,1,0), +(40828,1,0), +(40830,1,0), +(40848,1,1), +(40874,1,0), +(40887,1,0), +(40978,1,0), +(40985,1,1), +(40989,1,0), +(40993,1,1), +(41007,1,1), +(41015,1,1), +(41022,1,1), +(41073,1,0), +(41077,1,0), +(41122,1,0), +(41124,1,0), +(41125,1,0), +(41128,1,0), +(41129,1,0), +(41154,1,0), +(41257,1,0), +(41268,1,0), +(41269,1,0), +(41271,1,0), +(41285,1,1), +(41295,1,0), +(41333,1,0), +(41342,1,0), +(41343,1,0), +(41344,1,0), +(41362,1,0), +(41455,1,0), +(41457,1,0), +(41477,1,0), +(41499,1,0), +(41522,1,0), +(41525,1,0), +(41537,1,0), +(41557,1,0), +(41560,1,0), +(41575,1,0), +(41602,1,0), +(41614,1,0), +(41624,1,1), +(41975,1,0), +(41976,1,0), +(41993,1,0), +(42008,1,0), +(42014,1,0), +(42138,1,1), +(42143,1,0), +(42151,1,0), +(42166,1,0), +(42167,1,0), +(42168,1,0), +(42178,1,0), +(42219,1,0), +(42222,1,0), +(42247,1,0), +(42269,1,0), +(42271,1,0), +(42272,1,0), +(42289,1,0), +(42317,1,0), +(42318,1,0), +(42321,1,0), +(42339,1,0), +(42341,1,0), +(42352,1,0), +(42356,1,0), +(42391,1,0), +(42393,1,0), +(42405,1,0), +(42410,1,0), +(42415,1,0), +(42428,1,0), +(42442,1,0), +(42447,1,0), +(42454,1,0), +(42471,1,0), +(42473,1,0), +(42482,1,0), +(42484,1,0), +(42515,1,0), +(42517,1,0), +(42530,1,0), +(42534,1,0), +(42536,1,0), +(42542,1,0), +(42550,1,0), +(42564,1,0), +(42567,1,0), +(42570,1,0), +(42577,1,0), +(42585,1,0), +(42604,1,0), +(42605,1,0), +(42616,1,0), +(42631,1,0), +(42638,1,1), +(42647,1,0), +(42654,1,0), +(42655,1,0), +(42659,1,0), +(42661,1,0), +(42664,1,0), +(42674,1,1), +(42685,1,0), +(42695,1,0), +(42697,1,0), +(42703,1,0), +(42707,1,0), +(42713,1,0), +(42720,1,0), +(42734,1,0), +(42757,1,1), +(42768,1,0), +(42793,1,0), +(42797,1,0), +(42808,1,0), +(42809,1,0), +(42813,1,0), +(42815,1,0), +(42816,1,0), +(42818,1,0), +(42821,1,0), +(42839,1,0), +(42857,1,0), +(42881,1,0), +(42882,1,0), +(42883,1,0), +(42884,1,0), +(42888,1,0), +(42905,1,0), +(42968,1,0), +(42982,1,0), +(43033,1,0), +(43035,1,0), +(43057,1,0), +(43066,1,0), +(43068,1,0), +(43069,1,0), +(43072,1,0), +(43076,1,0), +(43078,1,0), +(43079,1,0), +(43092,1,0), +(43101,1,0), +(43106,1,0), +(43109,1,0), +(43144,1,0), +(43171,1,0), +(43209,1,0), +(43210,1,0), +(43234,1,0), +(43239,1,0), +(43244,1,0), +(43255,1,0), +(43291,1,0), +(43306,1,0), +(43307,1,0), +(43333,1,0), +(43371,1,0), +(43385,1,0), +(43386,1,0), +(43403,1,0), +(43404,1,0), +(43407,1,0), +(43450,1,0), +(43458,1,0), +(43468,1,0), +(43486,1,0), +(43487,1,0), +(43515,1,0), +(43520,1,0), +(43525,1,0), +(43546,1,0), +(43559,1,0), +(43563,1,0), +(43568,1,0), +(43615,1,0), +(43647,1,0), +(43662,1,0), +(43685,1,0), +(43691,1,0), +(43711,1,0), +(43734,1,0), +(43754,1,0), +(43770,1,0), +(43791,1,0), +(43805,1,0), +(43863,1,0), +(43865,1,0), +(43867,1,0), +(43871,1,0), +(43872,1,0), +(43878,1,0), +(43882,1,0), +(43892,1,0), +(43942,1,0), +(43943,1,0), +(43949,1,0), +(43962,1,0), +(43990,1,0), +(43994,1,0), +(44014,1,0), +(44022,1,0), +(44023,1,0), +(44024,1,0), +(44026,1,0), +(44027,1,0), +(44028,1,0), +(44037,1,0), +(44145,1,0), +(44161,1,0), +(44193,1,0), +(44214,1,0), +(44224,1,1), +(44229,1,0), +(44232,1,1), +(44250,1,0), +(44255,1,0), +(44260,1,0), +(44266,1,0), +(44270,1,0), +(44283,1,0), +(44284,1,0), +(44309,1,0), +(44313,1,0), +(44329,1,0), +(44330,1,0), +(44355,1,0), +(44362,1,0), +(44365,1,0), +(44367,1,0), +(44374,1,0), +(44392,1,0), +(44411,1,0), +(44420,1,0), +(44422,1,0), +(44458,1,0), +(44550,1,0), +(44562,1,0), +(44574,1,0), +(44609,1,0), +(44610,1,0), +(44653,1,0), +(44681,1,0), +(44682,1,1), +(44749,1,0), +(44804,1,0), +(44807,1,0), +(44826,1,0), +(44837,1,0), +(44838,1,0), +(44839,1,0), +(44840,1,0), +(44841,1,0), +(44842,1,0), +(44845,1,0), +(44846,1,0), +(44849,1,1), +(44864,1,0), +(44865,1,0), +(44872,1,0), +(44877,1,0), +(44883,1,0), +(44886,1,0), +(44938,1,0), +(44939,1,0), +(44941,1,0), +(44946,1,0), +(44948,1,0), +(44963,1,0), +(44965,1,0), +(44981,1,0), +(45005,1,0), +(45008,1,0), +(45012,1,0), +(45013,1,0), +(45076,1,0), +(45086,1,0), +(45103,1,0), +(45109,1,0), +(45114,1,0), +(45115,1,0), +(45119,1,0), +(45172,1,0), +(45188,1,0), +(45191,1,0), +(45219,1,0), +(45223,1,0), +(45224,1,0), +(45229,1,0), +(45233,1,0), +(45259,1,0), +(45260,1,1), +(45264,1,0), +(45267,1,0), +(45277,1,0), +(45279,1,0), +(45307,1,0), +(45323,1,0), +(45339,1,0), +(45340,1,0), +(45351,1,0), +(45368,1,0), +(45371,1,0), +(45388,1,0), +(45389,1,0), +(45405,1,0), +(45407,1,0), +(45414,1,0), +(45437,1,0), +(45446,1,0), +(45448,1,0), +(45449,1,0), +(45465,1,0), +(45474,1,0), +(45536,1,0), +(45581,1,0), +(45583,1,0), +(45586,1,0), +(45594,1,0), +(45595,1,0), +(45596,1,0), +(45597,1,0), +(45602,1,0), +(45605,1,0), +(45606,1,0), +(45607,1,0), +(45608,1,0), +(45609,1,0), +(45622,1,0), +(45623,1,0), +(45630,1,0), +(45634,1,0), +(45644,1,1), +(45651,1,0), +(45655,1,0), +(45656,1,0), +(45666,1,0), +(45667,1,0), +(45671,1,1), +(45680,1,1), +(45692,1,0), +(45700,1,0), +(45714,1,0), +(45732,1,0), +(45735,1,0), +(45761,1,0), +(45774,1,0), +(45780,1,0), +(45788,1,0), +(45805,1,0), +(45808,1,0), +(45834,1,0), +(45835,1,0), +(45841,1,0), +(45853,1,0), +(45859,1,0), +(45863,1,0), +(45864,1,0), +(45867,1,0), +(45872,1,0), +(45888,1,0), +(45907,1,0), +(45911,1,0), +(45912,1,0), +(45914,1,0), +(45918,1,1), +(45923,1,0), +(45929,1,0), +(45930,1,0), +(45941,1,0), +(45949,1,0), +(45961,1,0), +(45968,1,0), +(45969,1,0), +(45970,1,0), +(45976,1,0), +(45979,1,0), +(45990,1,0), +(45993,1,0), +(46013,1,0), +(46018,1,1), +(46022,1,0), +(46034,1,0), +(46054,1,0), +(46058,1,0), +(46063,1,0), +(46066,1,0), +(46068,1,0), +(46085,1,0), +(46143,1,0), +(46171,1,0), +(46173,1,0), +(62377,1,0), +(46175,1,0), +(46176,1,0), +(46177,1,0), +(46178,1,0), +(46201,1,0), +(46208,1,0), +(46219,1,0), +(46222,1,0), +(46236,1,0), +(46237,1,0), +(46245,1,0), +(46246,1,0), +(46281,1,0), +(46307,1,1), +(46318,1,0), +(46319,1,0), +(46320,1,1), +(46330,1,0), +(46363,1,0), +(46372,1,1), +(46374,1,0), +(46376,1,0), +(46382,1,0), +(46385,1,0), +(46396,1,1), +(46398,1,0), +(46399,1,0), +(46400,1,0), +(46474,1,0), +(46475,1,0), +(46477,1,0), +(46482,1,0), +(46488,1,0), +(46521,1,0), +(46588,1,1), +(46592,1,0), +(46593,1,0), +(46603,1,0), +(46609,1,0), +(46610,1,0), +(46623,1,0), +(46631,1,0), +(46637,1,0), +(46650,1,0), +(46652,1,0), +(46656,1,0), +(46685,1,0), +(46692,1,0), +(46694,1,0), +(46704,1,0), +(46707,1,0), +(46732,1,1), +(46733,1,0), +(46735,1,0), +(46747,1,0), +(46793,1,0), +(46797,1,0), +(46809,1,0), +(46815,1,0), +(46818,1,0), +(46820,1,0), +(46843,1,0), +(46886,1,0), +(46895,1,0), +(46900,1,0), +(46902,1,0), +(46903,1,0), +(46904,1,0), +(46936,1,0), +(46937,1,0), +(46963,1,0), +(46964,1,0), +(46965,1,1), +(46974,1,0), +(47016,1,0), +(47026,1,0), +(47035,1,0), +(47060,1,0), +(47065,1,0), +(47104,1,0), +(47110,1,0), +(47137,1,0), +(47170,1,0), +(47176,1,0), +(47184,1,0), +(47214,1,0), +(47253,1,0), +(47254,1,0), +(47336,1,0), +(47344,1,0), +(47370,1,1), +(47374,1,0), +(47378,1,0), +(47421,1,0), +(47452,1,0), +(47460,1,0), +(47463,1,0), +(47469,1,0), +(47542,1,0), +(47547,1,0), +(47563,1,0), +(47574,1,0), +(47593,1,0), +(47594,1,0), +(47596,1,0), +(47597,1,0), +(47598,1,0), +(47599,1,0), +(47616,1,0), +(47617,1,0), +(47618,1,0), +(47619,1,0), +(47634,1,0), +(47669,1,0), +(47670,1,0), +(47681,1,0), +(47682,1,0), +(47683,1,0), +(47684,1,0), +(47685,1,0), +(47691,1,1), +(47711,1,0), +(47712,1,0), +(47713,1,0), +(47747,1,0), +(47771,1,0), +(47787,1,0), +(47799,1,0), +(47911,1,0), +(47913,1,0), +(47916,1,0), +(47933,1,0), +(47935,1,0), +(47939,1,0), +(47959,1,0), +(48009,1,0), +(48021,1,0), +(48028,1,1), +(48035,1,0), +(48115,1,0), +(48117,1,0), +(48183,1,0), +(48185,1,0), +(48188,1,0), +(48194,1,1), +(48199,1,0), +(48201,1,0), +(48202,1,0), +(48213,1,0), +(48218,1,0), +(48222,1,0), +(48223,1,0), +(48227,1,0), +(48246,1,1), +(48252,1,0), +(48293,1,0), +(48306,1,0), +(48315,1,0), +(48329,1,0), +(48344,1,0), +(48345,1,0), +(48362,1,0), +(48363,1,0), +(48375,1,0), +(48385,1,0), +(48398,1,0), +(48399,1,0), +(48425,1,0), +(48426,1,0), +(48455,1,0), +(48490,1,0), +(48497,1,0), +(48508,1,0), +(48530,1,0), +(48551,1,0), +(48597,1,0), +(48600,1,0), +(48605,1,0), +(48620,1,0), +(48623,1,0), +(48627,1,0), +(48641,1,0), +(48642,1,0), +(48646,1,0), +(48649,1,0), +(48685,1,0), +(48724,1,0), +(48726,1,0), +(48728,1,0), +(48730,1,0), +(48732,1,0), +(48748,1,0), +(48764,1,0), +(48771,1,0), +(48773,1,0), +(48790,1,0), +(48793,1,0), +(48799,1,0), +(48808,1,0), +(48811,1,0), +(48896,1,0), +(48901,1,0), +(48904,1,0), +(48929,1,0), +(48974,1,0), +(48975,1,0), +(49022,1,0), +(49030,1,0), +(49058,1,0), +(49062,1,0), +(49075,1,0), +(49080,1,0), +(49083,1,0), +(49118,1,0), +(49125,1,0), +(49128,1,0), +(49129,1,0), +(49131,1,0), +(49134,1,0), +(49135,1,0), +(49159,1,0), +(49166,1,0), +(49210,1,0), +(49211,1,0), +(49262,1,0), +(49291,1,0), +(49292,1,0), +(49313,1,0), +(49319,1,0), +(49325,1,0), +(49330,1,0), +(49332,1,0), +(49333,1,0), +(49334,1,0), +(49367,1,0), +(49370,1,0), +(49404,1,0), +(49405,1,0), +(49428,1,0), +(49434,1,0), +(49515,1,0), +(49517,1,0), +(49519,1,0), +(49524,1,0), +(49525,1,0), +(49552,1,0), +(49554,1,0), +(49555,1,0), +(49557,1,0), +(49590,1,0), +(49625,1,0), +(49634,1,0), +(49679,1,0), +(49682,1,0), +(49683,1,0), +(49684,1,0), +(49731,1,0), +(49751,1,0), +(49762,1,0), +(49825,1,0), +(49826,1,0), +(49829,1,0), +(49858,1,0), +(49862,1,0), +(49870,1,0), +(49899,1,0), +(49947,1,0), +(50036,1,0), +(50087,1,0), +(50133,1,0), +(50173,1,0), +(50174,1,0), +(50176,1,0), +(50177,1,0), +(50178,1,0), +(50179,1,0), +(50312,1,0), +(50315,1,1), +(50331,1,0), +(50350,1,0), +(50382,1,0), +(50383,1,0), +(50398,1,1), +(50430,1,0), +(50440,1,0), +(50492,1,0), +(50515,1,0), +(50524,1,0), +(50546,1,0), +(50547,1,0), +(50548,1,0), +(50554,1,0), +(50556,1,0), +(50562,1,0), +(50563,1,0), +(50568,1,0), +(50569,1,0), +(50592,1,0), +(50628,1,0), +(50669,1,0), +(50674,1,0), +(50682,1,1), +(50742,1,0), +(50775,1,0), +(50793,1,0), +(50794,1,0), +(50817,1,0), +(50835,1,0), +(50878,1,0), +(50883,1,1), +(50892,1,0), +(51001,1,0), +(51022,1,0), +(51023,1,0), +(51024,1,0), +(51025,1,0), +(51039,1,0), +(51049,1,0), +(51122,1,0), +(51136,1,0), +(51139,1,0), +(51152,1,0), +(51171,1,0), +(51172,1,0), +(51202,1,0), +(51213,1,0), +(51215,1,0), +(51234,1,0), +(51239,1,0), +(51247,1,0), +(51256,1,0), +(51276,1,0), +(51288,1,0), +(51318,1,0), +(51331,1,0), +(51332,1,0), +(51333,1,0), +(51343,1,0), +(51366,1,0), +(51368,1,0), +(51381,1,0), +(51384,1,0), +(51393,1,0), +(51396,1,0), +(51403,1,0), +(51420,1,0), +(51448,1,1), +(51516,1,0), +(51518,1,0), +(51577,1,0), +(51579,1,0), +(51590,1,0), +(51603,1,0), +(51606,1,0), +(51607,1,0), +(51616,1,0), +(51639,1,0), +(51641,1,0), +(51642,1,0), +(51643,1,0), +(51644,1,0), +(51645,1,0), +(51649,1,0), +(51650,1,0), +(51651,1,0), +(51652,1,0), +(51670,1,0), +(51694,1,0), +(51697,1,0), +(51727,1,0), +(51737,1,0), +(51739,1,0), +(51743,1,0), +(51754,1,0), +(51767,1,0), +(51769,1,0), +(51773,1,0), +(51774,1,0), +(51791,1,0), +(51794,1,0), +(51825,1,0), +(51840,1,0), +(51843,1,0), +(51858,1,0), +(51859,1,0), +(51861,1,0), +(51866,1,0), +(51870,1,0), +(51902,1,0), +(51904,1,0), +(51907,1,0), +(51910,1,0), +(51925,1,0), +(51927,1,0), +(51931,1,0), +(51932,1,0), +(51933,1,0), +(51942,1,0), +(51959,1,0), +(51964,1,0), +(51965,1,0), +(52011,1,0), +(52037,1,0), +(52059,1,0), +(52064,1,0), +(52089,1,0), +(52106,1,0), +(52122,1,0), +(52124,1,0), +(52140,1,0), +(52151,1,0), +(52164,1,0), +(52170,1,0), +(52173,1,0), +(52185,1,0), +(52227,1,0), +(52229,1,0), +(52238,1,0), +(52239,1,0), +(52242,1,0), +(52247,1,0), +(52254,1,0), +(52257,1,0), +(52259,1,0), +(52264,1,0), +(52294,1,0), +(52313,1,0), +(52322,1,0), +(52335,1,0), +(52336,1,0), +(52337,1,1), +(52340,1,0), +(52343,1,0), +(52349,1,0), +(52365,1,1), +(52369,1,0), +(52371,1,0), +(52381,1,0), +(52387,1,0), +(52388,1,0), +(52407,1,0), +(52412,1,0), +(52414,1,0), +(52427,1,0), +(52438,1,0), +(52446,1,0), +(52449,1,0), +(52452,1,0), +(52453,1,0), +(52454,1,0), +(52457,1,0), +(52458,1,0), +(52512,1,0), +(52514,1,0), +(52528,1,0), +(52576,1,0), +(52577,1,0), +(52585,1,0), +(52607,1,0), +(52632,1,0), +(52638,1,0), +(52654,1,0), +(52661,1,0), +(52676,1,0), +(52681,1,0), +(52686,1,0), +(52687,1,0), +(52688,1,0), +(52725,1,0), +(52726,1,0), +(52727,1,0), +(52728,1,0), +(52729,1,0), +(52730,1,0), +(52731,1,0), +(52732,1,0), +(52774,1,0), +(52791,1,0), +(52793,1,0), +(52805,1,0), +(52811,1,0), +(52816,1,0), +(52833,1,0), +(52834,1,0), +(52837,1,0), +(52838,1,0), +(52844,1,0), +(52850,1,0), +(52884,1,0), +(52908,1,0), +(52920,1,0), +(52930,1,0), +(52934,1,0), +(52935,1,0), +(52936,1,0), +(52937,1,0), +(52953,1,0), +(52955,1,0), +(52956,1,0), +(52981,1,0), +(52989,1,0), +(52990,1,0), +(53010,1,0), +(53020,1,0), +(53024,1,0), +(53029,1,0), +(53038,1,0), +(53083,1,0), +(53093,1,0), +(53096,1,0), +(53106,1,0), +(53110,1,0), +(53163,1,0), +(53170,1,0), +(53177,1,0), +(53185,1,0), +(53206,1,0), +(53210,1,0), +(53242,1,1), +(53272,1,0), +(53441,1,0), +(53464,1,0), +(53465,1,0), +(53466,1,0), +(53570,1,0), +(53609,1,0), +(53613,1,0), +(53626,1,0), +(53644,1,0), +(53680,1,0), +(53683,1,0), +(53684,1,0), +(53685,1,0), +(53701,1,0), +(53714,1,1), +(53717,1,0), +(53730,1,0), +(53745,1,0), +(53757,1,1), +(53778,1,0), +(53798,1,0), +(53826,1,0), +(53827,1,0), +(53828,1,0), +(53829,1,0), +(54040,1,0), +(54047,1,0), +(54089,1,0), +(54090,1,0), +(54097,1,0), +(54108,1,0), +(54112,1,0), +(54128,1,0), +(54142,1,0), +(54209,1,0), +(54236,1,0), +(54245,1,0), +(54250,1,0), +(54258,1,0), +(54264,1,0), +(54265,1,0), +(54266,1,0), +(54267,1,0), +(54269,1,0), +(54323,1,0), +(54325,1,0), +(54327,1,0), +(54328,1,0), +(54377,1,0), +(54423,1,0), +(54426,1,0), +(54430,1,0), +(54464,1,0), +(54510,1,0), +(54522,1,0), +(54539,1,0), +(54548,1,0), +(54643,1,0), +(54656,1,0), +(54664,1,0), +(54685,1,0), +(54699,1,1), +(54725,1,1), +(54728,1,0), +(54744,1,1), +(54746,1,1), +(54773,1,0), +(54796,1,0), +(54798,1,0), +(54806,1,0), +(54878,1,0), +(54899,1,0), +(54984,1,0), +(54985,1,0), +(54988,1,0), +(54991,1,0), +(55063,1,0), +(55089,1,0), +(55127,1,0), +(55134,1,0), +(55137,1,0), +(55138,1,0), +(55141,1,0), +(55145,1,0), +(55161,1,0), +(55223,1,0), +(55227,1,0), +(55229,1,0), +(55231,1,0), +(55244,1,0), +(55257,1,0), +(55287,1,0), +(55288,1,0), +(55290,1,0), +(55406,1,0), +(55418,1,0), +(55419,1,0), +(55423,1,1), +(55432,1,0), +(55465,1,0), +(55468,1,0), +(55510,1,0), +(55516,1,0), +(55519,1,0), +(55524,1,0), +(55526,1,0), +(55527,1,0), +(55571,1,0), +(55578,1,0), +(55616,1,1), +(55647,1,0), +(55660,1,0), +(55661,1,0), +(55662,1,0), +(55693,1,0), +(55720,1,0), +(55721,1,0), +(55722,1,0), +(55723,1,0), +(55724,1,0), +(55725,1,0), +(55726,1,0), +(55727,1,0), +(55785,1,0), +(55796,1,0), +(55801,1,0), +(55803,1,0), +(55805,1,0), +(55811,1,0), +(55844,1,0), +(55853,1,0), +(55868,1,0), +(55872,1,0), +(55875,1,0), +(55878,1,1), +(55881,1,1), +(55882,1,0), +(55885,1,1), +(55886,1,0), +(55887,1,1), +(55888,1,0), +(55954,1,0), +(56047,1,0), +(56066,1,0), +(56099,1,0), +(56103,1,0), +(56114,1,0), +(56117,1,0), +(56150,1,0), +(56152,1,0), +(56189,1,0), +(56227,1,0), +(56253,1,0), +(56263,1,0), +(56264,1,0), +(56265,1,0), +(56266,1,0), +(56275,1,0), +(56312,1,0), +(56387,1,0), +(56388,1,0), +(56393,1,0), +(56429,1,0), +(56458,1,0), +(56505,1,0), +(56523,1,0), +(56560,1,0), +(56563,1,0), +(56567,1,0), +(56575,1,0), +(56621,1,0), +(56622,1,0), +(56652,1,0), +(56661,1,0), +(56663,1,0), +(56665,1,0), +(56667,1,0), +(56669,1,0), +(56673,1,0), +(56677,1,0), +(56680,1,0), +(56683,1,0), +(56688,1,0), +(56691,1,0), +(56693,1,0), +(56695,1,0), +(56696,1,0), +(56711,1,0), +(56713,1,0), +(56722,1,0), +(56723,1,0), +(56724,1,0), +(56725,1,0), +(56738,1,0), +(56763,1,0), +(56764,1,0), +(56865,1,0), +(56905,1,0), +(56917,1,0), +(56941,1,1), +(57042,1,0), +(57068,1,0), +(57071,1,0), +(57072,1,0), +(57410,1,0), +(57417,1,0), +(57420,1,0), +(57422,1,0), +(57469,1,0), +(57471,1,0), +(57495,1,0), +(57523,1,0), +(57534,1,0), +(57632,1,0), +(57637,1,0), +(57638,1,0), +(57639,1,0), +(57642,1,0), +(57650,1,0), +(57659,1,0), +(57666,1,0), +(57667,1,0), +(57682,1,0), +(57732,1,0), +(57734,1,0), +(57735,1,0), +(57736,1,0), +(57737,1,0), +(57738,1,0), +(57797,1,0), +(57806,1,0), +(57809,1,0), +(57828,1,0), +(57852,1,0), +(57853,1,0), +(57885,1,0), +(57891,1,0), +(57912,1,0), +(57930,1,0), +(57962,1,0), +(57963,1,0), +(57980,1,0), +(57983,1,0), +(58036,1,0), +(58040,1,0), +(58064,1,0), +(58084,1,0), +(58103,1,0), +(58108,1,0), +(58109,1,0), +(58112,1,0), +(58114,1,0), +(58121,1,0), +(58123,1,0), +(58124,1,0), +(58131,1,0), +(58152,1,0), +(58178,1,0), +(58195,1,1), +(58196,1,1), +(58197,1,1), +(58198,1,1), +(58225,1,0), +(58350,1,0), +(58416,1,0), +(58493,1,1), +(58515,1,0), +(58533,1,0), +(58542,1,0), +(58552,1,0), +(58593,1,0), +(58641,1,0), +(58658,1,0), +(58672,1,0), +(58685,1,0), +(58793,1,0), +(58836,1,0), +(58838,1,0), +(58846,1,1), +(58858,1,0), +(58873,1,0), +(58916,1,0), +(58917,1,0), +(58945,1,0), +(58949,1,0), +(59078,1,0), +(59091,1,0), +(59098,1,0), +(59115,1,0), +(59125,1,0), +(59189,1,0), +(59190,1,0), +(59284,1,0), +(59335,1,0), +(59363,1,0), +(59375,1,0), +(59383,1,0), +(59386,1,0), +(59396,1,0), +(59449,1,0), +(59456,1,0), +(59461,1,1), +(59528,1,0), +(59534,1,0), +(59552,1,0), +(59554,1,0), +(59556,1,1), +(59579,1,0), +(59595,1,0), +(59643,1,0), +(59655,1,0), +(59668,1,0), +(59677,1,0), +(59678,1,0), +(59704,1,0), +(59729,1,0), +(59730,1,0), +(59764,1,0), +(59780,1,0), +(59781,1,0), +(59807,1,0), +(59847,1,0), +(59867,1,0), +(59871,1,0), +(59897,1,0), +(59925,1,0), +(59930,1,0), +(59951,1,0), +(59952,1,0), +(59977,1,0), +(60038,1,0), +(60045,1,0), +(60046,1,0), +(60088,1,0), +(60104,1,0), +(60178,1,1), +(60207,1,0), +(60208,1,0), +(60224,1,0), +(60243,1,0), +(60256,1,0), +(60285,1,0), +(60288,1,0), +(60291,1,1), +(60292,1,1), +(60293,1,1), +(60294,1,1), +(60295,1,1), +(60296,1,1), +(60297,1,1), +(60298,1,0), +(60310,1,0), +(60315,1,0), +(60316,1,0), +(60342,1,0), +(60422,1,0), +(60456,1,0), +(60476,1,1), +(60496,1,0), +(60499,1,1), +(60507,1,1), +(60508,1,1), +(60511,1,0), +(60516,1,0), +(60522,1,1), +(60528,1,0), +(60535,1,0), +(60536,1,0), +(60561,1,0), +(60612,1,0), +(60614,1,0), +(60713,1,0), +(60810,1,0), +(60829,1,0), +(60831,1,0), +(60834,1,0), +(60836,1,0), +(60863,1,0), +(60909,1,0), +(60912,1,1), +(60967,1,0), +(61007,1,0), +(61026,1,0), +(61028,1,0), +(61071,1,0), +(61072,1,0), +(61073,1,0), +(61074,1,0), +(61075,1,0), +(61114,1,0), +(61121,1,0), +(61151,1,0), +(61152,1,0), +(61180,1,0), +(61210,1,0), +(61219,1,0), +(61245,1,0), +(61254,1,0), +(61353,1,0), +(61355,1,0), +(61397,1,0), +(61408,1,0), +(61416,1,0), +(61487,1,0), +(61488,1,0), +(61492,1,0), +(61524,1,0), +(61537,1,0), +(61588,1,0), +(61602,1,0), +(61647,1,0), +(61652,1,0), +(61665,1,0), +(61710,1,0), +(61738,1,0), +(61764,1,0), +(61765,1,0), +(61766,1,0), +(61771,1,0), +(61816,1,1), +(61863,1,1), +(61901,1,0), +(61934,1,0), +(61942,1,0), +(61964,1,0), +(61975,1,0), +(62002,1,0), +(62016,1,0), +(62034,1,0), +(62037,1,1), +(62072,1,0), +(62082,1,0), +(62083,1,0), +(62084,1,0), +(62091,1,0), +(62102,1,0), +(62195,1,0), +(62223,1,0), +(62266,1,0), +(62272,1,0), +(62278,1,0), +(62284,1,0), +(62304,1,0), +(62323,1,0), +(62343,1,0), +(47129,2,0), +(34395,2,0), +(34387,2,0), +(32440,2,0), +(32439,2,0), +(32205,2,0), +(31538,2,0), +(30740,2,0), +(29831,2,0), +(28806,2,0), +(28353,2,0), +(27517,2,0), +(27203,2,0), +(27202,2,0), +(27201,2,0), +(27191,2,0), +(27190,2,0), +(27184,2,0), +(26560,2,0), +(26063,2,0), +(25005,2,0), +(24934,2,0), +(24871,2,0), +(24721,2,0), +(24390,2,0), +(23208,2,0), +(21127,2,0), +(18431,2,0), +(17731,2,0), +(17016,2,0), +(16613,2,0), +(16447,2,0), +(13489,2,0), +(12139,2,0), +(11792,2,0), +(9224,2,0), +(9223,2,0), +(9222,2,0), +(9221,2,0), +(8674,2,0), +(7729,2,0), +(7728,2,0), +(3921,2,0), +(35683,2,0), +(36066,2,0), +(36546,2,0), +(36851,2,0), +(37754,2,0), +(38439,2,0), +(38782,2,0), +(39050,2,0), +(40055,2,0), +(40165,2,0), +(40166,2,0), +(40167,2,0), +(40328,2,0), +(40447,2,0), +(40468,2,0), +(40632,2,0), +(40640,2,0), +(40642,2,0), +(40644,2,0), +(40675,2,0), +(40774,2,0), +(40785,2,0), +(40964,2,0), +(40965,2,0), +(40968,2,0), +(40970,2,0), +(41004,2,0), +(41145,2,0), +(41146,2,0), +(42020,2,0), +(42022,2,0), +(42323,2,0), +(42788,2,0), +(43418,2,0), +(43552,2,0), +(43723,2,0), +(43753,2,0), +(43768,2,0), +(43950,2,0), +(44307,2,0), +(44498,2,0), +(44499,2,0), +(44611,2,0), +(44686,2,0), +(44874,2,0), +(44885,2,0), +(45149,2,0), +(45222,2,0), +(45226,2,0), +(45795,2,0), +(45877,2,0), +(45971,2,0), +(46072,2,0), +(46350,2,0), +(46360,2,1), +(46584,2,0), +(76006,2,0), +(74179,2,0), +(72869,2,0), +(72868,2,0), +(72608,2,0), +(72456,2,0), +(72405,2,0), +(72340,2,1), +(71284,2,1), +(70598,2,1), +(70446,2,1), +(70346,2,0), +(70227,2,0), +(70199,2,0), +(70175,2,0), +(70173,2,0), +(69402,2,0), +(69400,2,0), +(69294,2,0), +(69157,2,0), +(67815,2,0), +(67814,2,0), +(67813,2,0), +(67812,2,0), +(67798,2,0), +(67459,2,0), +(67458,2,0), +(67448,2,0), +(67439,2,0), +(67436,2,0), +(66676,2,0), +(66672,2,0), +(66655,2,0), +(66531,2,0), +(66289,2,0), +(65209,2,0), +(64871,2,0), +(64570,2,0), +(64436,2,0), +(63618,2,0), +(63381,2,0), +(62776,2,0), +(62714,2,0), +(62635,2,0), +(62397,2,0), +(62363,2,0), +(62357,2,0), +(62355,2,0), +(62307,2,0), +(62086,2,0), +(61999,2,1), +(60289,2,0), +(60101,2,0), +(59790,2,0), +(59732,2,0), +(59576,2,0), +(58596,2,0), +(58231,2,0), +(57945,2,0), +(57619,2,0), +(57610,2,0), +(57607,2,0), +(57583,2,0), +(57575,2,0), +(57544,2,0), +(57517,2,0), +(57415,2,0), +(56790,2,0), +(56570,2,0), +(56385,2,0), +(56350,2,0), +(55934,2,0), +(55820,2,0), +(55367,2,0), +(55197,2,0), +(54712,2,0), +(54666,2,0), +(54530,2,0), +(52510,2,0), +(52408,2,0), +(52339,2,0), +(52277,2,0), +(52274,2,0), +(52115,2,0), +(51383,2,0), +(51328,2,0), +(51327,2,0), +(51326,2,0), +(51325,2,0), +(51241,2,0), +(50999,2,0), +(50319,2,0), +(50026,2,0), +(50003,2,0), +(49867,2,0), +(49860,2,0), +(49765,2,0), +(49728,2,0), +(49693,2,0), +(49689,2,0), +(49158,2,0), +(49123,2,0), +(49109,2,0), +(48794,2,0), +(48738,2,0), +(48347,2,0), +(47978,2,0), +(35246,2,0), +(42576,3,0), +(42492,3,0), +(42475,3,0), +(42433,3,0), +(42350,3,0), +(42348,3,0), +(42242,3,1), +(42228,3,0), +(42220,3,0), +(42114,3,0), +(41221,3,0), +(40961,3,0), +(40960,3,0), +(40959,3,0), +(40957,3,0), +(40885,3,0), +(40603,3,0), +(40495,3,0), +(40401,3,0), +(40380,3,0), +(40341,3,0), +(40307,3,0), +(40286,3,0), +(40285,3,0), +(40284,3,0), +(40283,3,0), +(40268,3,0), +(40247,3,0), +(40246,3,0), +(40245,3,0), +(40244,3,0), +(40240,3,0), +(40222,3,0), +(40179,3,0), +(40178,3,0), +(40177,3,0), +(40176,3,0), +(40105,3,0), +(40076,3,0), +(39932,3,0), +(39887,3,0), +(39844,3,0), +(39832,3,1), +(39831,3,0), +(39558,3,0), +(39401,3,0), +(39399,3,0), +(39398,3,0), +(39393,3,0), +(39384,3,0), +(39364,3,0), +(38866,3,0), +(38680,3,0), +(38173,3,0), +(38046,3,0), +(38044,3,0), +(37970,3,0), +(37954,3,0), +(37942,3,0), +(37919,3,0), +(37913,3,0), +(37793,3,1), +(37789,3,0), +(37750,3,1), +(37504,3,0), +(37489,3,0), +(37473,3,1), +(37366,3,0), +(37134,3,0), +(36821,3,0), +(36811,3,0), +(36450,3,0), +(36449,3,1), +(36325,3,0), +(35958,3,0), +(35776,3,0), +(35734,3,0), +(35599,3,0), +(35596,3,0), +(34303,3,0), +(34200,3,0), +(34186,3,0), +(42578,3,0), +(33814,3,0), +(33783,3,0), +(33670,3,0), +(33664,3,0), +(33365,3,0), +(33240,3,0), +(33111,3,0), +(32785,3,0), +(32314,3,0), +(32307,3,0), +(32241,3,0), +(32148,3,0), +(32067,3,0), +(31927,3,0), +(31543,3,0), +(31364,3,0), +(31363,3,0), +(31333,3,0), +(30758,3,0), +(30741,3,0), +(30284,3,0), +(29945,3,0), +(29866,3,0), +(29820,3,1), +(29460,3,0), +(28373,3,0), +(28250,3,0), +(28054,3,0), +(26521,3,0), +(26519,3,0), +(26518,3,0), +(26517,3,0), +(26516,3,0), +(26490,3,0), +(26488,3,0), +(26393,3,1), +(26373,3,0), +(26338,3,0), +(26337,3,0), +(26336,3,0), +(26335,3,0), +(26334,3,0), +(26333,3,0), +(26329,3,0), +(26328,3,0), +(26327,3,0), +(26326,3,0), +(26325,3,0), +(26304,3,0), +(26295,3,0), +(26294,3,0), +(26293,3,0), +(26292,3,0), +(26291,3,0), +(26286,3,0), +(25687,3,0), +(25183,3,0), +(25181,3,0), +(25180,3,0), +(25178,3,0), +(25177,3,0), +(24973,3,0), +(24731,3,0), +(23024,3,0), +(21086,3,0), +(21014,3,0), +(20038,3,0), +(20037,3,0), +(19873,3,0), +(17179,3,0), +(16629,3,0), +(16452,3,0), +(16337,3,0), +(15998,3,0), +(13488,3,0), +(12151,3,0), +(10860,3,0), +(10836,3,0), +(10835,3,0), +(10834,3,0), +(10805,3,0), +(9257,3,0), +(9232,3,0), +(42868,3,0), +(43233,3,0), +(43539,3,0), +(43664,3,0), +(43898,3,0), +(43954,3,0), +(43963,3,0), +(43986,3,0), +(44013,3,0), +(44132,3,0), +(44213,3,0), +(44249,3,0), +(44320,3,0), +(44321,3,0), +(44375,3,0), +(44465,3,0), +(44554,3,0), +(44565,3,0), +(44603,3,0), +(44678,3,0), +(44844,3,0), +(44884,3,0), +(45030,3,0), +(45050,3,1), +(45201,3,0), +(45203,3,0), +(45404,3,0), +(45502,3,0), +(45585,3,0), +(45633,3,0), +(45635,3,0), +(45653,3,0), +(45839,3,0), +(45885,3,1), +(46417,3,0), +(46574,3,0), +(46638,3,1), +(46852,3,0), +(46896,3,0), +(47030,3,1), +(47328,3,0), +(47510,3,0), +(47628,3,0), +(47745,3,0), +(47775,3,1), +(47800,3,0), +(48198,3,0), +(48212,3,0), +(48331,3,0), +(48431,3,0), +(48882,3,0), +(48972,3,0), +(49197,3,0), +(49300,3,0), +(49308,3,0), +(49453,3,0), +(49735,3,0), +(50313,3,1), +(50348,3,0), +(50443,3,0), +(50501,3,0), +(50626,3,0), +(50639,3,0), +(50640,3,0), +(50716,3,0), +(50790,3,0), +(50791,3,0), +(50802,3,0), +(50803,3,0), +(50825,3,0), +(50826,3,0), +(51212,3,0), +(51246,3,0), +(51395,3,0), +(51511,3,0), +(51742,3,0), +(51748,3,0), +(51805,3,0), +(51846,3,0), +(52067,3,1), +(52271,3,0), +(52305,3,0), +(52479,3,0), +(52480,3,0), +(52497,3,0), +(52603,3,0), +(52683,3,0), +(52685,3,0), +(52812,3,0), +(53677,3,0), +(53679,3,0), +(53694,3,0), +(53705,3,0), +(53706,3,0), +(54272,3,0), +(54517,3,0), +(54914,3,0), +(54961,3,0), +(54990,3,0), +(55037,3,0), +(55083,3,0), +(55365,3,0), +(55479,3,0), +(55715,3,0), +(55800,3,0), +(55889,3,1), +(56095,3,0), +(56140,3,0), +(56386,3,0), +(56389,3,0), +(56578,3,0), +(56747,3,0), +(56765,3,0), +(57586,3,0), +(57800,3,0), +(57824,3,0), +(57835,3,0), +(58766,3,0), +(58825,3,0), +(59008,3,0), +(59462,3,0), +(59464,3,0), +(59564,3,0), +(59629,3,0), +(59694,3,0), +(60639,3,0), +(61126,3,0), +(61224,3,0), +(61699,3,0), +(62000,3,0), +(62056,3,0), +(62385,3,0), +(62387,3,0), +(62399,3,0), +(62565,3,0), +(62709,3,0), +(62973,3,0), +(62991,3,0), +(63019,3,0), +(63122,3,1), +(63292,3,0), +(63294,3,0), +(63295,3,0), +(63317,3,0), +(63414,3,0), +(63528,3,0), +(63766,3,0), +(63983,3,0), +(63985,3,0), +(64021,3,0), +(65044,3,0), +(65045,3,0), +(65101,3,0), +(65585,3,0), +(65586,3,0), +(65690,3,0), +(66129,3,0), +(66170,3,0), +(66598,3,0), +(67398,3,0), +(68378,3,0), +(68902,3,0), +(69007,3,0), +(69095,3,0), +(69096,3,0), +(69708,3,0), +(69783,3,0), +(69797,3,0), +(69799,3,0), +(69802,3,0), +(69985,3,0), +(70028,3,0), +(70037,3,0), +(70194,3,0), +(70521,3,0), +(70564,3,0), +(70590,3,0), +(70997,3,0), +(70998,3,0), +(70999,3,0), +(71278,3,1), +(71621,3,0), +(71704,3,0), +(72155,3,1), +(72162,3,1), +(72274,3,1), +(72297,3,1), +(72460,3,1), +(72548,3,1), +(72549,3,1), +(72550,3,1), +(72619,3,1), +(72620,3,1), +(72679,3,0), +(72771,3,0), +(72850,3,0), +(72851,3,0), +(72852,3,0), +(74318,3,0), +(74319,3,0), +(74320,3,0), +(74472,3,0), +(75509,3,0), +(75553,3,1), +(75766,3,1), +(34012,3,0), +(74271,4,0), +(74270,4,0), +(72096,4,1), +(72034,4,1), +(71615,4,0), +(70827,4,0), +(69425,4,0), +(69164,4,0), +(69162,4,0), +(68981,4,0), +(68788,4,1), +(67816,4,0), +(67796,4,0), +(65370,4,0), +(65333,4,0), +(64626,4,0), +(62826,4,0), +(62489,4,0), +(62466,4,0), +(62457,4,0), +(62345,4,0), +(62308,4,0), +(60206,4,0), +(58185,4,0), +(55896,4,0), +(55349,4,0), +(54109,4,0), +(54107,4,0), +(51678,4,0), +(50652,4,0), +(49556,4,0), +(48610,4,0), +(48277,4,0), +(48224,4,0), +(47674,4,0), +(47109,4,0), +(45922,4,0), +(44969,4,0), +(44737,4,0), +(44687,4,0), +(44626,4,0), +(44233,4,0), +(40647,4,0), +(40259,4,0), +(39246,4,0), +(36904,4,0), +(36460,4,0), +(36374,4,0), +(30532,4,0), +(28995,4,0), +(10451,4,0), +(9735,4,0), +(8900,4,0), +(8899,4,0), +(8898,4,0), +(8202,4,0), +(74272,4,0), +(69767,5,0), +(65590,5,0), +(62386,5,0), +(55588,5,0), +(54713,5,0), +(49464,5,0), +(49460,5,0), +(49346,5,0), +(47310,5,1), +(45676,5,0), +(44217,5,0), +(43977,5,0), +(41962,5,0), +(40789,5,0), +(40503,5,0), +(38729,5,0), +(38312,5,0), +(38106,5,0), +(38105,5,0), +(38104,5,0), +(38103,5,0), +(38102,5,0), +(38101,5,0), +(38100,5,0), +(38099,5,0), +(37206,5,0), +(37205,5,0), +(37204,5,0), +(36817,5,0), +(34630,5,0), +(21866,5,0), +(21794,5,0), +(19832,5,0), +(19250,5,0), +(8913,5,0), +(67308,6,0), +(67307,6,0), +(67306,6,0), +(67305,6,0), +(67304,6,0), +(67303,6,0), +(65876,6,0), +(65875,6,0), +(63041,6,0), +(62560,6,0), +(59099,6,1), +(44608,6,0), +(43702,6,0), +(43080,6,0), +(43056,6,0), +(40902,6,0), +(40657,6,0), +(28803,6,1), +(16054,6,0), +(8712,6,0), +(75863,7,1), +(75448,7,1), +(74412,7,1), +(74323,7,0), +(74322,7,0), +(74321,7,0), +(73028,7,0), +(72622,7,1), +(72621,7,1), +(72459,7,1), +(72273,7,0), +(72272,7,0), +(71618,7,0), +(71614,7,0), +(71279,7,1), +(70982,7,0), +(70981,7,0), +(70952,7,0), +(69540,7,0), +(67751,7,0), +(66905,7,0), +(66667,7,0), +(65126,7,0), +(64218,7,0), +(63059,7,0), +(62942,7,0), +(62705,7,0), +(61920,7,0), +(61715,7,0), +(61714,7,0), +(61632,7,0), +(60532,7,0), +(60430,7,0), +(59474,7,0), +(59465,7,0), +(57409,7,0), +(57405,7,0), +(57056,7,1), +(56694,7,0), +(56454,7,0), +(54160,7,0), +(53605,7,0), +(52319,7,0), +(51719,7,0), +(50747,7,0), +(50646,7,0), +(50645,7,0), +(50627,7,0), +(50218,7,0), +(49889,7,0), +(48742,7,0), +(48552,7,0), +(46158,7,0), +(42287,7,0), +(42265,7,1), +(42079,7,0), +(42004,7,1), +(41284,7,0), +(41113,7,0), +(41112,7,0), +(41111,7,0), +(41110,7,0), +(41071,7,0), +(41064,7,1), +(40931,7,0), +(40929,7,0), +(40905,7,0), +(40900,7,0), +(40851,7,0), +(40370,7,0), +(40172,7,0), +(40171,7,0), +(40170,7,0), +(40169,7,0), +(40075,7,1), +(39698,7,0), +(39686,7,0), +(39218,7,0), +(38920,7,0), +(38774,7,0), +(38484,7,0), +(38449,7,0), +(38371,7,0), +(37076,7,0), +(35957,7,1), +(35754,7,0), +(35289,7,0), +(34350,7,0), +(34187,7,0), +(31625,7,0), +(31624,7,0), +(31617,7,0), +(30939,7,1), +(30659,7,0), +(30657,7,0), +(30531,7,0), +(30098,7,0), +(28681,7,1), +(25790,7,0), +(25029,7,0), +(23015,7,0), +(22710,7,0), +(20553,7,0), +(10732,7,0), +(10348,7,0), +(7082,7,0), +(5628,7,0), +(804,7,0), +(802,7,0), +(54069,1,0), +(56251,1,0), +(58630,1,0); + +-- remove redundant entries +DELETE FROM `conditions` WHERE `ConditionTypeOrReference` = 18 AND `ConditionValue1` = 1 AND `ConditionValue2` = 0 AND `SourceEntry` IN (SELECT `id` FROM `temp_convert_spells` WHERE onlyPlayers); + +-- set source group if available in db +UPDATE `conditions` SET `SourceGroup` = `ConditionValue3`, `ConditionValue3` = 0 WHERE `ConditionTypeOrReference` = 18; + +-- set source group in case of old default (not set) source group +UPDATE `conditions` SET `SourceGroup` = (SELECT `effMask` FROM `temp_convert_spells` WHERE `id` = `SourceEntry`) WHERE `SourceGroup` = 0 AND `ConditionTypeOrReference` = 18; + +CREATE TABLE `temp_cond_vals` +( + `sourceGroup` INT(11), + `sourceEntry` INT(11), + `conditionValue1` INT(11), + `conditionValue2` INT(11), + `elseGroup` INT(11) AUTO_INCREMENT, + PRIMARY KEY (`sourceGroup`, `sourceEntry`, `elseGroup`) +) ENGINE=MYISAM; + +INSERT INTO `temp_cond_vals` (`sourceGroup`, `sourceEntry`, `conditionValue1`, `conditionValue2`) SELECT `SourceGroup`, `SourceEntry`, `ConditionValue1`, `ConditionValue2` FROM `conditions` WHERE `ConditionTypeOrReference` = 18; + +-- set correct else group +UPDATE `conditions` SET `ElseGroup` = (SELECT `elseGroup` FROM `temp_cond_vals` WHERE `sourceGroup` = `conditions`.`SourceGroup` AND `sourceEntry` = `conditions`.`SourceEntry` AND `conditionValue1` = `conditions`.`ConditionValue1` AND `conditionValue2` = `conditions`.`ConditionValue2`)-1 WHERE `ConditionTypeOrReference` = 18; + +-- old condition type 3 (caster's minion) +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`) +SELECT `SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `ElseGroup`, 33, 0, 1, 3 FROM `conditions` WHERE `ConditionTypeOrReference` = 18 AND `ConditionValue1` = 3; + +UPDATE `conditions` SET `ConditionTypeOrReference` = 31 WHERE `ConditionTypeOrReference` = 18 AND `ConditionValue1` = 3; + +-- old condition type 2 (dead creature) +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `NegativeCondition`) +SELECT `SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `ElseGroup`, 36, 0, 0, 0, 1 FROM `conditions` WHERE `ConditionTypeOrReference` = 18 AND `ConditionValue1` = 2; + +UPDATE `conditions` SET `ConditionTypeOrReference` = 31, `ConditionValue1` = 3 WHERE `ConditionTypeOrReference` = 18 AND `ConditionValue1` = 2; + +-- old condition type 1 (creature) +UPDATE `conditions` SET `ConditionTypeOrReference` = 31, `ConditionValue1` = 3 WHERE `ConditionTypeOrReference` = 18 AND `ConditionValue1` = 1 AND `ConditionValue2`; + +-- old condition type 1 (player) +UPDATE `conditions` SET `ConditionTypeOrReference` = 32, `ConditionValue1` = 0x90 WHERE `ConditionTypeOrReference` = 18 AND `ConditionValue1` = 1 AND NOT `ConditionValue2`; + +-- old condition type 0 (gameobject) +UPDATE `conditions` SET `ConditionTypeOrReference` = 31, `ConditionValue1` = 5 WHERE `ConditionTypeOrReference` = 18 AND `ConditionValue1` = 0; + +DROP TABLE `temp_convert_spells`; +DROP TABLE `temp_cond_vals`;
\ No newline at end of file diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 550814ccf3f..af0c1a07c2b 100755 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -26,6 +26,7 @@ #include "ConditionMgr.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "Spell.h" // Checks if object meets the condition // Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI) @@ -94,14 +95,14 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) } case CONDITION_CLASS: { - if (Player* player = object->ToPlayer()) - condMeets = player->getClassMask() & ConditionValue1; + if (Unit* unit = object->ToUnit()) + condMeets = unit->getClassMask() & ConditionValue1; break; } case CONDITION_RACE: { - if (Player* player = object->ToPlayer()) - condMeets = player->getRaceMask() & ConditionValue1; + if (Unit* unit = object->ToUnit()) + condMeets = unit->getRaceMask() & ConditionValue1; break; } case CONDITION_SKILL: @@ -153,9 +154,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) condMeets = ((InstanceMap*)map)->GetInstanceScript()->GetData(ConditionValue1) == ConditionValue2; break; } - case CONDITION_SPELL_SCRIPT_TARGET: - condMeets = true;//spell target condition is handled in spellsystem, here it is always true - break; case CONDITION_MAPID: condMeets = object->GetMapId() == ConditionValue1; break; @@ -291,12 +289,153 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) return condMeets && script; } +uint32 Condition::GetSearcherTypeMaskForCondition() +{ + // build mask of types for which condition can return true + // this is used for speeding up gridsearches + if (NegativeCondition) + return (GRID_MAP_TYPE_MASK_ALL); + uint32 mask = 0; + switch (ConditionType) + { + case CONDITION_NONE: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_AURA: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ITEM: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ITEM_EQUIPPED: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ZONEID: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_REPUTATION_RANK: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ACHIEVEMENT: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_TEAM: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_CLASS: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_RACE: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_SKILL: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_QUESTREWARDED: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_QUESTTAKEN: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_QUEST_COMPLETE: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_QUEST_NONE: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_ACTIVE_EVENT: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_INSTANCE_DATA: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_MAPID: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_AREAID: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_SPELL: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_LEVEL: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_DRUNKENSTATE: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_NEAR_CREATURE: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_NEAR_GAMEOBJECT: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_OBJECT_ENTRY: + switch (ConditionValue1) + { + case TYPEID_UNIT: + mask |= GRID_MAP_TYPE_MASK_CREATURE; + break; + case TYPEID_PLAYER: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; + case TYPEID_GAMEOBJECT: + mask |= GRID_MAP_TYPE_MASK_GAMEOBJECT; + break; + case TYPEID_CORPSE: + mask |= GRID_MAP_TYPE_MASK_CORPSE; + break; + default: + break; + } + case CONDITION_TYPE_MASK: + if (ConditionValue1 & TYPEMASK_UNIT) + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + if (ConditionValue1 & TYPEMASK_PLAYER) + mask |= GRID_MAP_TYPE_MASK_PLAYER; + if (ConditionValue1 & TYPEMASK_GAMEOBJECT) + mask |= GRID_MAP_TYPE_MASK_GAMEOBJECT; + if (ConditionValue1 & TYPEMASK_CORPSE) + mask |= GRID_MAP_TYPE_MASK_CORPSE; + break; + case CONDITION_RELATION_TO: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_REACTION_TO: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_DISTANCE_TO: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_ALIVE: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_HP_VAL: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_HP_PCT: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; + case CONDITION_WORLD_STATE: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + case CONDITION_PHASEMASK: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; + default: + ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); + break; + } + return mask; +} + uint32 Condition::GetMaxAvailableConditionTargets() { // returns number of targets which are available for given source type switch(SourceType) { case CONDITION_SOURCE_TYPE_SPELL: + case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE: case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: @@ -327,8 +466,49 @@ ConditionList ConditionMgr::GetConditionReferences(uint32 refId) return conditions; } +uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionList const& conditions) +{ + if (conditions.empty()) + return GRID_MAP_TYPE_MASK_ALL; + // groupId, typeMask + std::map<uint32, uint32> ElseGroupStore; + for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i) + { + // no point of having not loaded conditions in list + ASSERT((*i)->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list"); + std::map<uint32, uint32>::const_iterator itr = ElseGroupStore.find((*i)->ElseGroup); + // group not filled yet, fill with widest mask possible + if (itr == ElseGroupStore.end()) + ElseGroupStore[(*i)->ElseGroup] = GRID_MAP_TYPE_MASK_ALL; + // no point of checking anymore, empty mask + else if (!(*itr).second) + continue; + + if ((*i)->ReferenceId) // handle reference + { + ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->ReferenceId); + ASSERT(ref != ConditionReferenceStore.end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference"); + ElseGroupStore[(*i)->ElseGroup] &= GetSearcherTypeMaskForConditionList((*ref).second); + } + else // handle normal condition + { + // object will match conditions in one ElseGroupStore only when it matches all of them + // so, let's find a smallest possible mask which satisfies all conditions + ElseGroupStore[(*i)->ElseGroup] &= (*i)->GetSearcherTypeMaskForCondition(); + } + } + // object will match condition when one of the checks in ElseGroupStore is matching + // so, let's include all possible masks + uint32 mask = 0; + for (std::map<uint32, uint32>::const_iterator i = ElseGroupStore.begin(); i != ElseGroupStore.end(); ++i) + mask |= i->second; + + return mask; +} + bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) { + // groupId, groupCheckPassed std::map<uint32, bool> ElseGroupStore; for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i) { @@ -391,6 +571,32 @@ bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, Con return IsObjectMeetToConditionList(sourceInfo, conditions); } +bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const +{ + return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || + sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION || + sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL || + sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || + sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT); +} + +bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const +{ + return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT); +} + ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) { ConditionList spellCond; @@ -487,6 +693,7 @@ void ConditionMgr::LoadConditions(bool isReload) sLog->outString("Re-Loading `gossip_menu_option` Table for Conditions!"); sObjectMgr->LoadGossipMenuItems(); + sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists(); } QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, " @@ -583,16 +790,23 @@ void ConditionMgr::LoadConditions(bool isReload) } //Grouping is only allowed for some types (loot templates, gossip menus, gossip items) - if (cond->SourceGroup && !isGroupable(cond->SourceType)) + if (cond->SourceGroup && !CanHaveSourceGroupSet(cond->SourceType)) + { + sLog->outErrorDb("Condition type %u has not allowed value of SourceGroup = %u!", uint32(cond->SourceType), cond->SourceGroup); + delete cond; + continue; + } + if (cond->SourceId && !CanHaveSourceIdSet(cond->SourceType)) { - sLog->outErrorDb("Condition type %u has not allowed grouping %u!", uint32(cond->SourceType), cond->SourceGroup); + sLog->outErrorDb("Condition type %u has not allowed value of SourceId = %u!", uint32(cond->SourceType), cond->SourceId); delete cond; continue; } - else if (cond->SourceGroup) + + if (cond->SourceGroup) { bool valid = false; - //handle grouped conditions + // handle grouped conditions switch (cond->SourceType) { case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: @@ -637,6 +851,9 @@ void ConditionMgr::LoadConditions(bool isReload) case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: valid = addToGossipMenuItems(cond); break; + case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: + valid = addToSpellImplicitTargetConditions(cond); + break; case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: { //if no list for vehicle create one @@ -771,6 +988,78 @@ bool ConditionMgr::addToGossipMenuItems(Condition* cond) return false; } +bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) +{ + uint32 conditionEffMask = cond->SourceGroup; + SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->GetSpellInfo(cond->SourceEntry)); + ASSERT(spellInfo); + std::list<uint32> sharedMasks; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + // check if effect is already a part of some shared mask + bool found = false; + for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) + { + if ((1<<i) & *itr) + { + found = true; + break; + } + } + if (found) + continue; + + // build new shared mask with found effect + uint32 sharedMask = (1<<i); + ConditionList* cmp = spellInfo->Effects[i].ImplicitTargetConditions; + for (uint8 effIndex = i+1; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + { + if (spellInfo->Effects[effIndex].ImplicitTargetConditions == cmp) + sharedMask |= 1<<effIndex; + } + sharedMasks.push_back(sharedMask); + } + + for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) + { + // some effect indexes should have same data + if (uint32 commonMask = *itr & conditionEffMask) + { + uint8 firstEffIndex = 0; + for (; firstEffIndex < MAX_SPELL_EFFECTS; ++firstEffIndex) + if ((1<<firstEffIndex) & *itr) + break; + + // get shared data + ConditionList* sharedList = spellInfo->Effects[firstEffIndex].ImplicitTargetConditions; + + // there's already data entry for that sharedMask + if (sharedList) + { + // we have overlapping masks in db + if (conditionEffMask != *itr) + { + sLog->outErrorDb("SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set - " + "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring.", cond->SourceEntry, cond->SourceGroup); + return false; + } + } + // no data for shared mask, we can create new submask + else + { + // add new list, create new shared mask + sharedList = new ConditionList(); + for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i) + if ((1<<i) & commonMask) + spellInfo->Effects[i].ImplicitTargetConditions = sharedList; + } + sharedList->push_back(cond); + break; + } + } + return true; +} + bool ConditionMgr::isSourceTypeValid(Condition* cond) { if (cond->SourceType == CONDITION_SOURCE_TYPE_NONE || cond->SourceType >= CONDITION_SOURCE_TYPE_MAX) @@ -985,64 +1274,48 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) } break; } - case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET: + case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: { - if (cond->ConditionType != CONDITION_SPELL_SCRIPT_TARGET) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry); + if (!spellInfo) { - sLog->outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_SPELL_SCRIPT_TARGET(18) is valid for CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET(14), ignoring.", cond->SourceEntry, uint32(cond->ConditionType)); + sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); return false; } - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry); - if (!spellProto) + if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup) { - sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry); + sLog->outErrorDb("SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set , ignoring.", cond->SourceEntry, cond->SourceGroup); return false; } - bool targetfound = false; + uint32 origGroup = cond->SourceGroup; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_SRC_AREA_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_NEARBY_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_NEARBY_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_NEARBY_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_NEARBY_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_SRC_AREA || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_SRC_AREA || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_DEST_AREA || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_DEST_AREA || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_DEST_NEARBY_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_DEST_NEARBY_ENTRY || - spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_CONE_ENTRY || - spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_CONE_ENTRY) + if (!((1<<i) & cond->SourceGroup)) + continue; + + switch (spellInfo->Effects[i].TargetA.GetSelectionCategory()) { - targetfound = true; - //break; + case TARGET_SELECT_CATEGORY_NEARBY: + case TARGET_SELECT_CATEGORY_CONE: + case TARGET_SELECT_CATEGORY_AREA: + continue; } - else if (cond->ConditionValue3 & (1 << i)) + switch (spellInfo->Effects[i].TargetB.GetSelectionCategory()) { - cond->ConditionValue3 &= ~(1 << i); - sLog->outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DEST_NEARBY_ENTRY (46)" - ", TARGET_UNIT_SRC_AREA_ENTRY(7), TARGET_UNIT_DEST_AREA_ENTRY(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)" - "TARGET_GAMEOBJECT_SRC_AREA(51), TARGET_GAMEOBJECT_DEST_AREA(52) in effect %u", cond->SourceEntry, uint32(i)); + case TARGET_SELECT_CATEGORY_NEARBY: + case TARGET_SELECT_CATEGORY_CONE: + case TARGET_SELECT_CATEGORY_AREA: + continue; } + sLog->outErrorDb("SourceEntry %u SourceGroup %u in `condition` table - spell %u does not have implicit targets of types: _AREA_, _CONE_, _NEARBY_ for effect %u, SourceGroup needs correction, ignoring.", cond->SourceEntry, origGroup, cond->SourceEntry, uint32(i)); + cond->SourceGroup &= ~(1<<i); } - if (!targetfound && !cond->ConditionValue3) // cond->mConditionValue3 already errored up there - { - sLog->outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DEST_NEARBY_ENTRY (46)" - ", TARGET_UNIT_SRC_AREA_ENTRY(7), TARGET_UNIT_DEST_AREA_ENTRY(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)" - "TARGET_GAMEOBJECT_SRC_AREA(51), TARGET_GAMEOBJECT_DEST_AREA(52)", cond->SourceEntry); - return false; - } - if ((cond->ConditionValue1 == SPELL_TARGET_TYPE_DEAD) && !spellProto->IsAllowingDeadTarget()) - { - sLog->outErrorDb("SourceEntry %u in `condition` table does have SPELL_TARGET_TYPE_DEAD specified but spell does not have SPELL_ATTR2_CAN_TARGET_DEAD", cond->SourceEntry); + // all effects were removed, no need to add the condition at all + if (!cond->SourceGroup) return false; - } break; } case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE: @@ -1318,46 +1591,6 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog->outErrorDb("Race condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_SPELL_SCRIPT_TARGET: - { - if (cond->ConditionValue1 >= MAX_SPELL_TARGET_TYPE) - { - sLog->outErrorDb("SpellTarget condition has non existing spell target type (%u), skipped", cond->ConditionValue1); - return false; - } - - switch (cond->ConditionValue1) - { - case SPELL_TARGET_TYPE_GAMEOBJECT: - { - if (cond->ConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->ConditionValue2)) - { - sLog->outErrorDb("SpellTarget condition has non existing gameobject (%u) as target, skipped", cond->ConditionValue2); - return false; - } - break; - } - case SPELL_TARGET_TYPE_CONTROLLED: - case SPELL_TARGET_TYPE_CREATURE: - case SPELL_TARGET_TYPE_DEAD: - { - if (cond->ConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->ConditionValue2)) - { - sLog->outErrorDb("SpellTarget condition has non existing creature template entry (%u) as target, skipped", cond->ConditionValue2); - return false; - } - - const CreatureTemplate* cInfo = sObjectMgr->GetCreatureTemplate(cond->ConditionValue2); - if (cond->SourceEntry == 30427 && !cInfo->SkinLootId) - { - sLog->outErrorDb("SpellTarget condition has creature entry %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!, skipped", cond->ConditionValue2); - return false; - } - break; - } - } - break; - } case CONDITION_MAPID: { MapEntry const* me = sMapStore.LookupEntry(cond->ConditionValue1); @@ -1598,6 +1831,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog->outErrorDb("Phasemask condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } + case CONDITION_UNUSED_18: + sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_18 in `conditions` table - ignoring"); + return false; case CONDITION_UNUSED_19: sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_19 in `conditions` table - ignoring"); return false; diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 9911aa2a98a..a1c6146d0cf 100755 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -48,7 +48,7 @@ enum ConditionTypes CONDITION_CLASS = 15, // class 0 0 true if player's class is equal to class CONDITION_RACE = 16, // race 0 0 true if player's race is equal to race CONDITION_ACHIEVEMENT = 17, // achievement_id 0 0 true if achievement is complete - CONDITION_SPELL_SCRIPT_TARGET = 18, // SpellScriptTargetType, TargetEntry, 0 + CONDITION_UNUSED_18 = 18, // CONDITION_UNUSED_19 = 19, // CONDITION_UNUSED_20 = 20, // CONDITION_UNUSED_21 = 21, // @@ -87,7 +87,7 @@ enum ConditionSourceType CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE = 10, CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE = 11, CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE = 12, - CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET = 13, + CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET = 13, CONDITION_SOURCE_TYPE_GOSSIP_MENU = 14, CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION = 15, CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE = 16, @@ -173,6 +173,7 @@ struct Condition } bool Meets(ConditionSourceInfo& sourceInfo); + uint32 GetSearcherTypeMaskForCondition(); bool isLoaded() const { return ConditionType > CONDITION_NONE || ReferenceId; } uint32 GetMaxAvailableConditionTargets(); }; @@ -198,9 +199,12 @@ class ConditionMgr bool isConditionTypeValid(Condition* cond); ConditionList GetConditionReferences(uint32 refId); + uint32 GetSearcherTypeMaskForConditionList(ConditionList const& conditions); bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions); bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions); bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions); + bool CanHaveSourceGroupSet(ConditionSourceType sourceType) const; + bool CanHaveSourceIdSet(ConditionSourceType sourceType) const; ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry); ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId); ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType); @@ -211,29 +215,10 @@ class ConditionMgr bool addToLootTemplate(Condition* cond, LootTemplate* loot); bool addToGossipMenus(Condition* cond); bool addToGossipMenuItems(Condition* cond); + bool addToSpellImplicitTargetConditions(Condition* cond); bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions); - bool isGroupable(ConditionSourceType sourceType) const - { - return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || - sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || - sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL || - sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT); - } - void Clean(); // free up resources std::list<Condition*> AllocatedMemoryStore; // some garbage collection :) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index aadf9f44b0b..c98364ecb2d 100755 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1085,9 +1085,9 @@ bool Object::PrintIndexError(uint32 index, bool set) const return false; } -bool Position::HasInLine(Unit const* target, float distance, float width) const +bool Position::HasInLine(WorldObject const* target, float width) const { - if (!HasInArc(M_PI, target) || !target->IsWithinDist3d(m_positionX, m_positionY, m_positionZ, distance)) + if (!HasInArc(M_PI, target)) return false; width += target->GetObjectSize(); float angle = GetRelativeAngle(target); @@ -1502,14 +1502,14 @@ bool WorldObject::IsInBetween(const WorldObject* obj1, const WorldObject* obj2, return (size * size) >= GetExactDist2dSq(obj1->GetPositionX() + cos(angle) * dist, obj1->GetPositionY() + sin(angle) * dist); } -bool WorldObject::isInFront(WorldObject const* target, float distance, float arc) const +bool WorldObject::isInFront(WorldObject const* target, float arc) const { - return IsWithinDist(target, distance) && HasInArc(arc, target); + return HasInArc(arc, target); } -bool WorldObject::isInBack(WorldObject const* target, float distance, float arc) const +bool WorldObject::isInBack(WorldObject const* target, float arc) const { - return IsWithinDist(target, distance) && !HasInArc(2 * M_PI - arc, target); + return !HasInArc(2 * M_PI - arc, target); } void WorldObject::GetRandomPoint(const Position &pos, float distance, float &rand_x, float &rand_y, float &rand_z) const diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index c14b7599d5f..7b3fcc4a337 100755 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -451,7 +451,7 @@ struct Position bool IsInDist(const Position* pos, float dist) const { return GetExactDistSq(pos) < dist * dist; } bool HasInArc(float arcangle, const Position* pos) const; - bool HasInLine(Unit const* target, float distance, float width) const; + bool HasInLine(WorldObject const* target, float width) const; std::string ToString() const; }; ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); @@ -707,8 +707,8 @@ class WorldObject : public Object, public WorldLocation bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const; bool IsInRange2d(float x, float y, float minRange, float maxRange) const; bool IsInRange3d(float x, float y, float z, float minRange, float maxRange) const; - bool isInFront(WorldObject const* target, float distance, float arc = M_PI) const; - bool isInBack(WorldObject const* target, float distance, float arc = M_PI) const; + bool isInFront(WorldObject const* target, float arc = M_PI) const; + bool isInBack(WorldObject const* target, float arc = M_PI) const; bool IsInBetween(const WorldObject* obj1, const WorldObject* obj2, float size = 0) const; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 47c3c1a9395..0e3e2f593fa 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -10004,6 +10004,7 @@ Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo) && _IsValidAttackTarget(magnet, spellInfo) && IsWithinLOSInMap(magnet)) { + // TODO: handle this charge drop by proc in cast phase on explicit target (*itr)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE); return magnet; } @@ -16178,26 +16179,6 @@ bool Unit::IsInRaidWith(Unit const* unit) const return false; } -bool Unit::IsTargetMatchingCheck(Unit const* target, SpellTargetSelectionCheckTypes check) const -{ - switch (check) - { - case TARGET_SELECT_CHECK_ENEMY: - if (IsControlledByPlayer()) - return !IsFriendlyTo(target); - else - return IsHostileTo(target); - case TARGET_SELECT_CHECK_ALLY: - return IsFriendlyTo(target); - case TARGET_SELECT_CHECK_PARTY: - return IsInPartyWith(target); - case TARGET_SELECT_CHECK_RAID: - return IsInRaidWith(target); - default: - return true; - } -} - void Unit::GetRaidMember(std::list<Unit*> &nearMembers, float radius) { Player* owner = GetCharmerOrOwnerPlayerOrPlayerItself(); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 66b0bcbeb54..e55141a3bae 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1394,7 +1394,6 @@ class Unit : public WorldObject bool IsNeutralToAll() const; bool IsInPartyWith(Unit const* unit) const; bool IsInRaidWith(Unit const* unit) const; - bool IsTargetMatchingCheck(Unit const* target, SpellTargetSelectionCheckTypes check) const; void GetPartyMemberInDist(std::list<Unit*> &units, float dist); void GetPartyMembers(std::list<Unit*> &units); void GetRaidMember(std::list<Unit*> &units, float dist); diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index 8651680cb49..d096bb7ab63 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -65,6 +65,16 @@ typedef GridRefManager<DynamicObject> DynamicObjectMapType; typedef GridRefManager<GameObject> GameObjectMapType; typedef GridRefManager<Player> PlayerMapType; +enum GridMapTypeMask +{ + GRID_MAP_TYPE_MASK_CORPSE = 0x01, + GRID_MAP_TYPE_MASK_CREATURE = 0x02, + GRID_MAP_TYPE_MASK_DYNAMICOBJECT = 0x04, + GRID_MAP_TYPE_MASK_GAMEOBJECT = 0x08, + GRID_MAP_TYPE_MASK_PLAYER = 0x10, + GRID_MAP_TYPE_MASK_ALL = 0x1F +}; + typedef Grid<Player, AllWorldObjectTypes, AllGridObjectTypes> GridType; typedef NGrid<MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 2446e9d4276..17d3066e64d 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -343,24 +343,17 @@ bool AnyDeadUnitObjectInRangeCheck::operator()(Creature* u) bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Player* u) { - return AnyDeadUnitObjectInRangeCheck::operator()(u) - && (i_spellInfo->CheckTarget(i_searchObj, u, true) == SPELL_CAST_OK) - && i_searchObj->IsTargetMatchingCheck(u, i_check); + return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u); } bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Corpse* u) { - Player* owner = ObjectAccessor::FindPlayer(u->GetOwnerGUID()); - return owner && AnyDeadUnitObjectInRangeCheck::operator()(u) - && (i_spellInfo->CheckTarget(i_searchObj, owner, true) == SPELL_CAST_OK) - && i_searchObj->IsTargetMatchingCheck(owner, i_check); + return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u); } bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u) { - return AnyDeadUnitObjectInRangeCheck::operator()(u) - && (i_spellInfo->CheckTarget(i_searchObj, u, true) == SPELL_CAST_OK) - && i_searchObj->IsTargetMatchingCheck(u, i_check); + return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u); } template void ObjectUpdater::Visit<GameObject>(GameObjectMapType &); diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 12e3fda0484..21f27d6a453 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -30,6 +30,7 @@ #include "Player.h" #include "Unit.h" #include "CreatureAI.h" +#include "Spell.h" class Player; //class Map; @@ -168,12 +169,33 @@ namespace Trinity template<class Check> struct WorldObjectSearcher { + uint32 i_mapTypeMask; uint32 i_phaseMask; WorldObject* &i_object; Check &i_check; - WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) {} + WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check), i_mapTypeMask(mapTypeMask) {} + + void Visit(GameObjectMapType &m); + void Visit(PlayerMapType &m); + void Visit(CreatureMapType &m); + void Visit(CorpseMapType &m); + void Visit(DynamicObjectMapType &m); + + template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {} + }; + + template<class Check> + struct WorldObjectLastSearcher + { + uint32 i_mapTypeMask; + uint32 i_phaseMask; + WorldObject* &i_object; + Check &i_check; + + WorldObjectLastSearcher(WorldObject const* searcher, WorldObject* & result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check), i_mapTypeMask(mapTypeMask) {} void Visit(GameObjectMapType &m); void Visit(PlayerMapType &m); @@ -187,12 +209,13 @@ namespace Trinity template<class Check> struct WorldObjectListSearcher { + uint32 i_mapTypeMask; uint32 i_phaseMask; std::list<WorldObject*> &i_objects; Check& i_check; - WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*> &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {} + WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*> &objects, Check & check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check), i_mapTypeMask(mapTypeMask) {} void Visit(PlayerMapType &m); void Visit(CreatureMapType &m); @@ -206,14 +229,17 @@ namespace Trinity template<class Do> struct WorldObjectWorker { + uint32 i_mapTypeMask; uint32 i_phaseMask; Do const& i_do; - WorldObjectWorker(WorldObject const* searcher, Do const& _do) - : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {} + WorldObjectWorker(WorldObject const* searcher, Do const& _do, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : i_phaseMask(searcher->GetPhaseMask()), i_do(_do), i_mapTypeMask(mapTypeMask) {} void Visit(GameObjectMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) + return; for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) i_do(itr->getSource()); @@ -221,12 +247,16 @@ namespace Trinity void Visit(PlayerMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) + return; for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) i_do(itr->getSource()); } void Visit(CreatureMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) + return; for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) i_do(itr->getSource()); @@ -234,6 +264,8 @@ namespace Trinity void Visit(CorpseMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) + return; for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) i_do(itr->getSource()); @@ -241,6 +273,8 @@ namespace Trinity void Visit(DynamicObjectMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) + return; for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) i_do(itr->getSource()); @@ -527,73 +561,11 @@ namespace Trinity // CHECKS && DO classes // WorldObject check classes - class RaiseDeadObjectCheck - { - public: - RaiseDeadObjectCheck(Unit* source, float range) : _source(source), _range(range) {} - bool operator()(Creature* u) - { - if (_source->GetTypeId() != TYPEID_PLAYER || !((Player*)_source)->isHonorOrXPTarget(u) || - u->getDeathState() != CORPSE || - (u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0 || - (u->GetDisplayId() != u->GetNativeDisplayId())) - return false; - - return _source->IsWithinDistInMap(u, _range); - } - bool operator()(Player* u) - { - if (_source == u || _source->GetTypeId() != TYPEID_PLAYER || !((Player*)_source)->isHonorOrXPTarget(u) || - u->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST) || u->isInFlight() || !u->isDead() || - (u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0) - return false; - return _source->IsWithinDistInMap(u, _range); - } - - bool operator()(Corpse* u) - { - if (_source->GetTypeId() != TYPEID_PLAYER || u->GetType() == CORPSE_BONES) - return false; - - return _source->IsWithinDistInMap(u, _range); - } - template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; } - private: - Unit* const _source; - float _range; - }; - - class ExplodeCorpseObjectCheck - { - public: - ExplodeCorpseObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} - bool operator()(Player* u) - { - if (u->getDeathState() != CORPSE || u->isInFlight() || - u->HasAuraType(SPELL_AURA_GHOST) || (u->GetDisplayId() != u->GetNativeDisplayId())) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } - bool operator()(Creature* u) - { - if (u->getDeathState() != CORPSE || u->isInFlight() || - (u->GetDisplayId() != u->GetNativeDisplayId()) || - (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL) != 0) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } - template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; } - private: - Unit* const i_funit; - float i_range; - }; class AnyDeadUnitObjectInRangeCheck { public: - AnyDeadUnitObjectInRangeCheck(Unit const* searchObj, float range) : i_searchObj(searchObj), i_range(range) {} + AnyDeadUnitObjectInRangeCheck(Unit* searchObj, float range) : i_searchObj(searchObj), i_range(range) {} bool operator()(Player* u); bool operator()(Corpse* u); bool operator()(Creature* u); @@ -606,15 +578,16 @@ namespace Trinity class AnyDeadUnitSpellTargetInRangeCheck : public AnyDeadUnitObjectInRangeCheck { public: - AnyDeadUnitSpellTargetInRangeCheck(Unit const* searchObj, float range, SpellInfo const* spellInfo, SpellTargetSelectionCheckTypes check) - : AnyDeadUnitObjectInRangeCheck(searchObj, range), i_spellInfo(spellInfo), i_check(check) {} + AnyDeadUnitSpellTargetInRangeCheck(Unit* searchObj, float range, SpellInfo const* spellInfo, SpellTargetCheckTypes check) + : AnyDeadUnitObjectInRangeCheck(searchObj, range), i_spellInfo(spellInfo), i_check(searchObj, searchObj, spellInfo, check, NULL) + {} bool operator()(Player* u); bool operator()(Corpse* u); bool operator()(Creature* u); template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; } protected: SpellInfo const* i_spellInfo; - SpellTargetSelectionCheckTypes i_check; + WorldObjectSpellTargetCheck i_check; }; // WorldObject do classes diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index 34fe7757c5f..40b3863679b 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -51,6 +51,9 @@ inline void Trinity::ObjectUpdater::Visit(CreatureMapType &m) template<class Check> void Trinity::WorldObjectSearcher<Check>::Visit(GameObjectMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) + return; + // already found if (i_object) return; @@ -71,6 +74,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(GameObjectMapType &m) template<class Check> void Trinity::WorldObjectSearcher<Check>::Visit(PlayerMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) + return; + // already found if (i_object) return; @@ -91,6 +97,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(PlayerMapType &m) template<class Check> void Trinity::WorldObjectSearcher<Check>::Visit(CreatureMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) + return; + // already found if (i_object) return; @@ -111,6 +120,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(CreatureMapType &m) template<class Check> void Trinity::WorldObjectSearcher<Check>::Visit(CorpseMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) + return; + // already found if (i_object) return; @@ -131,6 +143,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(CorpseMapType &m) template<class Check> void Trinity::WorldObjectSearcher<Check>::Visit(DynamicObjectMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) + return; + // already found if (i_object) return; @@ -148,9 +163,93 @@ void Trinity::WorldObjectSearcher<Check>::Visit(DynamicObjectMapType &m) } } + +template<class Check> +void Trinity::WorldObjectLastSearcher<Check>::Visit(GameObjectMapType &m) +{ + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) + return; + + for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + +template<class Check> +void Trinity::WorldObjectLastSearcher<Check>::Visit(PlayerMapType &m) +{ + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) + return; + + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + +template<class Check> +void Trinity::WorldObjectLastSearcher<Check>::Visit(CreatureMapType &m) +{ + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) + return; + + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + +template<class Check> +void Trinity::WorldObjectLastSearcher<Check>::Visit(CorpseMapType &m) +{ + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) + return; + + for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + +template<class Check> +void Trinity::WorldObjectLastSearcher<Check>::Visit(DynamicObjectMapType &m) +{ + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) + return; + + for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + template<class Check> void Trinity::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) + return; + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) if (i_check(itr->getSource())) @@ -160,6 +259,9 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m) template<class Check> void Trinity::WorldObjectListSearcher<Check>::Visit(CreatureMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) + return; + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) if (i_check(itr->getSource())) @@ -169,6 +271,9 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(CreatureMapType &m) template<class Check> void Trinity::WorldObjectListSearcher<Check>::Visit(CorpseMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) + return; + for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) if (i_check(itr->getSource())) @@ -178,6 +283,9 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(CorpseMapType &m) template<class Check> void Trinity::WorldObjectListSearcher<Check>::Visit(GameObjectMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) + return; + for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) if (i_check(itr->getSource())) @@ -187,6 +295,9 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(GameObjectMapType &m) template<class Check> void Trinity::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType &m) { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) + return; + for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) if (itr->getSource()->InSamePhase(i_phaseMask)) if (i_check(itr->getSource())) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 53356772ff6..207ab2b663d 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -592,19 +592,6 @@ Spell::~Spell() CheckEffectExecuteData(); } -template<typename T> -WorldObject* Spell::FindCorpseUsing() -{ - // non-standard target selection - float max_range = m_spellInfo->GetMaxRange(false); - - WorldObject* result = NULL; - T u_check(m_caster, max_range); - Trinity::WorldObjectSearcher<T> searcher(m_caster, result, u_check); - m_caster->GetMap()->VisitFirstFound(m_caster->GetPositionX(), m_caster->GetPositionY(), max_range, searcher); - return result; -} - void Spell::InitExplicitTargets(SpellCastTargets const& targets) { m_targets = targets; @@ -707,7 +694,8 @@ void Spell::SelectSpellTargets() { // select targets for cast phase SelectExplicitTargets(); - uint32 processedTargets = 0; + + uint32 processedAreaEffectsMask = 0; for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) { // not call for empty effect. @@ -715,9 +703,6 @@ void Spell::SelectSpellTargets() if (!m_spellInfo->Effects[i].IsEffect()) continue; - if (processedTargets & (1 << i)) - continue; - // set expected type of implicit targets to be sent to client uint32 implicitTargetMask = GetTargetFlagMask(m_spellInfo->Effects[i].TargetA.GetObjectType()) | GetTargetFlagMask(m_spellInfo->Effects[i].TargetB.GetObjectType()); if (implicitTargetMask & TARGET_FLAG_UNIT) @@ -725,13 +710,8 @@ void Spell::SelectSpellTargets() if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM)) m_targets.SetTargetFlag(TARGET_FLAG_GAMEOBJECT); - uint32 targetA = m_spellInfo->Effects[i].TargetA.GetTarget(); - uint32 targetB = m_spellInfo->Effects[i].TargetB.GetTarget(); - - if (targetA) - processedTargets |= SelectEffectTargets(i, m_spellInfo->Effects[i].TargetA); - if (targetB) - processedTargets |= SelectEffectTargets(i, m_spellInfo->Effects[i].TargetB); + SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetA, processedAreaEffectsMask); + SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetB, processedAreaEffectsMask); // Select targets of effect based on effect type // those are used when no valid target could be added for spell effect based on spell target type @@ -793,6 +773,920 @@ void Spell::SelectSpellTargets() } } +void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32& processedEffectMask) +{ + if (!targetType.GetTarget()) + return; + + uint32 effectMask = 1 << effIndex; + // set the same target list for all effects + // some spells appear to need this, however this requires more research + switch (targetType.GetSelectionCategory()) + { + case TARGET_SELECT_CATEGORY_NEARBY: + case TARGET_SELECT_CATEGORY_CONE: + case TARGET_SELECT_CATEGORY_AREA: + // targets for effect already selected + if (effectMask & processedEffectMask) + return; + // choose which targets we can select at once + for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j) + if (GetSpellInfo()->Effects[effIndex].TargetA.GetTarget() == GetSpellInfo()->Effects[j].TargetA.GetTarget() && + GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == GetSpellInfo()->Effects[j].TargetB.GetTarget() && + GetSpellInfo()->Effects[effIndex].ImplicitTargetConditions == GetSpellInfo()->Effects[j].ImplicitTargetConditions && + GetSpellInfo()->Effects[effIndex].CalcRadius(m_caster) == GetSpellInfo()->Effects[j].CalcRadius(m_caster)) + effectMask |= 1 << j; + processedEffectMask |= effectMask; + } + + switch(targetType.GetSelectionCategory()) + { + case TARGET_SELECT_CATEGORY_CHANNEL: + SelectImplicitChannelTargets(effIndex, targetType); + break; + case TARGET_SELECT_CATEGORY_NEARBY: + SelectImplicitNearbyTargets(effIndex, targetType, effectMask); + break; + case TARGET_SELECT_CATEGORY_CONE: + SelectImplicitConeTargets(effIndex, targetType, effectMask); + break; + case TARGET_SELECT_CATEGORY_AREA: + SelectImplicitAreaTargets(effIndex, targetType, effectMask); + break; + case TARGET_SELECT_CATEGORY_DEFAULT: + switch (targetType.GetObjectType()) + { + case TARGET_OBJECT_TYPE_SRC: + switch(targetType.GetReferenceType()) + { + case TARGET_REFERENCE_TYPE_CASTER: + m_targets.SetSrc(*m_caster); + break; + default: + ASSERT("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC"); + break; + } + break; + case TARGET_OBJECT_TYPE_DEST: + switch(targetType.GetReferenceType()) + { + case TARGET_REFERENCE_TYPE_CASTER: + SelectImplicitCasterDestTargets(effIndex, targetType); + break; + case TARGET_REFERENCE_TYPE_TARGET: + SelectImplicitCasterDestTargets(effIndex, targetType); + break; + case TARGET_REFERENCE_TYPE_DEST: + SelectImplicitDestDestTargets(effIndex, targetType); + break; + default: + ASSERT("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST"); + break; + } + break; + default: + switch(targetType.GetReferenceType()) + { + case TARGET_REFERENCE_TYPE_CASTER: + SelectImplicitCasterObjectTargets(effIndex, targetType); + break; + case TARGET_REFERENCE_TYPE_TARGET: + SelectImplicitTargetObjectTargets(effIndex, targetType); + break; + default: + ASSERT("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT"); + break; + } + break; + } + break; + case TARGET_SELECT_CATEGORY_NYI: + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: target type %u, found in spellID %u, effect %u is not implemented yet!", m_spellInfo->Id, effIndex, targetType.GetTarget()); + break; + default: + ASSERT(false && "Spell::SelectEffectImplicitTargets: received not implemented select target category"); + break; + } +} + +void Spell::SelectImplicitChannelTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) +{ + if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER) + { + ASSERT(false && "Spell::SelectImplicitChannelTargets: received not implemented target reference type"); + return; + } + + Spell* channeledSpell = m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + if (!channeledSpell) + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID %u, effect %u", m_spellInfo->Id, effIndex); + return; + } + switch (targetType.GetType()) + { + case TARGET_UNIT_CHANNEL_TARGET: + // unit target may be no longer avalible - teleported out of map for example + if (Unit* target = Unit::GetUnit(*m_caster, channeledSpell->m_targets.GetUnitTargetGUID())) + AddUnitTarget(target, 1 << effIndex); + else + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell target for spell ID %u, effect %u", m_spellInfo->Id, effIndex); + break; + case TARGET_DEST_CHANNEL_TARGET: + if (channeledSpell->m_targets.HasDst()) + m_targets.SetDst(channeledSpell->m_targets); + else if (WorldObject* target = ObjectAccessor::GetWorldObject(*m_caster, channeledSpell->m_targets.GetObjectTargetGUID())) + m_targets.SetDst(*target); + else + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell destination for spell ID %u, effect %u", m_spellInfo->Id, effIndex); + break; + case TARGET_DEST_CHANNEL_CASTER: + m_targets.SetDst(*channeledSpell->GetCaster()); + break; + default: + ASSERT(false && "Spell::SelectImplicitChannelTargets: received not implemented target type"); + break; + } +} + +void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask) +{ + if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER) + { + ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented target reference type"); + return; + } + + float range; + switch (targetType.GetCheckType()) + { + case TARGET_CHECK_ENEMY: + range = m_spellInfo->GetMaxRange(false, m_caster, this); + break; + case TARGET_CHECK_ALLY: + case TARGET_CHECK_PARTY: + case TARGET_CHECK_RAID: + case TARGET_CHECK_RAID_CLASS: + range = m_spellInfo->GetMaxRange(true, m_caster, this); + break; + case TARGET_CHECK_ENTRY: + case TARGET_CHECK_DEFAULT: + range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive(), m_caster, this); + break; + default: + ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented selection check type"); + break; + } + + ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; + + // handle emergency case - try to use other provided targets if no conditions provided + if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && !condList || condList->empty()) + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::SelectImplicitNearbyTargets: no conditions entry for target with TARGET_CHECK_ENTRY of spell ID %u, effect %u - selecting default targets", m_spellInfo->Id, effIndex); + switch (targetType.GetObjectType()) + { + case TARGET_OBJECT_TYPE_GOBJ: + if (m_spellInfo->RequiresSpellFocus) + { + if (focusObject) + AddGOTarget(focusObject, effMask); + return; + } + break; + case TARGET_OBJECT_TYPE_DEST: + if (m_spellInfo->RequiresSpellFocus) + { + if (focusObject) + m_targets.SetDst(*focusObject); + return; + } + break; + default: + break; + } + } + + WorldObject* target = SearchNearbyTarget(range, targetType.GetObjectType(), targetType.GetCheckType(), condList); + if (!target) + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID %u, effect %u", m_spellInfo->Id, effIndex); + return; + } + + switch (targetType.GetObjectType()) + { + case TARGET_OBJECT_TYPE_UNIT: + if (Unit* unitTarget = target->ToUnit()) + AddUnitTarget(unitTarget, effMask, false); + break; + case TARGET_OBJECT_TYPE_GOBJ: + if (GameObject* gobjTarget = target->ToGameObject()) + AddGOTarget(gobjTarget, effMask); + break; + case TARGET_OBJECT_TYPE_DEST: + m_targets.SetDst(*target); + break; + default: + ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented target object type"); + break; + } + + SelectImplicitChainTargets(effIndex, targetType, target, effMask); +} + +void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask) +{ + if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER) + { + ASSERT(false && "Spell::SelectImplicitConeTargets: received not implemented target reference type"); + return; + } + std::list<WorldObject*> targets; + SpellTargetObjectTypes objectType = targetType.GetObjectType(); + SpellTargetCheckTypes selectionType = targetType.GetCheckType(); + ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; + float coneAngle = M_PI/2; + float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod; + + if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList)) + { + Trinity::WorldObjectSpellConeTargetCheck check(coneAngle, radius, m_caster, m_spellInfo, selectionType, condList); + Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> searcher(m_caster, targets, check, containerTypeMask); + SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> > (searcher, containerTypeMask, m_caster, m_caster, radius); + + if (!targets.empty()) + { + // Other special target selection goes here + if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) + { + Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); + for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j) + if ((*j)->IsAffectedOnSpell(m_spellInfo)) + maxTargets += (*j)->GetAmount(); + + Trinity::RandomResizeList(targets, maxTargets); + } + + // for compability with older code - add only unit and go targets + // TODO: remove this + std::list<Unit*> unitTargets; + std::list<GameObject*> gObjTargets; + + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + { + if (Unit* unitTarget = (*itr)->ToUnit()) + unitTargets.push_back(unitTarget); + else if (GameObject* gObjTarget = (*itr)->ToGameObject()) + gObjTargets.push_back(gObjTarget); + } + + CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex); + + for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr) + AddUnitTarget(*itr, effMask, false); + + for (std::list<GameObject*>::iterator itr = gObjTargets.begin(); itr != gObjTargets.end(); ++itr) + AddGOTarget(*itr, effMask); + } + } +} + +void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask) +{ + Unit* referer = NULL; + switch (targetType.GetReferenceType()) + { + case TARGET_REFERENCE_TYPE_SRC: + case TARGET_REFERENCE_TYPE_DEST: + case TARGET_REFERENCE_TYPE_CASTER: + referer = m_caster; + break; + case TARGET_REFERENCE_TYPE_TARGET: + referer = m_targets.GetUnitTarget(); + break; + case TARGET_REFERENCE_TYPE_LAST: + { + // find last added target for this effect + for (std::list<TargetInfo>::reverse_iterator ihit = m_UniqueTargetInfo.rbegin(); ihit != m_UniqueTargetInfo.rend(); ++ihit) + { + if (ihit->effectMask & (1<<effIndex)) + { + referer = ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); + break; + } + } + break; + } + default: + ASSERT(false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type"); + return; + } + if (!referer) + return; + + Position const* center = NULL; + switch (targetType.GetReferenceType()) + { + case TARGET_REFERENCE_TYPE_SRC: + center = m_targets.GetSrc(); + break; + case TARGET_REFERENCE_TYPE_DEST: + center = m_targets.GetDst(); + break; + case TARGET_REFERENCE_TYPE_CASTER: + case TARGET_REFERENCE_TYPE_TARGET: + case TARGET_REFERENCE_TYPE_LAST: + center = referer; + break; + default: + ASSERT(false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type"); + return; + } + std::list<WorldObject*> targets; + float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod; + SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions); + + // Custom entries + // TODO: remove those + switch (m_spellInfo->Id) + { + case 46584: // Raise Dead + { + if (Player* playerCaster = m_caster->ToPlayer()) + { + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + { + switch ((*itr)->GetTypeId()) + { + case TYPEID_UNIT: + case TYPEID_PLAYER: + { + Unit* unitTarget = (*itr)->ToUnit(); + if (unitTarget->isAlive() || !playerCaster->isHonorOrXPTarget(unitTarget) + || ((unitTarget->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0) + || (unitTarget->GetDisplayId() != unitTarget->GetNativeDisplayId())) + break; + AddUnitTarget(unitTarget, effMask, false); + // no break; + } + case TYPEID_CORPSE: // wont work until corpses are allowed in target lists, but at least will send dest in packet + m_targets.SetDst(*(*itr)); + return; // nothing more to do here + default: + break; + } + } + } + return; // don't add targets to target map + } + // Corpse Explosion + case 49158: + case 51325: + case 51326: + case 51327: + case 51328: + // check if our target is not valid (spell can target ghoul or dead unit) + if (!(m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->GetDisplayId() == m_targets.GetUnitTarget()->GetNativeDisplayId() && + ((m_targets.GetUnitTarget()->GetEntry() == 26125 && m_targets.GetUnitTarget()->GetOwnerGUID() == m_caster->GetGUID()) + || m_targets.GetUnitTarget()->isDead()))) + { + // remove existing targets + CleanupTargetList(); + + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + { + switch ((*itr)->GetTypeId()) + { + case TYPEID_UNIT: + case TYPEID_PLAYER: + if (!(*itr)->ToUnit()->isDead()) + break; + AddUnitTarget((*itr)->ToUnit(), 1 << effIndex, false); + return; + default: + break; + } + } + if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true); + SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW); + finish(false); + } + return; + default: + break; + } + std::list<Unit*> unitTargets; + std::list<GameObject*> gObjTargets; + // for compability with older code - add only unit and go targets + // TODO: remove this + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + { + if (Unit* unitTarget = (*itr)->ToUnit()) + unitTargets.push_back(unitTarget); + else if (GameObject* gObjTarget = (*itr)->ToGameObject()) + gObjTargets.push_back(gObjTarget); + } + + if (!unitTargets.empty()) + { + // Special target selection for smart heals and energizes + uint32 maxSize = 0; + int32 power = -1; + switch (m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + switch (m_spellInfo->Id) + { + case 52759: // Ancestral Awakening + case 71610: // Echoes of Light (Althor's Abacus normal version) + case 71641: // Echoes of Light (Althor's Abacus heroic version) + maxSize = 1; + power = POWER_HEALTH; + break; + case 54968: // Glyph of Holy Light + maxSize = m_spellInfo->MaxAffectedTargets; + power = POWER_HEALTH; + break; + case 57669: // Replenishment + // In arenas Replenishment may only affect the caster + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->InArena()) + { + unitTargets.clear(); + unitTargets.push_back(m_caster); + break; + } + maxSize = 10; + power = POWER_MANA; + break; + default: + break; + } + break; + case SPELLFAMILY_PRIEST: + if (m_spellInfo->SpellFamilyFlags[0] == 0x10000000) // Circle of Healing + { + maxSize = m_caster->HasAura(55675) ? 6 : 5; // Glyph of Circle of Healing + power = POWER_HEALTH; + } + else if (m_spellInfo->Id == 64844) // Divine Hymn + { + maxSize = 3; + power = POWER_HEALTH; + } + else if (m_spellInfo->Id == 64904) // Hymn of Hope + { + maxSize = 3; + power = POWER_MANA; + } + else + break; + + // Remove targets outside caster's raid + for (std::list<Unit*>::iterator itr = unitTargets.begin() ; itr != unitTargets.end();) + { + if (!(*itr)->IsInRaidWith(m_caster)) + itr = unitTargets.erase(itr); + else + ++itr; + } + break; + case SPELLFAMILY_DRUID: + if (m_spellInfo->SpellFamilyFlags[1] == 0x04000000) // Wild Growth + { + maxSize = m_caster->HasAura(62970) ? 6 : 5; // Glyph of Wild Growth + power = POWER_HEALTH; + } + else if (m_spellInfo->SpellFamilyFlags[2] == 0x0100) // Starfall + { + // Remove targets not in LoS or in stealth + for (std::list<Unit*>::iterator itr = unitTargets.begin() ; itr != unitTargets.end();) + { + if ((*itr)->HasStealthAura() || (*itr)->HasInvisibilityAura() || !(*itr)->IsWithinLOSInMap(m_caster)) + itr = unitTargets.erase(itr); + else + ++itr; + } + break; + } + else + break; + + // Remove targets outside caster's raid + for (std::list<Unit*>::iterator itr = unitTargets.begin() ; itr != unitTargets.end();) + if (!(*itr)->IsInRaidWith(m_caster)) + itr = unitTargets.erase(itr); + else + ++itr; + break; + default: + break; + } + + if (maxSize && power != -1) + { + if (Powers(power) == POWER_HEALTH) + { + if (unitTargets.size() > maxSize) + { + unitTargets.sort(Trinity::HealthPctOrderPred()); + unitTargets.resize(maxSize); + } + } + else + { + for (std::list<Unit*>::iterator itr = unitTargets.begin() ; itr != unitTargets.end();) + if ((*itr)->getPowerType() != (Powers)power) + itr = unitTargets.erase(itr); + else + ++itr; + + if (unitTargets.size() > maxSize) + { + unitTargets.sort(Trinity::PowerPctOrderPred((Powers)power)); + unitTargets.resize(maxSize); + } + } + } + + // Other special target selection goes here + if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) + { + Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); + for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j) + if ((*j)->IsAffectedOnSpell(m_spellInfo)) + maxTargets += (*j)->GetAmount(); + + if (m_spellInfo->Id == 5246) //Intimidating Shout + unitTargets.remove(m_targets.GetUnitTarget()); + Trinity::RandomResizeList(unitTargets, maxTargets); + } + + CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex); + + for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr) + AddUnitTarget(*itr, effMask, false); + } + + if (!gObjTargets.empty()) + { + if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) + { + Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); + for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j) + if ((*j)->IsAffectedOnSpell(m_spellInfo)) + maxTargets += (*j)->GetAmount(); + + Trinity::RandomResizeList(gObjTargets, maxTargets); + } + for (std::list<GameObject*>::iterator itr = gObjTargets.begin(); itr != gObjTargets.end(); ++itr) + AddGOTarget(*itr, effMask); + } +} + +void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) +{ + switch(targetType.GetType()) + { + case TARGET_DEST_CASTER: + m_targets.SetDst(*m_caster); + return; + case TARGET_DEST_HOME: + if (Player* playerCaster = m_caster->ToPlayer()) + m_targets.SetDst(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->GetOrientation(), playerCaster->m_homebindMapId); + return; + case TARGET_DEST_DB: + if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id)) + { + // TODO: fix this check + if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS)) + m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId); + else if (st->target_mapId == m_caster->GetMapId()) + m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation); + } + else + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id); + WorldObject* target = m_targets.GetObjectTarget(); + m_targets.SetDst(target ? *target : *m_caster); + } + return; + case TARGET_DEST_CASTER_FISHING: + { + float min_dis = m_spellInfo->GetMinRange(true); + float max_dis = m_spellInfo->GetMaxRange(true); + float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis; + float x, y, z, angle; + angle = (float)rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f); + m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle); + m_targets.SetDst(x, y, z, m_caster->GetOrientation()); + return; + } + } + + float dist; + float angle = targetType.CalcDirectionAngle(); + float objSize = m_caster->GetObjectSize(); + if (targetType.GetType() == TARGET_DEST_CASTER_SUMMON) + dist = PET_FOLLOW_DIST; + else + dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); + + if (dist < objSize) + dist = objSize; + else if (targetType.GetType() == TARGET_DEST_CASTER_RANDOM) + dist = objSize + (dist - objSize) * (float)rand_norm(); + + Position pos; + if (targetType.GetType() == TARGET_DEST_CASTER_FRONT_LEAP) + m_caster->GetFirstCollisionPosition(pos, dist, angle); + else + m_caster->GetNearPosition(pos, dist, angle); + m_targets.SetDst(*m_caster); + m_targets.ModDst(pos); +} + +void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) +{ + WorldObject* target = m_targets.GetObjectTarget(); + switch(targetType.GetTarget()) + { + case TARGET_DEST_TARGET_ENEMY: + case TARGET_DEST_TARGET_ANY: + m_targets.SetDst(*target); + return; + } + + float angle = targetType.CalcDirectionAngle(); + float objSize = target->GetObjectSize(); + float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); + if (dist < objSize) + dist = objSize; + else if (targetType.GetType() == TARGET_DEST_TARGET_RANDOM) + dist = objSize + (dist - objSize) * (float)rand_norm(); + + Position pos; + target->GetNearPosition(pos, dist, angle); + m_targets.SetDst(*target); + m_targets.ModDst(pos); +} + +void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) +{ + switch(targetType.GetTarget()) + { + case TARGET_DEST_DYNOBJ_ENEMY: + case TARGET_DEST_DYNOBJ_ALLY: + case TARGET_DEST_DYNOBJ_NONE: + case TARGET_DEST_DEST: + return; + case TARGET_DEST_TRAJ: + SelectImplicitTrajTargets(); + return; + } + + float angle = targetType.CalcDirectionAngle(); + float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); + if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM) + dist *= (float)rand_norm(); + + Position pos = *m_targets.GetDst(); + m_caster->MovePosition(pos, dist, angle); + m_targets.ModDst(pos); +} + +void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) +{ + switch(targetType.GetTarget()) + { + case TARGET_UNIT_CASTER: + AddUnitTarget(m_caster, 1 << effIndex, false); + break; + case TARGET_UNIT_MASTER: + if (Unit* owner = m_caster->GetCharmerOrOwner()) + AddUnitTarget(owner, 1 << effIndex); + break; + case TARGET_UNIT_PET: + if (Guardian* pet = m_caster->GetGuardianPet()) + AddUnitTarget(pet, 1 << effIndex); + break; + case TARGET_UNIT_SUMMONER: + if (m_caster->isSummon()) + if (Unit* unit = m_caster->ToTempSummon()->GetSummoner()) + AddUnitTarget(unit, 1 << effIndex); + break; + case TARGET_UNIT_VEHICLE: + if (Unit *vehicle = m_caster->GetVehicleBase()) + AddUnitTarget(vehicle, 1 << effIndex); + break; + case TARGET_UNIT_PASSENGER_0: + case TARGET_UNIT_PASSENGER_1: + case TARGET_UNIT_PASSENGER_2: + case TARGET_UNIT_PASSENGER_3: + case TARGET_UNIT_PASSENGER_4: + case TARGET_UNIT_PASSENGER_5: + case TARGET_UNIT_PASSENGER_6: + case TARGET_UNIT_PASSENGER_7: + if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsVehicle()) + if (Unit *unit = m_caster->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0)) + AddUnitTarget(unit, 1 << effIndex); + break; + } +} + +void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) +{ + ASSERT(m_targets.GetObjectTarget() && "Spell::SelectImplicitTargetObjectTargets - no explicit object target available!"); + if (Unit* unit = m_targets.GetUnitTarget()) + AddUnitTarget(unit, 1 << effIndex); + else if (GameObject* gobj = m_targets.GetGOTarget()) + AddGOTarget(gobj, 1 << effIndex); + else + AddItemTarget(m_targets.GetItemTarget(), effIndex); + + if (WorldObject* target = m_targets.GetObjectTarget()) + SelectImplicitChainTargets(effIndex, targetType, target, 1 << effIndex); +} + +void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask) +{ + uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget; + if (Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this); + + if (maxTargets > 1) + { + // mark damage multipliers as used + for (uint32 k = effIndex; k < MAX_SPELL_EFFECTS; ++k) + if (effMask & (1 << k)) + m_damageMultipliers[k] = 1.0f; + m_applyMultiplierMask |= effMask; + + std::list<WorldObject*> targets; + SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType() + , m_spellInfo->Effects[effIndex].ImplicitTargetConditions, targetType.GetType() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY); + + // for backward compability + std::list<Unit*> unitTargets; + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if (Unit* unitTarget = (*itr)->ToUnit()) + unitTargets.push_back(unitTarget); + + CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex); + + for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr) + AddUnitTarget(*itr, effMask, false); + } +} + +float tangent(float x) +{ + x = tan(x); + //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x; + //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max(); + //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max(); + if (x < 100000.0f && x > -100000.0f) return x; + if (x >= 100000.0f) return 100000.0f; + if (x <= 100000.0f) return -100000.0f; + return 0.0f; +} + +#define DEBUG_TRAJ(a) //a + +void Spell::SelectImplicitTrajTargets() +{ + if (!m_targets.HasTraj()) + return; + + float dist2d = m_targets.GetDist2d(); + if (!dist2d) + return; + + float srcToDestDelta = m_targets.GetDst()->m_positionZ - m_targets.GetSrc()->m_positionZ; + + std::list<WorldObject*> targets; + Trinity::WorldObjectSpellTrajTargetCheck check(dist2d, m_targets.GetSrc(), m_caster, m_spellInfo); + Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> searcher(m_caster, targets, check, GRID_MAP_TYPE_MASK_ALL); + SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, m_targets.GetSrc(), dist2d); + if (targets.empty()) + return; + + targets.sort(Trinity::ObjectDistanceOrderPred(m_caster)); + + float b = tangent(m_targets.GetElevation()); + float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d); + if (a > -0.0001f) + a = 0; + DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: a %f b %f", a, b);) + + float bestDist = m_spellInfo->GetMaxRange(false); + + std::list<WorldObject*>::const_iterator itr = targets.begin(); + for (; itr != targets.end(); ++itr) + { + if (Unit* unitTarget = (*itr)->ToUnit()) + if (m_caster == *itr || m_caster->IsOnVehicle(unitTarget) || (unitTarget)->GetVehicle())//(*itr)->IsOnVehicle(m_caster)) + continue; + + const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3) + // TODO: all calculation should be based on src instead of m_caster + const float objDist2d = m_targets.GetSrc()->GetExactDist2d(*itr) * cos(m_targets.GetSrc()->GetRelativeAngle(*itr)); + const float dz = (*itr)->GetPositionZ() - m_targets.GetSrc()->m_positionZ; + + DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: check %u, dist between %f %f, height between %f %f.", (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size);) + + float dist = objDist2d - size; + float height = dist * (a * dist + b); + DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);) + if (dist < bestDist && height < dz + size && height > dz - size) + { + bestDist = dist > 0 ? dist : 0; + break; + } + +#define CHECK_DIST {\ + DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\ + if (dist > bestDist)\ + continue;\ + if (dist < objDist2d + size && dist > objDist2d - size)\ + {\ + bestDist = dist;\ + break;\ + }\ + } + + if (!a) + { + height = dz - size; + dist = height / b; + CHECK_DIST; + + height = dz + size; + dist = height / b; + CHECK_DIST; + + continue; + } + + height = dz - size; + float sqrt1 = b * b + 4 * a * height; + if (sqrt1 > 0) + { + sqrt1 = sqrt(sqrt1); + dist = (sqrt1 - b) / (2 * a); + CHECK_DIST; + } + + height = dz + size; + float sqrt2 = b * b + 4 * a * height; + if (sqrt2 > 0) + { + sqrt2 = sqrt(sqrt2); + dist = (sqrt2 - b) / (2 * a); + CHECK_DIST; + + dist = (-sqrt2 - b) / (2 * a); + CHECK_DIST; + } + + if (sqrt1 > 0) + { + dist = (-sqrt1 - b) / (2 * a); + CHECK_DIST; + } + } + + if (m_targets.GetSrc()->GetExactDist2d(m_targets.GetDst()) > bestDist) + { + float x = m_targets.GetSrc()->m_positionX + cos(m_caster->GetOrientation()) * bestDist; + float y = m_targets.GetSrc()->m_positionY + sin(m_caster->GetOrientation()) * bestDist; + float z = m_targets.GetSrc()->m_positionZ + bestDist * (a * bestDist + b); + + if (itr != targets.end()) + { + float distSq = (*itr)->GetExactDistSq(x, y, z); + float sizeSq = (*itr)->GetObjectSize(); + sizeSq *= sizeSq; + DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);) + if (distSq > sizeSq) + { + float factor = 1 - sqrt(sizeSq / distSq); + x += factor * ((*itr)->GetPositionX() - x); + y += factor * ((*itr)->GetPositionY() - y); + z += factor * ((*itr)->GetPositionZ() - z); + + distSq = (*itr)->GetExactDistSq(x, y, z); + DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);) + } + } + + Position trajDst; + trajDst.Relocate(x, y, z, m_caster->GetOrientation()); + m_targets.ModDst(trajDst); + } +} + void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) { // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER @@ -865,6 +1759,190 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) } } +uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList) +{ + // this function selects which containers need to be searched for spell target + uint32 retMask = GRID_MAP_TYPE_MASK_ALL; + + // filter searchers based on searched object type + switch (objType) + { + case TARGET_OBJECT_TYPE_UNIT: + case TARGET_OBJECT_TYPE_UNIT_AND_DEST: + case TARGET_OBJECT_TYPE_CORPSE: + case TARGET_OBJECT_TYPE_CORPSE_ENEMY: + case TARGET_OBJECT_TYPE_CORPSE_ALLY: + retMask &= GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_CREATURE; + break; + case TARGET_OBJECT_TYPE_GOBJ: + case TARGET_OBJECT_TYPE_GOBJ_ITEM: + retMask &= GRID_MAP_TYPE_MASK_GAMEOBJECT; + break; + } + if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD)) + retMask &= ~GRID_MAP_TYPE_MASK_CORPSE; + if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS) + retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER; + if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) + retMask &= GRID_MAP_TYPE_MASK_PLAYER; + + if (condList) + retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList); + return retMask; +} + +template<class SEARCHER> +void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius) +{ + if (!containerMask) + return; + + // search world and grid for possible targets + bool searchInGrid = containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT); + bool searchInWorld = containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE); + if (searchInGrid || searchInWorld) + { + float x,y; + x = pos->GetPositionX(); + y = pos->GetPositionY(); + + CellCoord p(Trinity::ComputeCellCoord(x, y)); + Cell cell(p); + cell.SetNoCreate(); + + Map& map = *(referer->GetMap()); + + if (searchInWorld) + { + TypeContainerVisitor<SEARCHER, WorldTypeMapContainer> world_object_notifier(searcher); + cell.Visit(p, world_object_notifier, map, radius, x, y); + } + if (searchInGrid) + { + TypeContainerVisitor<SEARCHER, GridTypeMapContainer > grid_object_notifier(searcher); + cell.Visit(p, grid_object_notifier, map, radius, x , y); + } + } +} + +WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList) +{ + WorldObject* target = NULL; + uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList); + if (!containerTypeMask) + return NULL; + Trinity::WorldObjectSpellNearbyTargetCheck check(range, m_caster, m_spellInfo, selectionType, condList); + Trinity::WorldObjectLastSearcher<Trinity::WorldObjectSpellNearbyTargetCheck> searcher(m_caster, target, check, containerTypeMask); + SearchTargets<Trinity::WorldObjectLastSearcher<Trinity::WorldObjectSpellNearbyTargetCheck> > (searcher, containerTypeMask, m_caster, m_caster, range); + return target; +} + +void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList) +{ + uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList); + if (!containerTypeMask) + return; + Trinity::WorldObjectSpellAreaTargetCheck check(range, position, m_caster, referer, m_spellInfo, selectionType, condList); + Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> searcher(m_caster, targets, check, containerTypeMask); + SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> > (searcher, containerTypeMask, m_caster, m_caster, range); +} + +void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionList* condList, bool isChainHeal) +{ + // max dist for jump target selection + float jumpRadius = 0.0f; + switch (m_spellInfo->DmgClass) + { + case SPELL_DAMAGE_CLASS_RANGED: + // 7.5y for multi shot + jumpRadius = 7.5f; + break; + case SPELL_DAMAGE_CLASS_MELEE: + // 5y for swipe, cleave and similar + jumpRadius = 5.0f; + break; + case SPELL_DAMAGE_CLASS_NONE: + case SPELL_DAMAGE_CLASS_MAGIC: + // 12.5y for chain heal spell since 3.2 patch + if (isChainHeal) + jumpRadius = 12.5f; + // 10y as default for magic chain spells + else + jumpRadius = 10.0f; + break; + } + + // chain lightning/heal spells and similar - allow to jump at larger distance and go out of los + bool isBouncingFar = (m_spellInfo->AttributesEx4 & SPELL_ATTR4_AREA_TARGET_CHAIN + || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE + || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC); + + // max dist which spell can reach + float searchRadius = jumpRadius; + if (isBouncingFar) + searchRadius *= chainTargets; + + std::list<WorldObject*> tempTargets; + SearchAreaTargets(tempTargets, searchRadius, target, m_caster, objectType, selectType, condList); + tempTargets.remove(target); + + // remove targets which are always invalid for chain spells + // for some spells allow only chain targets in front of caster (swipe for example) + if (!isBouncingFar) + { + for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end();) + { + std::list<WorldObject*>::iterator checkItr = itr++; + if (!m_caster->HasInArc(static_cast<float>(M_PI), *checkItr)) + tempTargets.erase(checkItr); + } + } + + while (chainTargets) + { + // try to get unit for next chain jump + std::list<WorldObject*>::iterator foundItr = tempTargets.end(); + // get unit with highest hp deficit in dist + if (isChainHeal) + { + uint32 maxHPDeficit = 0; + for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr) + { + if (Unit* unitTarget = (*itr)->ToUnit()) + { + uint32 deficit = unitTarget->GetMaxHealth() - unitTarget->GetHealth(); + if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && target->IsWithinDist(unitTarget, jumpRadius) && target->IsWithinLOSInMap(unitTarget)) + { + foundItr = itr; + maxHPDeficit = deficit; + } + } + } + } + // get closest object + else + { + for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr) + { + if (foundItr == tempTargets.end()) + { + if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr)) + foundItr = itr; + } + else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr)) + foundItr = itr; + } + } + // not found any valid target - chain ends + if (foundItr == tempTargets.end()) + break; + target = *foundItr; + tempTargets.erase(foundItr); + targets.push_back(target); + --chainTargets; + } +} + void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/) { //========================================================================================== @@ -1791,1077 +2869,6 @@ struct ChainHealingOrder : public std::binary_function<const Unit*, const Unit*, } }; -void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uint32 num, SpellTargets TargetType) -{ - Unit* cur = m_targets.GetUnitTarget(); - if (!cur) - return; - - //FIXME: This very like horrible hack and wrong for most spells - if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE) - max_range += num * CHAIN_SPELL_JUMP_RADIUS; - - std::list<Unit*> tempUnitMap; - if (TargetType == SPELL_TARGETS_CHAINHEAL) - { - SearchAreaTarget(tempUnitMap, max_range, PUSH_CHAIN, SPELL_TARGETS_ALLY); - tempUnitMap.sort(ChainHealingOrder(m_caster)); - } - else - SearchAreaTarget(tempUnitMap, max_range, PUSH_CHAIN, TargetType); - tempUnitMap.remove(cur); - - while (num) - { - TagUnitMap.push_back(cur); - --num; - - if (tempUnitMap.empty()) - break; - - std::list<Unit*>::iterator next; - - if (TargetType == SPELL_TARGETS_CHAINHEAL) - { - next = tempUnitMap.begin(); - while (cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS || !cur->IsWithinLOSInMap(*next)) - { - ++next; - if (next == tempUnitMap.end()) - return; - } - } - else - { - tempUnitMap.sort(Trinity::ObjectDistanceOrderPred(cur)); - next = tempUnitMap.begin(); - - if (cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) // Don't search beyond the max jump radius - break; - - // Check if (*next) is a valid chain target. If not, don't add to TagUnitMap, and repeat loop. - // If you want to add any conditions to exclude a target from TagUnitMap, add condition in this while () loop. - while ((m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE - && !m_caster->isInFrontInMap(*next, max_range)) - || !m_caster->canSeeOrDetect(*next) - || !cur->IsWithinLOSInMap(*next) - || (*next)->GetCreatureType() == CREATURE_TYPE_CRITTER - || ((GetSpellInfo()->AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED) && !(*next)->CanFreeMove())) - { - ++next; - if (next == tempUnitMap.end() || cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) // Don't search beyond the max jump radius - return; - } - } - - cur = *next; - tempUnitMap.erase(next); - } -} - -void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry) -{ - if (TargetType == SPELL_TARGETS_GO) - return; - - Position const* pos; - switch (type) - { - case PUSH_DST_CENTER: - CheckDst(); - pos = m_targets.GetDst(); - break; - case PUSH_SRC_CENTER: - CheckSrc(); - pos = m_targets.GetSrc(); - break; - case PUSH_CHAIN: - { - Unit* target = m_targets.GetUnitTarget(); - if (!target) - { - sLog->outError("SPELL: cannot find unit target for spell ID %u\n", m_spellInfo->Id); - return; - } - pos = target; - break; - } - default: - pos = m_caster; - break; - } - - Trinity::SpellNotifierCreatureAndPlayer notifier(m_caster, TagUnitMap, radius, type, TargetType, pos, entry, m_spellInfo); - if ((m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS) || (TargetType == SPELL_TARGETS_ENTRY && !entry)) - m_caster->GetMap()->VisitWorld(pos->m_positionX, pos->m_positionY, radius, notifier); - else - m_caster->GetMap()->VisitAll(pos->m_positionX, pos->m_positionY, radius, notifier); -} - -void Spell::SearchGOAreaTarget(std::list<GameObject*> &TagGOMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry) -{ - if (TargetType != SPELL_TARGETS_GO) - return; - - Position const* pos; - switch (type) - { - case PUSH_DST_CENTER: - CheckDst(); - pos = m_targets.GetDst(); - break; - case PUSH_SRC_CENTER: - CheckSrc(); - pos = m_targets.GetSrc(); - break; - default: - pos = m_caster; - break; - } - - Trinity::GameObjectInRangeCheck check(pos->m_positionX, pos->m_positionY, pos->m_positionZ, radius, entry); - Trinity::GameObjectListSearcher<Trinity::GameObjectInRangeCheck> searcher(m_caster, TagGOMap, check); - m_caster->GetMap()->VisitGrid(pos->m_positionX, pos->m_positionY, radius, searcher); -} - -WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType, SpellEffIndex effIndex) -{ - switch (TargetType) - { - case SPELL_TARGETS_ENTRY: - { - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id); - if (conditions.empty()) - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell (ID: %u) (caster Entry: %u) does not have record in `conditions` for spell script target (ConditionSourceType 13)", m_spellInfo->Id, m_caster->GetEntry()); - if (m_spellInfo->IsPositive()) - return SearchNearbyTarget(range, SPELL_TARGETS_ALLY, effIndex); - else - return SearchNearbyTarget(range, SPELL_TARGETS_ENEMY, effIndex); - } - - Creature* creatureScriptTarget = NULL; - GameObject* goScriptTarget = NULL; - - for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST) - { - if ((*i_spellST)->ConditionType != CONDITION_SPELL_SCRIPT_TARGET) - continue; - if ((*i_spellST)->ConditionValue3 && !((*i_spellST)->ConditionValue3 & (1 << uint32(effIndex)))) - continue; - switch ((*i_spellST)->ConditionValue1) - { - case SPELL_TARGET_TYPE_CONTROLLED: - for (Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr) - if ((*itr)->GetEntry() == (*i_spellST)->ConditionValue2 && (*itr)->IsWithinDistInMap(m_caster, range)) - { - goScriptTarget = NULL; - creatureScriptTarget = (*itr)->ToCreature(); - range = m_caster->GetDistance(creatureScriptTarget); - } - break; - case SPELL_TARGET_TYPE_GAMEOBJECT: - if ((*i_spellST)->ConditionValue2) - { - if (GameObject* go = m_caster->FindNearestGameObject((*i_spellST)->ConditionValue2, range)) - { - // remember found target and range, next attempt will find more near target with another entry - goScriptTarget = go; - creatureScriptTarget = NULL; - range = m_caster->GetDistance(goScriptTarget); - } - } - else if (focusObject) //Focus Object - { - float frange = m_caster->GetDistance(focusObject); - if (range >= frange) - { - creatureScriptTarget = NULL; - goScriptTarget = focusObject; - range = frange; - } - } - break; - case SPELL_TARGET_TYPE_CREATURE: - if (m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->GetEntry() == (*i_spellST)->ConditionValue2) - return m_targets.GetUnitTarget(); - case SPELL_TARGET_TYPE_DEAD: - default: - if (Creature* cre = m_caster->FindNearestCreature((*i_spellST)->ConditionValue2, range, (*i_spellST)->ConditionValue1 != SPELL_TARGET_TYPE_DEAD)) - { - creatureScriptTarget = cre; - goScriptTarget = NULL; - range = m_caster->GetDistance(creatureScriptTarget); - } - break; - } - } - - if (creatureScriptTarget) - return creatureScriptTarget; - else - return goScriptTarget; - } - default: - case SPELL_TARGETS_ENEMY: - { - Unit* target = NULL; - Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, range); - Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check); - m_caster->VisitNearbyObject(range, searcher); - return target; - } - case SPELL_TARGETS_ALLY: - { - Unit* target = NULL; - Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, range); - Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check); - m_caster->VisitNearbyObject(range, searcher); - return target; - } - } -} - -uint32 Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur) -{ - SpellNotifyPushType pushType = PUSH_NONE; - Player* modOwner = NULL; - if (m_originalCaster) - modOwner = m_originalCaster->GetSpellModOwner(); - - uint32 effectMask = 1 << i; - // ENTRY targets may have different selection lists, skip those for now until we can compare lists easily and quickly - if (GetSpellInfo()->Effects[i].TargetA.GetSelectionCheckType() != TARGET_SELECT_CHECK_ENTRY && - GetSpellInfo()->Effects[i].TargetB.GetSelectionCheckType() != TARGET_SELECT_CHECK_ENTRY) - for (uint32 j = i + 1; j < MAX_SPELL_EFFECTS; ++j) - if (GetSpellInfo()->Effects[i].TargetA.GetTarget() == GetSpellInfo()->Effects[j].TargetA.GetTarget() && - GetSpellInfo()->Effects[i].TargetB.GetTarget() == GetSpellInfo()->Effects[j].TargetB.GetTarget() && - GetSpellInfo()->Effects[i].CalcRadius(m_caster) == GetSpellInfo()->Effects[j].CalcRadius(m_caster)) - effectMask |= 1 << j; - - switch (cur.GetType()) - { - case TARGET_TYPE_UNIT_CASTER: - { - switch (cur.GetTarget()) - { - case TARGET_UNIT_CASTER: - AddUnitTarget(m_caster, effectMask, false); - break; - case TARGET_DEST_CASTER_FISHING: - { - float min_dis = m_spellInfo->GetMinRange(true); - float max_dis = m_spellInfo->GetMaxRange(true); - float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis; - float x, y, z, angle; - angle = (float)rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f); - m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle); - m_targets.SetDst(x, y, z, m_caster->GetOrientation()); - break; - } - case TARGET_UNIT_MASTER: - if (Unit* owner = m_caster->GetCharmerOrOwner()) - AddUnitTarget(owner, effectMask); - break; - case TARGET_UNIT_PET: - if (Guardian* pet = m_caster->GetGuardianPet()) - AddUnitTarget(pet, effectMask); - break; - case TARGET_UNIT_SUMMONER: - if (m_caster->isSummon()) - if (Unit* unit = m_caster->ToTempSummon()->GetSummoner()) - AddUnitTarget(unit, effectMask); - break; - case TARGET_UNIT_CASTER_AREA_PARTY: - case TARGET_UNIT_CASTER_AREA_RAID: - pushType = PUSH_CASTER_CENTER; - break; - case TARGET_UNIT_VEHICLE: - if (Unit* vehicle = m_caster->GetVehicleBase()) - AddUnitTarget(vehicle, effectMask); - break; - case TARGET_UNIT_PASSENGER_0: - case TARGET_UNIT_PASSENGER_1: - case TARGET_UNIT_PASSENGER_2: - case TARGET_UNIT_PASSENGER_3: - case TARGET_UNIT_PASSENGER_4: - case TARGET_UNIT_PASSENGER_5: - case TARGET_UNIT_PASSENGER_6: - case TARGET_UNIT_PASSENGER_7: - if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsVehicle()) - if (Unit* unit = m_caster->GetVehicleKit()->GetPassenger(cur.GetTarget() - TARGET_UNIT_PASSENGER_0)) - AddUnitTarget(unit, effectMask); - break; - default: - break; - } - break; - } - - case TARGET_TYPE_UNIT_TARGET: - { - Unit* target = m_targets.GetUnitTarget(); - if (!target) - { - sLog->outError("SPELL: no unit target for spell ID %u", m_spellInfo->Id); - break; - } - - switch (cur.GetTarget()) - { - case TARGET_UNIT_TARGET_ENEMY: - case TARGET_UNIT_TARGET_ANY: - pushType = PUSH_CHAIN; - break; - case TARGET_UNIT_TARGET_CHAINHEAL_ALLY: - pushType = PUSH_CHAIN; - break; - case TARGET_UNIT_TARGET_ALLY: - AddUnitTarget(target, effectMask, false); - break; - case TARGET_UNIT_TARGET_RAID: - case TARGET_UNIT_TARGET_PARTY: - case TARGET_UNIT_TARGET_MINIPET: - AddUnitTarget(target, effectMask, false); - break; - case TARGET_UNIT_TARGET_PASSENGER: - AddUnitTarget(target, effectMask, false); - break; - case TARGET_UNIT_LASTTARGET_AREA_PARTY: - case TARGET_UNIT_TARGET_AREA_RAID_CLASS: - pushType = PUSH_CASTER_CENTER; // not real - break; - default: - break; - } - break; - } - - case TARGET_TYPE_UNIT_NEARBY: - { - WorldObject* target = NULL; - float range; - - switch (cur.GetTarget()) - { - case TARGET_UNIT_NEARBY_ENEMY: - range = m_spellInfo->GetMaxRange(false); - if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); - target = SearchNearbyTarget(range, SPELL_TARGETS_ENEMY, SpellEffIndex(i)); - break; - case TARGET_UNIT_NEARBY_ALLY: - case TARGET_UNIT_NEARBY_PARTY: // TODO: fix party/raid targets - case TARGET_UNIT_NEARBY_RAID: - range = m_spellInfo->GetMaxRange(true); - if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); - target = SearchNearbyTarget(range, SPELL_TARGETS_ALLY, SpellEffIndex(i)); - break; - case TARGET_UNIT_NEARBY_ENTRY: - case TARGET_GAMEOBJECT_NEARBY_ENTRY: - range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive()); - if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); - target = SearchNearbyTarget(range, SPELL_TARGETS_ENTRY, SpellEffIndex(i)); - break; - default: - break; - } - - if (!target) - return 0; - else if (target->GetTypeId() == TYPEID_GAMEOBJECT) - AddGOTarget((GameObject*)target, effectMask); - else - { - pushType = PUSH_CHAIN; - - if (m_targets.GetUnitTarget() != target) - m_targets.SetUnitTarget((Unit*)target); - } - - break; - } - - case TARGET_TYPE_AREA_SRC: - pushType = PUSH_SRC_CENTER; - break; - - case TARGET_TYPE_AREA_DST: - pushType = PUSH_DST_CENTER; - break; - - case TARGET_TYPE_AREA_CONE: - if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_BACK) - pushType = PUSH_IN_BACK; - else if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_LINE) - pushType = PUSH_IN_LINE; - else - pushType = PUSH_IN_FRONT; - break; - - case TARGET_TYPE_DEST_CASTER: //4+8+2 - { - if (cur.GetTarget() == TARGET_SRC_CASTER) - { - m_targets.SetSrc(*m_caster); - break; - } - else if (cur.GetTarget() == TARGET_DEST_CASTER) - { - m_targets.SetDst(*m_caster); - break; - } - - float angle, dist; - - float objSize = m_caster->GetObjectSize(); - if (cur.GetTarget() == TARGET_DEST_CASTER_SUMMON) - dist = 0.0f; - else - dist = m_spellInfo->Effects[i].CalcRadius(m_caster); - if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, dist, this); - if (dist < objSize) - dist = objSize; - else if (cur.GetTarget() == TARGET_DEST_CASTER_RANDOM) - dist = objSize + (dist - objSize) * (float)rand_norm(); - - switch (cur.GetTarget()) - { - case TARGET_DEST_CASTER_FRONT_LEFT: angle = static_cast<float>(-M_PI/4); break; - case TARGET_DEST_CASTER_BACK_LEFT: angle = static_cast<float>(-3*M_PI/4); break; - case TARGET_DEST_CASTER_BACK_RIGHT: angle = static_cast<float>(3*M_PI/4); break; - case TARGET_DEST_CASTER_FRONT_RIGHT:angle = static_cast<float>(M_PI/4); break; - case TARGET_DEST_CASTER_SUMMON: - case TARGET_DEST_CASTER_FRONT_LEAP: - case TARGET_DEST_CASTER_FRONT: angle = 0.0f; break; - case TARGET_DEST_CASTER_BACK: angle = static_cast<float>(M_PI); break; - case TARGET_DEST_CASTER_RIGHT: angle = static_cast<float>(-M_PI/2); break; - case TARGET_DEST_CASTER_LEFT: angle = static_cast<float>(M_PI/2); break; - default: angle = (float)rand_norm()*static_cast<float>(2*M_PI); break; - } - - Position pos; - if (cur.GetTarget() == TARGET_DEST_CASTER_FRONT_LEAP) - m_caster->GetFirstCollisionPosition(pos, dist, angle); - else - m_caster->GetNearPosition(pos, dist, angle); - m_targets.SetDst(*m_caster); - m_targets.ModDst(pos); - break; - } - - case TARGET_TYPE_DEST_TARGET: //2+8+2 - { - Unit* target = m_targets.GetUnitTarget(); - if (!target) - { - sLog->outError("SPELL: no unit target for spell ID %u", m_spellInfo->Id); - break; - } - - if (cur.GetTarget() == TARGET_DEST_TARGET_ENEMY || cur.GetTarget() == TARGET_DEST_TARGET_ANY) - { - m_targets.SetDst(*target); - break; - } - - float angle, dist; - - float objSize = target->GetObjectSize(); - dist = m_spellInfo->Effects[i].CalcRadius(m_caster); - if (dist < objSize) - dist = objSize; - else if (cur.GetTarget() == TARGET_DEST_TARGET_RANDOM) - dist = objSize + (dist - objSize) * (float)rand_norm(); - - switch (cur.GetTarget()) - { - case TARGET_DEST_TARGET_FRONT: angle = 0.0f; break; - case TARGET_DEST_TARGET_BACK: angle = static_cast<float>(M_PI); break; - case TARGET_DEST_TARGET_RIGHT: angle = static_cast<float>(M_PI/2); break; - case TARGET_DEST_TARGET_LEFT: angle = static_cast<float>(-M_PI/2); break; - case TARGET_DEST_TARGET_FRONT_LEFT: angle = static_cast<float>(-M_PI/4); break; - case TARGET_DEST_TARGET_BACK_LEFT: angle = static_cast<float>(-3*M_PI/4); break; - case TARGET_DEST_TARGET_BACK_RIGHT: angle = static_cast<float>(3*M_PI/4); break; - case TARGET_DEST_TARGET_FRONT_RIGHT:angle = static_cast<float>(M_PI/4); break; - default: angle = (float)rand_norm()*static_cast<float>(2*M_PI); break; - } - - Position pos; - target->GetNearPosition(pos, dist, angle); - m_targets.SetDst(*target); - m_targets.ModDst(pos); - break; - } - - case TARGET_TYPE_DEST_DEST: //5+8+1 - { - if (!m_targets.HasDst()) - { - sLog->outError("SPELL: no destination for spell ID %u", m_spellInfo->Id); - break; - } - - float angle; - switch (cur.GetTarget()) - { - case TARGET_DEST_DYNOBJ_ENEMY: - case TARGET_DEST_DYNOBJ_ALLY: - case TARGET_DEST_DYNOBJ_NONE: - case TARGET_DEST_DEST: - return effectMask; - case TARGET_DEST_TRAJ: - SelectTrajTargets(); - return effectMask; - case TARGET_DEST_DEST_FRONT: angle = 0.0f; break; - case TARGET_DEST_DEST_BACK: angle = static_cast<float>(M_PI); break; - case TARGET_DEST_DEST_RIGHT: angle = static_cast<float>(M_PI/2); break; - case TARGET_DEST_DEST_LEFT: angle = static_cast<float>(-M_PI/2); break; - case TARGET_DEST_DEST_FRONT_LEFT: angle = static_cast<float>(-M_PI/4); break; - case TARGET_DEST_DEST_BACK_LEFT: angle = static_cast<float>(-3*M_PI/4); break; - case TARGET_DEST_DEST_BACK_RIGHT: angle = static_cast<float>(3*M_PI/4); break; - case TARGET_DEST_DEST_FRONT_RIGHT:angle = static_cast<float>(M_PI/4); break; - default: angle = (float)rand_norm()*static_cast<float>(2*M_PI); break; - } - - float dist = m_spellInfo->Effects[i].CalcRadius(m_caster); - if (cur.GetTarget() == TARGET_DEST_DEST_RANDOM || cur.GetTarget() == TARGET_DEST_DEST_RADIUS) - dist *= (float)rand_norm(); - - // must has dst, no need to set flag - Position pos = *m_targets.GetDst(); - m_caster->MovePosition(pos, dist, angle); - m_targets.ModDst(pos); - break; - } - - case TARGET_TYPE_DEST_SPECIAL: - { - switch (cur.GetTarget()) - { - case TARGET_DEST_DB: - if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id)) - { - //TODO: fix this check - if (m_spellInfo->Effects[0].Effect == SPELL_EFFECT_TELEPORT_UNITS || m_spellInfo->Effects[1].Effect == SPELL_EFFECT_TELEPORT_UNITS || m_spellInfo->Effects[2].Effect == SPELL_EFFECT_TELEPORT_UNITS) - m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId); - else if (st->target_mapId == m_caster->GetMapId()) - m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation); - } - else - { - sLog->outError("SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id); - Unit* target = NULL; - if (uint64 guid = m_caster->GetUInt64Value(UNIT_FIELD_TARGET)) - target = ObjectAccessor::GetUnit(*m_caster, guid); - m_targets.SetDst(target ? *target : *m_caster); - } - break; - case TARGET_DEST_HOME: - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_targets.SetDst(m_caster->ToPlayer()->m_homebindX, m_caster->ToPlayer()->m_homebindY, m_caster->ToPlayer()->m_homebindZ, m_caster->ToPlayer()->GetOrientation(), m_caster->ToPlayer()->m_homebindMapId); - break; - case TARGET_DEST_NEARBY_ENTRY: - { - float range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive()); - if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); - - if (WorldObject* target = SearchNearbyTarget(range, SPELL_TARGETS_ENTRY, SpellEffIndex(i))) - m_targets.SetDst(*target); - break; - } - default: - break; - } - break; - } - - case TARGET_TYPE_CHANNEL: - { - if (!m_originalCaster || !m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: no current channeled spell for spell ID %u - spell triggering this spell was interrupted.", m_spellInfo->Id); - break; - } - - switch (cur.GetTarget()) - { - case TARGET_UNIT_CHANNEL_TARGET: - // unit target may be no longer avalible - teleported out of map for example - if (Unit* target = Unit::GetUnit(*m_caster, m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->m_targets.GetUnitTargetGUID())) - AddUnitTarget(target, effectMask); - else - sLog->outError("SPELL: cannot find channel spell target for spell ID %u", m_spellInfo->Id); - break; - case TARGET_DEST_CHANNEL_TARGET: - if (m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->m_targets.HasDst()) - m_targets.SetDst(m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->m_targets); - else if (Unit* target = Unit::GetUnit(*m_caster, m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->m_targets.GetUnitTargetGUID())) - m_targets.SetDst(*target); - else - sLog->outError("SPELL: cannot find channel spell destination for spell ID %u", m_spellInfo->Id); - break; - case TARGET_DEST_CHANNEL_CASTER: - m_targets.SetDst(*m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->GetCaster()); - break; - default: - break; - } - break; - } - - default: - { - switch (cur.GetTarget()) - { - case TARGET_GAMEOBJECT_TARGET: - if (m_targets.GetGOTarget()) - AddGOTarget(m_targets.GetGOTarget(), effectMask); - break; - case TARGET_GAMEOBJECT_ITEM_TARGET: - if (m_targets.GetGOTargetGUID()) - AddGOTarget(m_targets.GetGOTarget(), effectMask); - else if (m_targets.GetItemTarget()) - AddItemTarget(m_targets.GetItemTarget(), effectMask); - break; - default: - sLog->outError("SPELL (caster[type: %u; guidlow: %u], spell: %u): unhandled spell target (%u)", - m_caster->GetTypeId(), m_caster->GetGUIDLow(), m_spellInfo->Id, cur.GetTarget()); - break; - } - break; - } - } - - if (pushType == PUSH_CHAIN) // Chain - { - Unit* target = m_targets.GetUnitTarget(); - if (!target) - { - sLog->outError("SPELL: no chain unit target for spell ID %u", m_spellInfo->Id); - return 0; - } - - //Chain: 2, 6, 22, 25, 45, 77 - uint32 maxTargets = m_spellInfo->Effects[i].ChainTarget; - if (modOwner) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this); - - if (maxTargets > 1) - { - //otherwise, this multiplier is used for something else - for (uint32 k = i; k < MAX_SPELL_EFFECTS; ++k) - if (effectMask & (1 << k)) - m_damageMultipliers[k] = 1.0f; - m_applyMultiplierMask |= effectMask; - - float range; - std::list<Unit*> unitList; - - switch (cur.GetTarget()) - { - case TARGET_UNIT_NEARBY_ENEMY: - case TARGET_UNIT_TARGET_ENEMY: - case TARGET_UNIT_NEARBY_ENTRY: // fix me - range = m_spellInfo->GetMaxRange(false); - if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); - SearchChainTarget(unitList, range, maxTargets, SPELL_TARGETS_ENEMY); - break; - case TARGET_UNIT_TARGET_CHAINHEAL_ALLY: - case TARGET_UNIT_NEARBY_ALLY: // fix me - case TARGET_UNIT_NEARBY_PARTY: - case TARGET_UNIT_NEARBY_RAID: - range = m_spellInfo->GetMaxRange(true); - if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); - SearchChainTarget(unitList, range, maxTargets, SPELL_TARGETS_CHAINHEAL); - break; - default: - break; - } - - CallScriptAfterUnitTargetSelectHandlers(unitList, SpellEffIndex(i)); - - for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) - AddUnitTarget(*itr, effectMask, false); - } - else - AddUnitTarget(target, effectMask, false); - } - else if (pushType) - { - float radius; - SpellTargets targetType; - switch (cur.GetTarget()) - { - case TARGET_UNIT_SRC_AREA_ENEMY: - case TARGET_UNIT_DEST_AREA_ENEMY: - case TARGET_UNIT_CONE_ENEMY_24: - case TARGET_UNIT_CONE_ENEMY_54: - case TARGET_UNIT_CONE_ENEMY_104: - radius = m_spellInfo->Effects[i].CalcRadius(); - targetType = SPELL_TARGETS_ENEMY; - break; - case TARGET_UNIT_SRC_AREA_ALLY: - case TARGET_UNIT_DEST_AREA_ALLY: - case TARGET_UNIT_CONE_ALLY: - radius = m_spellInfo->Effects[i].CalcRadius(); - targetType = SPELL_TARGETS_ALLY; - break; - case TARGET_UNIT_DEST_AREA_ENTRY: - case TARGET_UNIT_SRC_AREA_ENTRY: - case TARGET_UNIT_CONE_ENTRY: // fix me - radius = m_spellInfo->Effects[i].CalcRadius(); - targetType = SPELL_TARGETS_ENTRY; - break; - case TARGET_GAMEOBJECT_SRC_AREA: - case TARGET_GAMEOBJECT_DEST_AREA: - case TARGET_GAMEOBJECT_CONE: - radius = m_spellInfo->Effects[i].CalcRadius(); - targetType = SPELL_TARGETS_GO; - break; - default: - radius = m_spellInfo->Effects[i].CalcRadius(); - targetType = SPELL_TARGETS_NONE; - break; - } - - if (modOwner) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius, this); - radius *= m_spellValue->RadiusMod; - - std::list<Unit*> unitList; - std::list<GameObject*> gobjectList; - switch (targetType) - { - case SPELL_TARGETS_ENTRY: - { - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id); - if (!conditions.empty()) - { - for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST) - { - if ((*i_spellST)->ConditionType != CONDITION_SPELL_SCRIPT_TARGET) - continue; - if ((*i_spellST)->ConditionValue3 && !((*i_spellST)->ConditionValue3 & effectMask)) - continue; - if ((*i_spellST)->ConditionValue1 == SPELL_TARGET_TYPE_CREATURE) - SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, (*i_spellST)->ConditionValue2); - else if ((*i_spellST)->ConditionValue1 == SPELL_TARGET_TYPE_CONTROLLED) - { - for (Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr) - if ((*itr)->GetEntry() == (*i_spellST)->ConditionValue2 && - (*itr)->IsInMap(m_caster)) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect) - unitList.push_back(*itr); - } - } - } - else - { - // Custom entries - // TODO: move these to sql - switch (m_spellInfo->Id) - { - case 46584: // Raise Dead - { - if (WorldObject* result = FindCorpseUsing<Trinity::RaiseDeadObjectCheck>()) - { - switch (result->GetTypeId()) - { - case TYPEID_UNIT: - case TYPEID_PLAYER: - unitList.push_back(result->ToUnit()); - // no break; - case TYPEID_CORPSE: // wont work until corpses are allowed in target lists, but at least will send dest in packet - m_targets.SetDst(*result); - break; - default: - break; - } - } - break; - } - // Corpse Explosion - case 49158: - case 51325: - case 51326: - case 51327: - case 51328: - // Search for ghoul if our ghoul or dead body not valid unit target - if (!(m_targets.GetUnitTarget() && ((m_targets.GetUnitTarget()->GetEntry() == 26125 && m_targets.GetUnitTarget()->GetOwnerGUID() == m_caster->GetGUID()) - || (m_targets.GetUnitTarget()->getDeathState() == CORPSE - && m_targets.GetUnitTarget()->GetTypeId() == TYPEID_UNIT - && !(m_targets.GetUnitTarget()->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL) - && m_targets.GetUnitTarget()->GetDisplayId() == m_targets.GetUnitTarget()->GetNativeDisplayId())))) - { - CleanupTargetList(); - - WorldObject* result = FindCorpseUsing<Trinity::ExplodeCorpseObjectCheck>(); - - if (result) - { - switch (result->GetTypeId()) - { - case TYPEID_UNIT: - case TYPEID_PLAYER: - m_targets.SetUnitTarget((Unit*)result); - break; - default: - break; - } - } - else - { - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true); - SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW); - finish(false); - } - } - break; - - default: - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell (ID: %u) (caster Entry: %u) does not have type CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET record in `conditions` table.", m_spellInfo->Id, m_caster->GetEntry()); - - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_TELEPORT_UNITS) - SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, 0); - else if (m_spellInfo->IsPositiveEffect(i)) - SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY); - else - SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY); - } - } - break; - } - case SPELL_TARGETS_GO: - { - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id); - if (!conditions.empty()) - { - for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST) - { - if ((*i_spellST)->ConditionType != CONDITION_SPELL_SCRIPT_TARGET) - continue; - if ((*i_spellST)->ConditionValue3 && !((*i_spellST)->ConditionValue3 & effectMask)) - continue; - if ((*i_spellST)->ConditionValue1 == SPELL_TARGET_TYPE_GAMEOBJECT) - SearchGOAreaTarget(gobjectList, radius, pushType, SPELL_TARGETS_GO, (*i_spellST)->ConditionValue2); - } - } - else - { - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_ACTIVATE_OBJECT) - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell (ID: %u) (caster Entry: %u) with SPELL_EFFECT_ACTIVATE_OBJECT does not have type CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET record in `conditions` table.", m_spellInfo->Id, m_caster->GetEntry()); - SearchGOAreaTarget(gobjectList, radius, pushType, SPELL_TARGETS_GO); - } - break; - } - case SPELL_TARGETS_ALLY: - case SPELL_TARGETS_ENEMY: - case SPELL_TARGETS_CHAINHEAL: - case SPELL_TARGETS_ANY: - SearchAreaTarget(unitList, radius, pushType, targetType); - break; - default: - switch (cur.GetTarget()) - { - case TARGET_UNIT_SRC_AREA_PARTY: - case TARGET_UNIT_DEST_AREA_PARTY: - m_caster->GetPartyMemberInDist(unitList, radius); //fix me - break; - case TARGET_UNIT_LASTTARGET_AREA_PARTY: - m_targets.GetUnitTarget()->GetPartyMemberInDist(unitList, radius); - break; - case TARGET_UNIT_CASTER_AREA_PARTY: - m_caster->GetPartyMemberInDist(unitList, radius); - break; - case TARGET_UNIT_CASTER_AREA_RAID: - m_caster->GetRaidMember(unitList, radius); - break; - case TARGET_UNIT_TARGET_AREA_RAID_CLASS: - { - Player* targetPlayer = m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->GetTypeId() == TYPEID_PLAYER - ? (Player*)m_targets.GetUnitTarget() : NULL; - - Group* group = targetPlayer ? targetPlayer->GetGroup() : NULL; - if (group) - { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* Target = itr->getSource(); - - // IsHostileTo check duel and controlled by enemy - if (Target && targetPlayer->IsWithinDistInMap(Target, radius) && targetPlayer->getClass() == Target->getClass() && !m_caster->IsHostileTo(Target)) - AddUnitTarget(Target, effectMask); - } - } - else if (m_targets.GetUnitTarget()) - AddUnitTarget(m_targets.GetUnitTarget(), effectMask); - break; - } - default: - break; - } - break; - } - - if (!unitList.empty()) - { - // Special target selection for smart heals and energizes - uint32 maxSize = 0; - int32 power = -1; - switch (m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - switch (m_spellInfo->Id) - { - case 52759: // Ancestral Awakening - case 71610: // Echoes of Light (Althor's Abacus normal version) - case 71641: // Echoes of Light (Althor's Abacus heroic version) - maxSize = 1; - power = POWER_HEALTH; - break; - case 54968: // Glyph of Holy Light - maxSize = m_spellInfo->MaxAffectedTargets; - power = POWER_HEALTH; - break; - case 57669: // Replenishment - // In arenas Replenishment may only affect the caster - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->InArena()) - { - unitList.clear(); - unitList.push_back(m_caster); - break; - } - maxSize = 10; - power = POWER_MANA; - break; - default: - break; - } - break; - case SPELLFAMILY_PRIEST: - if (m_spellInfo->SpellFamilyFlags[0] == 0x10000000) // Circle of Healing - { - maxSize = m_caster->HasAura(55675) ? 6 : 5; // Glyph of Circle of Healing - power = POWER_HEALTH; - } - else if (m_spellInfo->Id == 64844) // Divine Hymn - { - maxSize = 3; - power = POWER_HEALTH; - } - else if (m_spellInfo->Id == 64904) // Hymn of Hope - { - maxSize = 3; - power = POWER_MANA; - } - else - break; - - // Remove targets outside caster's raid - for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) - { - if (!(*itr)->IsInRaidWith(m_caster)) - itr = unitList.erase(itr); - else - ++itr; - } - break; - case SPELLFAMILY_DRUID: - if (m_spellInfo->SpellFamilyFlags[1] == 0x04000000) // Wild Growth - { - maxSize = m_caster->HasAura(62970) ? 6 : 5; // Glyph of Wild Growth - power = POWER_HEALTH; - } - else if (m_spellInfo->SpellFamilyFlags[2] == 0x0100) // Starfall - { - // Remove targets not in LoS or in stealth - for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) - { - if ((*itr)->HasStealthAura() || (*itr)->HasInvisibilityAura() || !(*itr)->IsWithinLOSInMap(m_caster)) - itr = unitList.erase(itr); - else - ++itr; - } - break; - } - else - break; - - // Remove targets outside caster's raid - for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) - if (!(*itr)->IsInRaidWith(m_caster)) - itr = unitList.erase(itr); - else - ++itr; - break; - default: - break; - } - - if (maxSize && power != -1) - { - if (Powers(power) == POWER_HEALTH) - { - if (unitList.size() > maxSize) - { - unitList.sort(Trinity::HealthPctOrderPred()); - unitList.resize(maxSize); - } - } - else - { - for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) - if ((*itr)->getPowerType() != (Powers)power) - itr = unitList.erase(itr); - else - ++itr; - - if (unitList.size() > maxSize) - { - unitList.sort(Trinity::PowerPctOrderPred((Powers)power)); - unitList.resize(maxSize); - } - } - } - - // Other special target selection goes here - if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) - { - Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); - for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j) - if ((*j)->IsAffectedOnSpell(m_spellInfo)) - maxTargets += (*j)->GetAmount(); - - if (m_spellInfo->Id == 5246) //Intimidating Shout - unitList.remove(m_targets.GetUnitTarget()); - Trinity::RandomResizeList(unitList, maxTargets); - } - - CallScriptAfterUnitTargetSelectHandlers(unitList, SpellEffIndex(i)); - - for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) - AddUnitTarget(*itr, effectMask, false); - } - - if (!gobjectList.empty()) - { - if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) - { - Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); - for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j) - if ((*j)->IsAffectedOnSpell(m_spellInfo)) - maxTargets += (*j)->GetAmount(); - - Trinity::RandomResizeList(gobjectList, maxTargets); - } - for (std::list<GameObject*>::iterator itr = gobjectList.begin(); itr != gobjectList.end(); ++itr) - AddGOTarget(*itr, effectMask); - } - } - - return effectMask; -} - void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggeredByAura) { if (m_CastItem) @@ -6847,150 +6854,6 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value) } } -float tangent(float x) -{ - x = tan(x); - //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x; - //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max(); - //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max(); - if (x < 100000.0f && x > -100000.0f) return x; - if (x >= 100000.0f) return 100000.0f; - if (x <= 100000.0f) return -100000.0f; - return 0.0f; -} - -#define DEBUG_TRAJ(a) //a - -void Spell::SelectTrajTargets() -{ - if (!m_targets.HasTraj()) - return; - - float dist2d = m_targets.GetDist2d(); - if (!dist2d) - return; - - float srcToDestDelta = m_targets.GetDst()->m_positionZ - m_targets.GetSrc()->m_positionZ; - - UnitList unitList; - SearchAreaTarget(unitList, dist2d, PUSH_IN_THIN_LINE, SPELL_TARGETS_ANY); - if (unitList.empty()) - return; - - unitList.sort(Trinity::ObjectDistanceOrderPred(m_caster)); - - float b = tangent(m_targets.GetElevation()); - float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d); - if (a > -0.0001f) - a = 0; - DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: a %f b %f", a, b);) - - float bestDist = m_spellInfo->GetMaxRange(false); - - UnitList::const_iterator itr = unitList.begin(); - for (; itr != unitList.end(); ++itr) - { - if (m_caster == *itr || m_caster->IsOnVehicle(*itr) || (*itr)->GetVehicle())//(*itr)->IsOnVehicle(m_caster)) - continue; - - const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3) - // TODO: all calculation should be based on src instead of m_caster - const float objDist2d = m_targets.GetSrc()->GetExactDist2d(*itr) * cos(m_targets.GetSrc()->GetRelativeAngle(*itr)); - const float dz = (*itr)->GetPositionZ() - m_targets.GetSrc()->m_positionZ; - - DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: check %u, dist between %f %f, height between %f %f.", (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size);) - - float dist = objDist2d - size; - float height = dist * (a * dist + b); - DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);) - if (dist < bestDist && height < dz + size && height > dz - size) - { - bestDist = dist > 0 ? dist : 0; - break; - } - -#define CHECK_DIST {\ - DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\ - if (dist > bestDist)\ - continue;\ - if (dist < objDist2d + size && dist > objDist2d - size)\ - {\ - bestDist = dist;\ - break;\ - }\ - } - - if (!a) - { - height = dz - size; - dist = height / b; - CHECK_DIST; - - height = dz + size; - dist = height / b; - CHECK_DIST; - - continue; - } - - height = dz - size; - float sqrt1 = b * b + 4 * a * height; - if (sqrt1 > 0) - { - sqrt1 = sqrt(sqrt1); - dist = (sqrt1 - b) / (2 * a); - CHECK_DIST; - } - - height = dz + size; - float sqrt2 = b * b + 4 * a * height; - if (sqrt2 > 0) - { - sqrt2 = sqrt(sqrt2); - dist = (sqrt2 - b) / (2 * a); - CHECK_DIST; - - dist = (-sqrt2 - b) / (2 * a); - CHECK_DIST; - } - - if (sqrt1 > 0) - { - dist = (-sqrt1 - b) / (2 * a); - CHECK_DIST; - } - } - - if (m_targets.GetSrc()->GetExactDist2d(m_targets.GetDst()) > bestDist) - { - float x = m_targets.GetSrc()->m_positionX + cos(m_caster->GetOrientation()) * bestDist; - float y = m_targets.GetSrc()->m_positionY + sin(m_caster->GetOrientation()) * bestDist; - float z = m_targets.GetSrc()->m_positionZ + bestDist * (a * bestDist + b); - - if (itr != unitList.end()) - { - float distSq = (*itr)->GetExactDistSq(x, y, z); - float sizeSq = (*itr)->GetObjectSize(); - sizeSq *= sizeSq; - DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);) - if (distSq > sizeSq) - { - float factor = 1 - sqrt(sizeSq / distSq); - x += factor * ((*itr)->GetPositionX() - x); - y += factor * ((*itr)->GetPositionY() - y); - z += factor * ((*itr)->GetPositionZ() - z); - - distSq = (*itr)->GetExactDistSq(x, y, z); - DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);) - } - } - - Position trajDst; - trajDst.Relocate(x, y, z, m_caster->GetOrientation()); - m_targets.ModDst(trajDst); - } -} - void Spell::PrepareTargetProcessing() { CheckEffectExecuteData(); @@ -7342,3 +7205,152 @@ void Spell::CancelGlobalCooldown() else if (m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); } + +namespace Trinity +{ + +WorldObjectSpellTargetCheck::WorldObjectSpellTargetCheck(Unit* caster, Unit* referer, SpellInfo const* spellInfo, + SpellTargetCheckTypes selectionType, ConditionList* condList) : _caster(caster), _referer(referer), _spellInfo(spellInfo), + _condList(condList), _targetSelectionType(selectionType) +{ + if (condList) + _condSrcInfo = new ConditionSourceInfo(NULL, caster); + else + _condSrcInfo = NULL; +} + +WorldObjectSpellTargetCheck::~WorldObjectSpellTargetCheck() +{ + if (_condSrcInfo) + delete _condSrcInfo; +} + +bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) +{ + if (_spellInfo->CheckTarget(_caster, target, true) != SPELL_CAST_OK) + return false; + Unit* unitTarget = target->ToUnit(); + if (Corpse* corpseTarget = target->ToCorpse()) + { + // use ofter for party/assistance checks + if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID())) + unitTarget = owner; + else + return false; + } + if (unitTarget) + { + switch (_targetSelectionType) + { + case TARGET_CHECK_ENEMY: + if (unitTarget->isTotem()) + return false; + if (!_caster->_IsValidAttackTarget(unitTarget, _spellInfo)) + return false; + break; + case TARGET_CHECK_ALLY: + if (unitTarget->isTotem()) + return false; + if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo)) + return false; + break; + case TARGET_CHECK_PARTY: + if (unitTarget->isTotem()) + return false; + if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo)) + return false; + if (!_referer->IsInPartyWith(unitTarget)) + return false; + break; + case TARGET_CHECK_RAID_CLASS: + if (_referer->getClass() != unitTarget->getClass()) + return false; + // nobreak; + case TARGET_CHECK_RAID: + if (unitTarget->isTotem()) + return false; + if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo)) + return false; + if (!_referer->IsInRaidWith(unitTarget)) + return false; + break; + default: + break; + } + } + if (!_condSrcInfo) + return true; + _condSrcInfo->mConditionTargets[0] = target; + return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList); +} + +WorldObjectSpellNearbyTargetCheck::WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo, + SpellTargetCheckTypes selectionType, ConditionList* condList) + : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(caster) +{ +} + +bool WorldObjectSpellNearbyTargetCheck::operator()(WorldObject* target) +{ + float dist = target->GetDistance(*_position); + if (dist < _range && WorldObjectSpellTargetCheck::operator ()(target)) + { + _range = dist; + return true; + } + return false; +} + +WorldObjectSpellAreaTargetCheck::WorldObjectSpellAreaTargetCheck(float range, Position const* position, Unit* caster, + Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList) + : WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList), _range(range), _position(position) +{ +} + +bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target) +{ + if (!target->IsWithinDist3d(_position, _range)) + return false; + return WorldObjectSpellTargetCheck::operator ()(target); +} + +WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle, float range, Unit* caster, + SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList) + : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList), _coneAngle(coneAngle) +{ +} + +bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target) +{ + if (_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_BACK) + { + if (!_caster->isInBack(target, _coneAngle)) + return false; + } + else if (_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_LINE) + { + if (!_caster->HasInLine(target, _caster->GetObjectSize())) + return false; + } + else + { + if (!_caster->isInFront(target, _coneAngle)) + return false; + } + return WorldObjectSpellAreaTargetCheck::operator ()(target); +} + +WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo) + : WorldObjectSpellAreaTargetCheck(range, position, caster, caster, spellInfo, TARGET_CHECK_DEFAULT, NULL) +{ +} + +bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target) +{ + // return all targets on missile trajectory (0 - size of a missile) + if (!_caster->HasInLine(target, 0)) + return false; + return WorldObjectSpellAreaTargetCheck::operator ()(target); +} + +} //namespace Trinity diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 583123eb261..5e7c3a94737 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -79,19 +79,6 @@ enum SpellRangeFlag SPELL_RANGE_RANGED = 2, //hunter range and ranged weapon }; -enum SpellNotifyPushType -{ - PUSH_NONE = 0, - PUSH_IN_FRONT, - PUSH_IN_BACK, - PUSH_IN_LINE, - PUSH_IN_THIN_LINE, - PUSH_SRC_CENTER, - PUSH_DST_CENTER, - PUSH_CASTER_CENTER, //this is never used in grid search - PUSH_CHAIN, -}; - class SpellCastTargets { public: @@ -210,17 +197,6 @@ enum SpellEffectHandleMode SPELL_EFFECT_HANDLE_HIT_TARGET, }; -enum SpellTargets -{ - SPELL_TARGETS_NONE = 0, - SPELL_TARGETS_ALLY, - SPELL_TARGETS_ENEMY, - SPELL_TARGETS_ENTRY, - SPELL_TARGETS_CHAINHEAL, - SPELL_TARGETS_ANY, - SPELL_TARGETS_GO -}; - namespace Trinity { struct SpellNotifierCreatureAndPlayer; @@ -228,7 +204,6 @@ namespace Trinity class Spell { - friend struct Trinity::SpellNotifierCreatureAndPlayer; friend void Unit::SetCurrentCastedSpell(Spell* pSpell); friend class SpellScript; public: @@ -364,6 +339,32 @@ class Spell Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID = 0, bool skipCheck = false); ~Spell(); + void InitExplicitTargets(SpellCastTargets const& targets); + void SelectExplicitTargets(); + + void SelectSpellTargets(); + void SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32& processedEffectMask); + void SelectImplicitChannelTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); + void SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask); + void SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask); + void SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask); + void SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); + void SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); + void SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); + void SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); + void SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); + void SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask); + void SelectImplicitTrajTargets(); + + void SelectEffectTypeImplicitTargets(uint8 effIndex); + + uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList); + template<class SEARCHER> void SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius); + + WorldObject* SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList = NULL); + void SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList); + void SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionList* condList, bool isChainHeal); + void prepare(SpellCastTargets const* targets, AuraEffect const* triggeredByAura = NULL); void cancel(); void update(uint32 difftime); @@ -404,15 +405,6 @@ class Spell void WriteSpellGoTargets(WorldPacket* data); void WriteAmmoToPacket(WorldPacket* data); - void InitExplicitTargets(SpellCastTargets const& targets); - void SelectExplicitTargets(); - void SelectSpellTargets(); - void SelectEffectTypeImplicitTargets(uint8 effIndex); - uint32 SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur); - void SelectTrajTargets(); - - template<typename T> WorldObject* FindCorpseUsing(); - bool CheckEffectTarget(Unit const* target, uint32 eff) const; bool CanAutoCast(Unit* target); void CheckSrc() { if (!m_targets.HasSrc()) m_targets.SetSrc(*m_caster); } @@ -607,10 +599,6 @@ class Spell void DoAllEffectOnTarget(GOTargetInfo* target); void DoAllEffectOnTarget(ItemTargetInfo* target); bool UpdateChanneledTargetList(); - void SearchAreaTarget(std::list<Unit*> &unitList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0); - void SearchGOAreaTarget(std::list<GameObject*> &gobjectList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0); - void SearchChainTarget(std::list<Unit*> &unitList, float radius, uint32 unMaxTargets, SpellTargets TargetType); - WorldObject* SearchNearbyTarget(float range, SpellTargets TargetType, SpellEffIndex effIndex); bool IsValidDeadOrAliveTarget(Unit const* target) const; void HandleLaunchPhase(); void DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier); @@ -676,98 +664,52 @@ class Spell namespace Trinity { - struct SpellNotifierCreatureAndPlayer + struct WorldObjectSpellTargetCheck { - std::list<Unit*> *i_data; - SpellNotifyPushType i_push_type; - float i_radius; - SpellTargets i_TargetType; - const Unit* const i_source; - uint32 i_entry; - const Position* const i_pos; - SpellInfo const* i_spellProto; - - SpellNotifierCreatureAndPlayer(Unit* source, std::list<Unit*> &data, float radius, SpellNotifyPushType type, - SpellTargets TargetType = SPELL_TARGETS_ENEMY, const Position* pos = NULL, uint32 entry = 0, SpellInfo const* spellProto = NULL) - : i_data(&data), i_push_type(type), i_radius(radius), i_TargetType(TargetType), - i_source(source), i_entry(entry), i_pos(pos), i_spellProto(spellProto) - { - ASSERT(i_source); - } + Unit* _caster; + Unit* _referer; + SpellInfo const* _spellInfo; + SpellTargetCheckTypes _targetSelectionType; + ConditionSourceInfo* _condSrcInfo; + ConditionList* _condList; + + WorldObjectSpellTargetCheck(Unit* caster, Unit* referer, SpellInfo const* spellInfo, + SpellTargetCheckTypes selectionType, ConditionList* condList); + WorldObjectSpellTargetCheck::~WorldObjectSpellTargetCheck(); + bool operator()(WorldObject* target); + }; - template<class T> inline void Visit(GridRefManager<T>& m) - { - for (typename GridRefManager<T>::iterator itr = m.begin(); itr != m.end(); ++itr) - { - Unit* target = (Unit*)itr->getSource(); - - if (i_spellProto->CheckTarget(i_source, target, true) != SPELL_CAST_OK) - continue; - - switch (i_TargetType) - { - case SPELL_TARGETS_ENEMY: - if (target->isTotem()) - continue; - if (!i_source->_IsValidAttackTarget(target, i_spellProto)) - continue; - break; - case SPELL_TARGETS_ALLY: - if (target->isTotem()) - continue; - if (!i_source->_IsValidAssistTarget(target, i_spellProto)) - continue; - break; - case SPELL_TARGETS_ENTRY: - if (target->GetEntry()!= i_entry) - continue; - break; - case SPELL_TARGETS_ANY: - default: - break; - } - - switch (i_push_type) - { - case PUSH_SRC_CENTER: - case PUSH_DST_CENTER: - case PUSH_CHAIN: - default: - if (target->IsWithinDist3d(i_pos, i_radius)) - i_data->push_back(target); - break; - case PUSH_IN_FRONT: - if (i_source->isInFront(target, i_radius, static_cast<float>(M_PI/2))) - i_data->push_back(target); - break; - case PUSH_IN_BACK: - if (i_source->isInBack(target, i_radius, static_cast<float>(M_PI/2))) - i_data->push_back(target); - break; - case PUSH_IN_LINE: - if (i_source->HasInLine(target, i_radius, i_source->GetObjectSize())) - i_data->push_back(target); - break; - case PUSH_IN_THIN_LINE: // only traj - if (i_pos->HasInLine(target, i_radius, 0)) - i_data->push_back(target); - break; - } - } - } + struct WorldObjectSpellNearbyTargetCheck : public WorldObjectSpellTargetCheck + { + float _range; + Position const* _position; + WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo, + SpellTargetCheckTypes selectionType, ConditionList* condList); + bool operator()(WorldObject* target); + }; + + struct WorldObjectSpellAreaTargetCheck : public WorldObjectSpellTargetCheck + { + float _range; + Position const* _position; + WorldObjectSpellAreaTargetCheck(float range, Position const* position, Unit* caster, + Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList); + bool operator()(WorldObject* target); + }; - #ifdef _WIN32 - template<> inline void Visit(CorpseMapType &) {} - template<> inline void Visit(GameObjectMapType &) {} - template<> inline void Visit(DynamicObjectMapType &) {} - #endif + struct WorldObjectSpellConeTargetCheck : public WorldObjectSpellAreaTargetCheck + { + float _coneAngle; + WorldObjectSpellConeTargetCheck(float coneAngle, float range, Unit* caster, + SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList); + bool operator()(WorldObject* target); }; - #ifndef _WIN32 - template<> inline void SpellNotifierCreatureAndPlayer::Visit(CorpseMapType&) {} - template<> inline void SpellNotifierCreatureAndPlayer::Visit(GameObjectMapType&) {} - template<> inline void SpellNotifierCreatureAndPlayer::Visit(DynamicObjectMapType&) {} - #endif + struct WorldObjectSpellTrajTargetCheck : public WorldObjectSpellAreaTargetCheck + { + WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo); + bool operator()(WorldObject* target); + }; } typedef void(Spell::*pEffect)(SpellEffIndex effIndex); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index ad465767ab0..6d5c802e64f 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -20,6 +20,7 @@ #include "SpellMgr.h" #include "Spell.h" #include "DBCStores.h" +#include "ConditionMgr.h" uint32 GetTargetFlagMask(SpellTargetObjectTypes objType) { @@ -80,7 +81,7 @@ SpellTargetObjectTypes SpellImplicitTargetInfo::GetObjectType() const return _data[_target].ObjectType; } -SpellTargetSelectionCheckTypes SpellImplicitTargetInfo::GetSelectionCheckType() const +SpellTargetCheckTypes SpellImplicitTargetInfo::GetCheckType() const { return _data[_target].SelectionCheckType; } @@ -158,23 +159,25 @@ uint32 SpellImplicitTargetInfo::GetExplicitTargetMask(bool& srcSet, bool& dstSet case TARGET_OBJECT_TYPE_UNIT_AND_DEST: case TARGET_OBJECT_TYPE_UNIT: case TARGET_OBJECT_TYPE_DEST: - switch (GetSelectionCheckType()) + switch (GetCheckType()) { - case TARGET_SELECT_CHECK_ENEMY: + case TARGET_CHECK_ENEMY: targetMask = TARGET_FLAG_UNIT_ENEMY; break; - case TARGET_SELECT_CHECK_ALLY: + case TARGET_CHECK_ALLY: targetMask = TARGET_FLAG_UNIT_ALLY; break; - case TARGET_SELECT_CHECK_PARTY: + case TARGET_CHECK_PARTY: targetMask = TARGET_FLAG_UNIT_PARTY; break; - case TARGET_SELECT_CHECK_RAID: + case TARGET_CHECK_RAID: targetMask = TARGET_FLAG_UNIT_RAID; break; - case TARGET_SELECT_CHECK_PASSENGER: + case TARGET_CHECK_PASSENGER: targetMask = TARGET_FLAG_UNIT_PASSENGER; break; + case TARGET_CHECK_RAID_CLASS: + // nobreak; default: targetMask = TARGET_FLAG_UNIT; break; @@ -344,117 +347,117 @@ SpellSelectTargetTypes SpellImplicitTargetInfo::Type[TOTAL_SPELL_TARGETS]; SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_TARGETS] = { - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 1 TARGET_UNIT_CASTER - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 2 TARGET_UNIT_NEARBY_ENEMY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 3 TARGET_UNIT_NEARBY_PARTY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 4 TARGET_UNIT_NEARBY_ALLY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 5 TARGET_UNIT_PET - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 6 TARGET_UNIT_TARGET_ENEMY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 7 TARGET_UNIT_SRC_AREA_ENTRY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 8 TARGET_UNIT_DEST_AREA_ENTRY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 9 TARGET_DEST_HOME - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 10 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 11 TARGET_UNIT_SRC_AREA_UNK_11 - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 12 - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 13 - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 14 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 15 TARGET_UNIT_SRC_AREA_ENEMY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 16 TARGET_UNIT_DEST_AREA_ENEMY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 17 TARGET_DEST_DB - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 18 TARGET_DEST_CASTER - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 19 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 20 TARGET_UNIT_CASTER_AREA_PARTY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 21 TARGET_UNIT_TARGET_ALLY - {TARGET_OBJECT_TYPE_SRC, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 22 TARGET_SRC_CASTER - {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 23 TARGET_GAMEOBJECT_TARGET - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_FRONT}, // 24 TARGET_UNIT_CONE_ENEMY_24 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 25 TARGET_UNIT_TARGET_ANY - {TARGET_OBJECT_TYPE_GOBJ_ITEM, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 26 TARGET_GAMEOBJECT_ITEM_TARGET - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 27 TARGET_UNIT_MASTER - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 28 TARGET_DEST_DYNOBJ_ENEMY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 29 TARGET_DEST_DYNOBJ_ALLY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 30 TARGET_UNIT_SRC_AREA_ALLY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 31 TARGET_UNIT_DEST_AREA_ALLY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 32 TARGET_DEST_CASTER_SUMMON - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 33 TARGET_UNIT_SRC_AREA_PARTY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 34 TARGET_UNIT_DEST_AREA_PARTY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 35 TARGET_UNIT_TARGET_PARTY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 36 TARGET_DEST_CASTER_UNK_36 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_LAST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 37 TARGET_UNIT_LASTTARGET_AREA_PARTY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 38 TARGET_UNIT_NEARBY_ENTRY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 39 TARGET_DEST_CASTER_FISHING - {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 40 TARGET_GAMEOBJECT_NEARBY_ENTRY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 41 TARGET_DEST_CASTER_FRONT_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 42 TARGET_DEST_CASTER_BACK_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 43 TARGET_DEST_CASTER_BACK_LEFT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 44 TARGET_DEST_CASTER_FRONT_LEFT - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 45 TARGET_UNIT_TARGET_CHAINHEAL_ALLY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 46 TARGET_DEST_NEARBY_ENTRY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 47 TARGET_DEST_CASTER_FRONT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK}, // 48 TARGET_DEST_CASTER_BACK - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 49 TARGET_DEST_CASTER_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 50 TARGET_DEST_CASTER_LEFT - {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 51 TARGET_GAMEOBJECT_SRC_AREA - {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 52 TARGET_GAMEOBJECT_DEST_AREA - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 53 TARGET_DEST_TARGET_ENEMY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_FRONT}, // 54 TARGET_UNIT_CONE_ENEMY_54 - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 55 TARGET_DEST_CASTER_FRONT_LEAP - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_RAID, TARGET_DIR_NONE}, // 56 TARGET_UNIT_CASTER_AREA_RAID - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_RAID, TARGET_DIR_NONE}, // 57 TARGET_UNIT_TARGET_RAID - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_RAID, TARGET_DIR_NONE}, // 58 TARGET_UNIT_NEARBY_RAID - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_FRONT}, // 59 TARGET_UNIT_CONE_ALLY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_FRONT}, // 60 TARGET_UNIT_CONE_ENTRY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_RAID, TARGET_DIR_NONE}, // 61 TARGET_UNIT_TARGET_AREA_RAID_CLASS - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 62 TARGET_UNK_62 - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 63 TARGET_DEST_TARGET_ANY - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 64 TARGET_DEST_TARGET_FRONT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK}, // 65 TARGET_DEST_TARGET_BACK - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 66 TARGET_DEST_TARGET_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 67 TARGET_DEST_TARGET_LEFT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 68 TARGET_DEST_TARGET_FRONT_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 69 TARGET_DEST_TARGET_BACK_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 70 TARGET_DEST_TARGET_BACK_LEFT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 71 TARGET_DEST_TARGET_FRONT_LEFT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 72 TARGET_DEST_CASTER_RANDOM - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 73 TARGET_DEST_CASTER_RADIUS - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 74 TARGET_DEST_TARGET_RANDOM - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 75 TARGET_DEST_TARGET_RADIUS - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 76 TARGET_DEST_CHANNEL_TARGET - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 77 TARGET_UNIT_CHANNEL_TARGET - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 78 TARGET_DEST_DEST_FRONT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK}, // 79 TARGET_DEST_DEST_BACK - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 80 TARGET_DEST_DEST_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 81 TARGET_DEST_DEST_LEFT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 82 TARGET_DEST_DEST_FRONT_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 83 TARGET_DEST_DEST_BACK_RIGHT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 84 TARGET_DEST_DEST_BACK_LEFT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 85 TARGET_DEST_DEST_FRONT_LEFT - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 86 TARGET_DEST_DEST_RANDOM - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 87 TARGET_DEST_DEST - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 88 TARGET_DEST_DYNOBJ_NONE - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 89 TARGET_DEST_TRAJ - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 90 TARGET_UNIT_TARGET_MINIPET - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 91 TARGET_DEST_DEST_RADIUS - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 92 TARGET_UNIT_SUMMONER - {TARGET_OBJECT_TYPE_CORPSE, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 93 TARGET_CORPSE_SRC_AREA_ENEMY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 94 TARGET_UNIT_VEHICLE - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_PASSENGER, TARGET_DIR_NONE}, // 95 TARGET_UNIT_TARGET_PASSENGER - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 96 TARGET_UNIT_PASSENGER_0 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 97 TARGET_UNIT_PASSENGER_1 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 98 TARGET_UNIT_PASSENGER_2 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 99 TARGET_UNIT_PASSENGER_3 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 100 TARGET_UNIT_PASSENGER_4 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 101 TARGET_UNIT_PASSENGER_5 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 102 TARGET_UNIT_PASSENGER_6 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 103 TARGET_UNIT_PASSENGER_7 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_FRONT}, // 104 TARGET_UNIT_CONE_ENEMY_104 - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 105 TARGET_UNIT_UNK_105 - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 106 TARGET_DEST_CHANNEL_CASTER - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 107 TARGET_UNK_DEST_AREA_UNK_107 - {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 108 TARGET_GAMEOBJECT_CONE - {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 109 - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 110 TARGET_DEST_UNK_110 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 1 TARGET_UNIT_CASTER + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 2 TARGET_UNIT_NEARBY_ENEMY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 3 TARGET_UNIT_NEARBY_PARTY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 4 TARGET_UNIT_NEARBY_ALLY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 5 TARGET_UNIT_PET + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 6 TARGET_UNIT_TARGET_ENEMY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 7 TARGET_UNIT_SRC_AREA_ENTRY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 8 TARGET_UNIT_DEST_AREA_ENTRY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 9 TARGET_DEST_HOME + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 10 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 11 TARGET_UNIT_SRC_AREA_UNK_11 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 12 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 13 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 14 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 15 TARGET_UNIT_SRC_AREA_ENEMY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 16 TARGET_UNIT_DEST_AREA_ENEMY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 17 TARGET_DEST_DB + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 18 TARGET_DEST_CASTER + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 19 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 20 TARGET_UNIT_CASTER_AREA_PARTY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 21 TARGET_UNIT_TARGET_ALLY + {TARGET_OBJECT_TYPE_SRC, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 22 TARGET_SRC_CASTER + {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 23 TARGET_GAMEOBJECT_TARGET + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 24 TARGET_UNIT_CONE_ENEMY_24 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 25 TARGET_UNIT_TARGET_ANY + {TARGET_OBJECT_TYPE_GOBJ_ITEM, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 26 TARGET_GAMEOBJECT_ITEM_TARGET + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 27 TARGET_UNIT_MASTER + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 28 TARGET_DEST_DYNOBJ_ENEMY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 29 TARGET_DEST_DYNOBJ_ALLY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 30 TARGET_UNIT_SRC_AREA_ALLY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 31 TARGET_UNIT_DEST_AREA_ALLY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 32 TARGET_DEST_CASTER_SUMMON + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 33 TARGET_UNIT_SRC_AREA_PARTY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 34 TARGET_UNIT_DEST_AREA_PARTY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 35 TARGET_UNIT_TARGET_PARTY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 36 TARGET_DEST_CASTER_UNK_36 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_LAST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 37 TARGET_UNIT_LASTTARGET_AREA_PARTY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 38 TARGET_UNIT_NEARBY_ENTRY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 39 TARGET_DEST_CASTER_FISHING + {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 40 TARGET_GAMEOBJECT_NEARBY_ENTRY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 41 TARGET_DEST_CASTER_FRONT_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 42 TARGET_DEST_CASTER_BACK_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 43 TARGET_DEST_CASTER_BACK_LEFT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 44 TARGET_DEST_CASTER_FRONT_LEFT + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 45 TARGET_UNIT_TARGET_CHAINHEAL_ALLY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 46 TARGET_DEST_NEARBY_ENTRY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 47 TARGET_DEST_CASTER_FRONT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK}, // 48 TARGET_DEST_CASTER_BACK + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 49 TARGET_DEST_CASTER_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 50 TARGET_DEST_CASTER_LEFT + {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 51 TARGET_GAMEOBJECT_SRC_AREA + {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 52 TARGET_GAMEOBJECT_DEST_AREA + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 53 TARGET_DEST_TARGET_ENEMY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 54 TARGET_UNIT_CONE_ENEMY_54 + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 55 TARGET_DEST_CASTER_FRONT_LEAP + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_RAID, TARGET_DIR_NONE}, // 56 TARGET_UNIT_CASTER_AREA_RAID + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_RAID, TARGET_DIR_NONE}, // 57 TARGET_UNIT_TARGET_RAID + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_RAID, TARGET_DIR_NONE}, // 58 TARGET_UNIT_NEARBY_RAID + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ALLY, TARGET_DIR_FRONT}, // 59 TARGET_UNIT_CONE_ALLY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENTRY, TARGET_DIR_FRONT}, // 60 TARGET_UNIT_CONE_ENTRY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_RAID_CLASS,TARGET_DIR_NONE}, // 61 TARGET_UNIT_TARGET_AREA_RAID_CLASS + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 62 TARGET_UNK_62 + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 63 TARGET_DEST_TARGET_ANY + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 64 TARGET_DEST_TARGET_FRONT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK}, // 65 TARGET_DEST_TARGET_BACK + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 66 TARGET_DEST_TARGET_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 67 TARGET_DEST_TARGET_LEFT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 68 TARGET_DEST_TARGET_FRONT_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 69 TARGET_DEST_TARGET_BACK_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 70 TARGET_DEST_TARGET_BACK_LEFT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 71 TARGET_DEST_TARGET_FRONT_LEFT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 72 TARGET_DEST_CASTER_RANDOM + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 73 TARGET_DEST_CASTER_RADIUS + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 74 TARGET_DEST_TARGET_RANDOM + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 75 TARGET_DEST_TARGET_RADIUS + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 76 TARGET_DEST_CHANNEL_TARGET + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 77 TARGET_UNIT_CHANNEL_TARGET + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 78 TARGET_DEST_DEST_FRONT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK}, // 79 TARGET_DEST_DEST_BACK + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 80 TARGET_DEST_DEST_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 81 TARGET_DEST_DEST_LEFT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 82 TARGET_DEST_DEST_FRONT_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 83 TARGET_DEST_DEST_BACK_RIGHT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 84 TARGET_DEST_DEST_BACK_LEFT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 85 TARGET_DEST_DEST_FRONT_LEFT + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 86 TARGET_DEST_DEST_RANDOM + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 87 TARGET_DEST_DEST + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 88 TARGET_DEST_DYNOBJ_NONE + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 89 TARGET_DEST_TRAJ + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 90 TARGET_UNIT_TARGET_MINIPET + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 91 TARGET_DEST_DEST_RADIUS + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 92 TARGET_UNIT_SUMMONER + {TARGET_OBJECT_TYPE_CORPSE, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 93 TARGET_CORPSE_SRC_AREA_ENEMY + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 94 TARGET_UNIT_VEHICLE + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_PASSENGER, TARGET_DIR_NONE}, // 95 TARGET_UNIT_TARGET_PASSENGER + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 96 TARGET_UNIT_PASSENGER_0 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 97 TARGET_UNIT_PASSENGER_1 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 98 TARGET_UNIT_PASSENGER_2 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 99 TARGET_UNIT_PASSENGER_3 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 100 TARGET_UNIT_PASSENGER_4 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 101 TARGET_UNIT_PASSENGER_5 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 102 TARGET_UNIT_PASSENGER_6 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 103 TARGET_UNIT_PASSENGER_7 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 104 TARGET_UNIT_CONE_ENEMY_104 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 105 TARGET_UNIT_UNK_105 + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 106 TARGET_DEST_CHANNEL_CASTER + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 107 TARGET_UNK_DEST_AREA_UNK_107 + {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 108 TARGET_GAMEOBJECT_CONE + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 109 + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 110 TARGET_DEST_UNK_110 }; SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex) @@ -481,6 +484,7 @@ SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* ItemType = spellEntry->EffectItemType[effIndex]; TriggerSpell = spellEntry->EffectTriggerSpell[effIndex]; SpellClassMask = spellEntry->EffectSpellClassMask[effIndex]; + ImplicitTargetConditions = NULL; } bool SpellEffectInfo::IsEffect() const @@ -938,6 +942,11 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry) ChainEntry = NULL; } +SpellInfo::~SpellInfo() +{ + _UnloadImplicitTargetConditionLists(); +} + bool SpellInfo::HasEffect(SpellEffects effect) const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -1563,38 +1572,99 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a return SPELL_CAST_OK; } -SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, bool implicit) const +SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* target, bool implicit) const { if (AttributesEx & SPELL_ATTR1_CANT_TARGET_SELF && caster == target) return SPELL_FAILED_BAD_TARGETS; - if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT && target->isInCombat()) - return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + // check visibility - ignore stealth for implicit (area) targets + if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->canSeeOrDetect(target, implicit)) + return SPELL_FAILED_BAD_TARGETS; + + Unit const* unitTarget; + + // creature/player specific target checks + if (unitTarget = target->ToUnit()) + { + if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT && unitTarget->isInCombat()) + return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + + // only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts + if (((AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) != 0) != unitTarget->HasAuraType(SPELL_AURA_GHOST)) + { + if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) + return SPELL_FAILED_TARGET_NOT_GHOST; + else + return SPELL_FAILED_BAD_TARGETS; + } + + if (caster != unitTarget) + { + if (caster->GetTypeId() == TYPEID_PLAYER) + { + // Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells) + if (AttributesEx2 & SPELL_ATTR2_CANT_TARGET_TAPPED) + if (Creature const* targetCreature = unitTarget->ToCreature()) + if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(caster->ToPlayer())) + return SPELL_FAILED_CANT_CAST_ON_TAPPED; + + if (AttributesCu & SPELL_ATTR0_CU_PICKPOCKET) + { + if (unitTarget->GetTypeId() == TYPEID_PLAYER) + return SPELL_FAILED_BAD_TARGETS; + else if ((unitTarget->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0) + return SPELL_FAILED_TARGET_NO_POCKETS; + } + + // Not allow disarm unarmed player + if (Mechanic == MECHANIC_DISARM) + { + if (unitTarget->GetTypeId() == TYPEID_PLAYER) + { + Player const* player = unitTarget->ToPlayer(); + if (!player->GetWeaponForAttack(BASE_ATTACK) || !player->IsUseEquipedWeapon(true)) + return SPELL_FAILED_TARGET_NO_WEAPONS; + } + else if (!unitTarget->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID)) + return SPELL_FAILED_TARGET_NO_WEAPONS; + } + } + } + } + // corpse specific target checks + else if (Corpse const* corpseTarget = target->ToCorpse()) + { + // cannot target bare bones + if (corpseTarget->GetType() == CORPSE_BONES) + return SPELL_FAILED_BAD_TARGETS; + // we have to use owner for some checks (aura preventing resurrection for example) + if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID())) + unitTarget = owner; + // we're not interested in corpses without owner + else + return SPELL_FAILED_BAD_TARGETS; + } + // other types of objects - always valid + else return SPELL_CAST_OK; - if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !target->ToPlayer()) + // corpseOwner and unit specific target checks + if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !unitTarget->ToPlayer()) return SPELL_FAILED_TARGET_NOT_PLAYER; - if (!IsAllowingDeadTarget() && !target->isAlive()) + if (!IsAllowingDeadTarget() && !unitTarget->isAlive()) return SPELL_FAILED_TARGETS_DEAD; - if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS && !(!target->isAlive() && target->HasAuraType(SPELL_AURA_GHOST))) - return SPELL_FAILED_TARGET_NOT_GHOST; - // check this flag only for implicit targets (chain and area), allow to explicitly target units for spells like Shield of Righteousness - if (implicit && AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !target->CanFreeMove()) + if (implicit && AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !unitTarget->CanFreeMove()) return SPELL_FAILED_BAD_TARGETS; - // check visibility - ignore stealth for implicit (area) targets - if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->canSeeOrDetect(target, implicit)) - return SPELL_FAILED_BAD_TARGETS; - // checked in Unit::IsValidAttack/AssistTarget, shouldn't be checked for ENTRY targets //if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) // return SPELL_FAILED_BAD_TARGETS; //if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS) - if (!CheckTargetCreatureType(target)) + if (!CheckTargetCreatureType(unitTarget)) { if (target->GetTypeId() == TYPEID_PLAYER) return SPELL_FAILED_TARGET_IS_PLAYER; @@ -1603,65 +1673,32 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, b } // check GM mode and GM invisibility - only for player casts (npc casts are controlled by AI) and negative spells - if (target != caster && (caster->IsControlledByPlayer() || !IsPositive()) && target->GetTypeId() == TYPEID_PLAYER) + if (unitTarget != caster && (caster->IsControlledByPlayer() || !IsPositive()) && unitTarget->GetTypeId() == TYPEID_PLAYER) { - if (!target->ToPlayer()->IsVisible()) + if (!unitTarget->ToPlayer()->IsVisible()) return SPELL_FAILED_BM_OR_INVISGOD; - if (target->ToPlayer()->isGameMaster()) + if (unitTarget->ToPlayer()->isGameMaster()) return SPELL_FAILED_BM_OR_INVISGOD; } // not allow casting on flying player - if (target->HasUnitState(UNIT_STATE_IN_FLIGHT)) + if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT)) return SPELL_FAILED_BAD_TARGETS; - if (TargetAuraState && !target->HasAuraState(AuraStateType(TargetAuraState), this, caster)) + if (TargetAuraState && !unitTarget->HasAuraState(AuraStateType(TargetAuraState), this, caster)) return SPELL_FAILED_TARGET_AURASTATE; - if (TargetAuraStateNot && target->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster)) + if (TargetAuraStateNot && unitTarget->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster)) return SPELL_FAILED_TARGET_AURASTATE; - if (TargetAuraSpell && !target->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster))) + if (TargetAuraSpell && !unitTarget->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster))) return SPELL_FAILED_TARGET_AURASTATE; - if (ExcludeTargetAuraSpell && target->HasAura(sSpellMgr->GetSpellIdForDifficulty(ExcludeTargetAuraSpell, caster))) + if (ExcludeTargetAuraSpell && unitTarget->HasAura(sSpellMgr->GetSpellIdForDifficulty(ExcludeTargetAuraSpell, caster))) return SPELL_FAILED_TARGET_AURASTATE; - if (caster != target) - { - if (caster->GetTypeId() == TYPEID_PLAYER) - { - // Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells) - if (AttributesEx2 & SPELL_ATTR2_CANT_TARGET_TAPPED) - if (Creature const* targetCreature = target->ToCreature()) - if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(caster->ToPlayer())) - return SPELL_FAILED_CANT_CAST_ON_TAPPED; - - if (AttributesCu & SPELL_ATTR0_CU_PICKPOCKET) - { - if (target->GetTypeId() == TYPEID_PLAYER) - return SPELL_FAILED_BAD_TARGETS; - else if ((target->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0) - return SPELL_FAILED_TARGET_NO_POCKETS; - } - - // Not allow disarm unarmed player - if (Mechanic == MECHANIC_DISARM) - { - if (target->GetTypeId() == TYPEID_PLAYER) - { - Player const* player = target->ToPlayer(); - if (!player->GetWeaponForAttack(BASE_ATTACK) || !player->IsUseEquipedWeapon(true)) - return SPELL_FAILED_TARGET_NO_WEAPONS; - } - else if (!target->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID)) - return SPELL_FAILED_TARGET_NO_WEAPONS; - } - } - } - - if (target->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) + if (unitTarget->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT_NEW)) return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED; @@ -2035,13 +2072,19 @@ float SpellInfo::GetMinRange(bool positive) const return RangeEntry->minRangeHostile; } -float SpellInfo::GetMaxRange(bool positive) const +float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const { if (!RangeEntry) return 0.0f; + float range; if (positive) - return RangeEntry->maxRangeFriend; - return RangeEntry->maxRangeHostile; + range = RangeEntry->maxRangeFriend; + else + range = RangeEntry->maxRangeHostile; + if (caster) + if (Player* modOwner = caster->GetSpellModOwner()) + modOwner->ApplySpellMod(Id, SPELLMOD_RANGE, range, spell); + return range; } int32 SpellInfo::GetDuration() const @@ -2552,3 +2595,20 @@ bool SpellInfo::_IsPositiveTarget(uint32 targetA, uint32 targetB) return _IsPositiveTarget(targetB, 0); return true; } + +void SpellInfo::_UnloadImplicitTargetConditionLists() +{ + // find the same instances of ConditionList and delete them. + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + ConditionList* cur = Effects[i].ImplicitTargetConditions; + if (!cur) + continue; + for (uint8 j = i; j < MAX_SPELL_EFFECTS; ++j) + { + if (Effects[j].ImplicitTargetConditions == cur) + Effects[j].ImplicitTargetConditions = NULL; + } + delete cur; + } +} diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 65be5981c64..69ea07f7563 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -36,6 +36,7 @@ struct SpellRangeEntry; struct SpellRadiusEntry; struct SpellEntry; struct SpellCastTimesEntry; +struct Condition; enum SpellCastTargetFlags { @@ -105,15 +106,16 @@ enum SpellTargetObjectTypes TARGET_OBJECT_TYPE_CORPSE_ALLY, }; -enum SpellTargetSelectionCheckTypes +enum SpellTargetCheckTypes { - TARGET_SELECT_CHECK_DEFAULT, - TARGET_SELECT_CHECK_ENTRY, - TARGET_SELECT_CHECK_ENEMY, - TARGET_SELECT_CHECK_ALLY, - TARGET_SELECT_CHECK_PARTY, - TARGET_SELECT_CHECK_RAID, - TARGET_SELECT_CHECK_PASSENGER, + TARGET_CHECK_DEFAULT, + TARGET_CHECK_ENTRY, + TARGET_CHECK_ENEMY, + TARGET_CHECK_ALLY, + TARGET_CHECK_PARTY, + TARGET_CHECK_RAID, + TARGET_CHECK_RAID_CLASS, + TARGET_CHECK_PASSENGER, }; enum SpellTargetDirectionTypes @@ -220,7 +222,7 @@ public: SpellTargetSelectionCategories GetSelectionCategory() const; SpellTargetReferenceTypes GetReferenceType() const; SpellTargetObjectTypes GetObjectType() const; - SpellTargetSelectionCheckTypes GetSelectionCheckType() const; + SpellTargetCheckTypes GetCheckType() const; SpellTargetDirectionTypes GetDirectionType() const; float CalcDirectionAngle() const; @@ -240,7 +242,7 @@ private: SpellTargetObjectTypes ObjectType; // type of object returned by target type SpellTargetReferenceTypes ReferenceType; // defines which object is used as a reference when selecting target SpellTargetSelectionCategories SelectionCategory; - SpellTargetSelectionCheckTypes SelectionCheckType; // defines selection criteria + SpellTargetCheckTypes SelectionCheckType; // defines selection criteria SpellTargetDirectionTypes DirectionType; // direction for cone and dest targets }; static StaticData _data[TOTAL_SPELL_TARGETS]; @@ -271,6 +273,7 @@ public: uint32 ItemType; uint32 TriggerSpell; flag96 SpellClassMask; + std::list<Condition*>* ImplicitTargetConditions; SpellEffectInfo() {} SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex); @@ -388,6 +391,7 @@ public: SpellChainNode const* ChainEntry; SpellInfo(SpellEntry const* spellEntry); + ~SpellInfo(); bool HasEffect(SpellEffects effect) const; bool HasAura(AuraType aura) const; @@ -438,7 +442,7 @@ public: SpellCastResult CheckShapeshift(uint32 form) const; SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const; - SpellCastResult CheckTarget(Unit const* caster, Unit const* target, bool implicit = true) const; + SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const; SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const; bool CheckTargetCreatureType(Unit const* target) const; @@ -456,7 +460,7 @@ public: SpellSpecificType GetSpellSpecific() const; float GetMinRange(bool positive = false) const; - float GetMaxRange(bool positive = false) const; + float GetMaxRange(bool positive = false, Unit* caster = NULL, Spell* spell = NULL) const; int32 GetDuration() const; int32 GetMaxDuration() const; @@ -482,6 +486,9 @@ public: bool _IsPositiveEffect(uint8 effIndex, bool deep) const; bool _IsPositiveSpell() const; static bool _IsPositiveTarget(uint32 targetA, uint32 targetB); + + // unloading helpers + void _UnloadImplicitTargetConditionLists(); }; #endif // _SPELLINFO_H diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index ff4eaae42f2..c1b267d9fac 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2644,11 +2644,20 @@ void SpellMgr::UnloadSpellInfoStore() for (uint32 i = 0; i < mSpellInfoMap.size(); ++i) { if (mSpellInfoMap[i]) - delete mSpellInfoMap[i]; + delete mSpellInfoMap[i]; } mSpellInfoMap.clear(); } +void SpellMgr::UnloadSpellInfoImplicitTargetConditionLists() +{ + for (uint32 i = 0; i < mSpellInfoMap.size(); ++i) + { + if (mSpellInfoMap[i]) + mSpellInfoMap[i]->_UnloadImplicitTargetConditionLists(); + } +} + void SpellMgr::LoadSpellCustomAttr() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 14137b6a91b..9fffd474651 100755 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -360,17 +360,6 @@ struct SpellThreatEntry typedef std::map<uint32, SpellThreatEntry> SpellThreatMap; -// Spell script target related declarations (accessed using SpellMgr functions) -enum SpellScriptTargetType -{ - SPELL_TARGET_TYPE_GAMEOBJECT = 0, - SPELL_TARGET_TYPE_CREATURE = 1, - SPELL_TARGET_TYPE_DEAD = 2, - SPELL_TARGET_TYPE_CONTROLLED = 3, -}; - -#define MAX_SPELL_TARGET_TYPE 4 - // coordinates for spells (accessed using SpellMgr functions) struct SpellTargetPosition { @@ -726,6 +715,7 @@ class SpellMgr void LoadSpellAreas(); void LoadSpellInfoStore(); void UnloadSpellInfoStore(); + void UnloadSpellInfoImplicitTargetConditionLists(); void LoadSpellCustomAttr(); void LoadDbcDataCorrections(); diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 14dd32a71b6..03fea614c0d 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -473,11 +473,6 @@ void SpellScript::GetSummonPosition(uint32 i, Position &pos, float radius = 0.0f m_spell->GetSummonPosition(i, pos, radius, count); } -void SpellScript::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry) -{ - m_spell->SearchAreaTarget(TagUnitMap, radius, type, TargetType, entry); -} - void SpellScript::PreventHitEffect(SpellEffIndex effIndex) { if (!IsInHitPhase() && !IsInEffectHook()) diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 09b9eaebd62..1bf8d25adef 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -336,7 +336,6 @@ class SpellScript : public _SpellScript void PreventHitHeal() { SetHitHeal(0); } Spell* GetSpell() { return m_spell; } void GetSummonPosition(uint32 i, Position &pos, float radius, uint32 count); - void SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry); // returns current spell hit target aura Aura* GetHitAura(); // prevents applying aura on current spell hit target diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp index d5695a0f39d..19ed96e8885 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp @@ -62,7 +62,7 @@ class OrientationCheck : public std::unary_function<Unit*, bool> explicit OrientationCheck(Unit* _caster) : caster(_caster) { } bool operator() (Unit* unit) { - return !unit->isInFront(caster, 40.0f, 2.5f); + return !unit->isInFront(caster, 2.5f) || !unit->IsWithinDist(caster, 40.0f); } private: diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index da46d016e91..c4f973726bc 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -1736,25 +1736,29 @@ class spell_vehicle_throw_passenger : public SpellScriptLoader if (Vehicle* vehicle = GetCaster()->GetVehicleKit()) if (Unit* passenger = vehicle->GetPassenger(damage - 1)) { - std::list<Unit*> unitList; // use 99 because it is 3d search - SearchAreaTarget(unitList, 99, PUSH_DST_CENTER, SPELL_TARGETS_ENTRY, NPC_SEAT); + std::list<WorldObject*> targetList; + Trinity::WorldObjectSpellAreaTargetCheck check(99, GetTargetDest(), GetCaster(), GetCaster(), GetSpellInfo(), TARGET_CHECK_DEFAULT, NULL); + Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> searcher(GetCaster(), targetList, check); + GetCaster()->GetMap()->VisitAll(GetCaster()->m_positionX, GetCaster()->m_positionY, 99, searcher); float minDist = 99 * 99; Unit* target = NULL; - for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) + for (std::list<WorldObject*>::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) { - if (Vehicle* seat = (*itr)->GetVehicleKit()) - if (!seat->GetPassenger(0)) - if (Unit* device = seat->GetPassenger(2)) - if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - { - float dist = (*itr)->GetExactDistSq(targets.GetDst()); - if (dist < minDist) - { - minDist = dist; - target = (*itr); - } - } + if (Unit* unit = (*itr)->ToUnit()) + if (unit->GetEntry() == NPC_SEAT) + if (Vehicle* seat = unit->GetVehicleKit()) + if (!seat->GetPassenger(0)) + if (Unit* device = seat->GetPassenger(2)) + if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + { + float dist = unit->GetExactDistSq(targets.GetDst()); + if (dist < minDist) + { + minDist = dist; + target = unit; + } + } } if (target && target->IsWithinDist2d(targets.GetDst(), GetSpellInfo()->Effects[effIndex].CalcRadius() * 2)) // now we use *2 because the location of the seat is not correct passenger->EnterVehicle(target, 0); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 638a17bc4f9..3835cb8ca0f 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -196,7 +196,7 @@ class spell_gen_cannibalize : public SpellScriptLoader float max_range = GetSpellInfo()->GetMaxRange(false); WorldObject* result = NULL; // search for nearby enemy corpse in range - Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_SELECT_CHECK_ENEMY); + Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_CHECK_ENEMY); Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check); caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher); if (!result) diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index dd9bfd90a0b..855af75cd83 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -532,7 +532,7 @@ class spell_hun_pet_carrion_feeder : public SpellScriptLoader float max_range = GetSpellInfo()->GetMaxRange(false); WorldObject* result = NULL; // search for nearby enemy corpse in range - Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_SELECT_CHECK_ENEMY); + Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_CHECK_ENEMY); Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check); caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher); if (!result) |