From 903b810353779b6ee6272bde1a4e6415038daa48 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Wed, 11 Mar 2009 16:32:19 +0300 Subject: [PATCH 01/46] [7441] Fixed reward money counting for ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD --- src/game/Player.cpp | 6 ++++-- src/shared/revision_nr.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 65a3cf2b2..9abcebfb9 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -12852,7 +12852,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver GiveXP( XP , NULL ); else { - int32 money = int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)); + uint32 money = uint32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)); ModifyMoney( money ); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, money); } @@ -12861,7 +12861,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver if(pQuest->GetRewOrReqMoney()) { ModifyMoney( pQuest->GetRewOrReqMoney() ); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney()); + + if(pQuest->GetRewOrReqMoney() > 0) + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney()); } // honor reward diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 96986cb2e..b81b26e98 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7440" + #define REVISION_NR "7441" #endif // __REVISION_NR_H__ From 498ab2df070cd8a3abc210455e84116bf4a7002a Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Wed, 11 Mar 2009 22:40:12 +0300 Subject: [PATCH 02/46] [7442] Implement TARGET_DIRECTLY_FORWARD spell target mode. It used in many cannon/rocket ike spells. --- src/game/SharedDefines.h | 3 ++- src/game/Spell.cpp | 23 ++++++++++++++++++++++- src/shared/revision_nr.h | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 7a27b0f03..981444368 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -838,10 +838,11 @@ enum Targets TARGET_SINGLE_FRIEND_2 = 57, TARGET_AREAEFFECT_PARTY_AND_CLASS = 61, TARGET_DUELVSPLAYER_COORDINATES = 63, - TARGET_BEHIND_VICTIM = 65, // uses in teleport behind spells + TARGET_BEHIND_VICTIM = 65, // uses in teleport behind spells, caster/target dependent from spell effect TARGET_DYNAMIC_OBJECT_COORDINATES = 76, TARGET_SINGLE_ENEMY = 77, TARGET_SELF2 = 87, + TARGET_DIRECTLY_FORWARD = 89, TARGET_NONCOMBAT_PET = 90, }; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 71ee209f5..04fc0ae65 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -448,6 +448,9 @@ void Spell::FillTargetMap() default: switch(m_spellInfo->EffectImplicitTargetB[i]) { + case 0: + SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); + break; case TARGET_SCRIPT_COORDINATES: // B case filled in canCast but we need fill unit list base at A case SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); break; @@ -2065,7 +2068,25 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) // if parent spell create dynamic object extract area from it if(DynamicObject* dynObj = m_caster->GetDynObject(m_triggeredByAuraSpell ? m_triggeredByAuraSpell->Id : m_spellInfo->Id)) m_targets.setDestination(dynObj->GetPositionX(), dynObj->GetPositionY(), dynObj->GetPositionZ()); - }break; + break; + } + case TARGET_DIRECTLY_FORWARD: + { + if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) + { + SpellRangeEntry const* rEntry = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); + float minRange = GetSpellMinRange(rEntry); + float maxRange = GetSpellMaxRange(rEntry); + float dist = minRange+ rand_norm()*(maxRange-minRange); + + float _target_x, _target_y, _target_z; + m_caster->GetClosePoint(_target_x, _target_y, _target_z, m_caster->GetObjectSize(), dist); + m_targets.setDestination(_target_x, _target_y, _target_z); + } + + TagUnitMap.push_back(m_caster); + break; + } default: break; } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b81b26e98..bd8b21711 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7441" + #define REVISION_NR "7442" #endif // __REVISION_NR_H__ From 719991d3819a1e4beffb5e5f7b9bd75f61906010 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Thu, 12 Mar 2009 10:01:34 +0300 Subject: [PATCH 03/46] [7443] Better error reporting at DBC files extraction in ad.exe. No functionlity chnages in normal work case. --- contrib/extractor/System.cpp | 21 ++++++++++++++++++--- contrib/extractor/ad.exe | Bin 162816 -> 163840 bytes contrib/extractor/dbcfile.cpp | 31 ++++++++++++++++++++++--------- contrib/extractor/dbcfile.h | 2 +- src/shared/revision_nr.h | 2 +- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/contrib/extractor/System.cpp b/contrib/extractor/System.cpp index 843fe616e..9dffa0048 100644 --- a/contrib/extractor/System.cpp +++ b/contrib/extractor/System.cpp @@ -153,7 +153,12 @@ uint32 ReadMapDBC() { printf("Read Map.dbc file... "); DBCFile dbc("DBFilesClient\\Map.dbc"); - dbc.open(); + + if(!dbc.open()) + { + printf("Fatal error: Invalid Map.dbc file format!\n"); + exit(1); + } size_t map_count = dbc.getRecordCount(); map_ids = new map_id[map_count]; @@ -170,7 +175,12 @@ void ReadAreaTableDBC() { printf("Read AreaTable.dbc file..."); DBCFile dbc("DBFilesClient\\AreaTable.dbc"); - dbc.open(); + + if(!dbc.open()) + { + printf("Fatal error: Invalid AreaTable.dbc file format!\n"); + exit(1); + } size_t area_count = dbc.getRecordCount(); size_t maxid = dbc.getMaxId(); @@ -189,7 +199,12 @@ void ReadLiquidTypeTableDBC() { printf("Read LiquidType.dbc file..."); DBCFile dbc("DBFilesClient\\LiquidType.dbc"); - dbc.open(); + if(!dbc.open()) + { + printf("Fatal error: Invalid LiquidType.dbc file format!\n"); + exit(1); + } + size_t LiqType_count = dbc.getRecordCount(); size_t LiqType_maxid = dbc.getMaxId(); LiqType = new uint16[LiqType_maxid + 1]; diff --git a/contrib/extractor/ad.exe b/contrib/extractor/ad.exe index 8300b697cef7de057e2967b637a9ed0e0c1156e0..208eb2da03065891ec5012d36de6dc24c8c1b530 100755 GIT binary patch delta 36611 zcmb@v4O~=37eBspcNbP&+*KD`6lB#^QAp7R1;GRa)B;^V7fl5-r47x{c8z*a&;@0^ zu3=+sFIJk?)6-*RX@b2Nh=P`xy&0yJ+1oX==+P9@-2eC71;t+ezyI&^`QzvAoqOiY znKS3ioH=u5?zOzFOL=+M>Lk{>VcdinYu^!HK63K=YaLh9w&H8ecy8KOcr6|GGku=9 z_JN%L-L;o+fB)#4*AB}0cV0U$=Zo#nj%y#{Ip?0c>_lrrf8&Nzn%woT*G^Wn|D94O zSvS^2p*YPHiYNU*WgyaeN(;D>{b?lC1j1j(U9mY(p-?Flx9<~pA{*2_wop(+5<+#L zVi)5pg|Q);X#x@G^d~50vkm?G^c?P3P~reQ@tgL_PV=8wzwTWZ6D}$%#_b0lB1Cj4 z#uJgX@mui(+A>=!b`}b2S;m=#i3-Kx8-HTGm0XO@U( zs$!tZGpU$M>VX6c3Md>_a-&VzHZ&+zVcBo>q?xtzw^Ci=uWpA~(-a`F)SXWUJi(|~ zyk_CB7yrK%y8!eLG|9aj+2S;_Ay=Gj)=syH4zp48aZ{J5P}eU^dB)w{)u^iUdD0@4 z4>aV@nPsUfXyEg^M9-|EKqKjY7lRIS@xXO+I(1+J!n0tBMGWZAXK455gh z*Pm9q>Y4KBTBiIQvaYCeXPS+k(ost1A*#CaL@g0nc6&=#&o(o)jGyZ=qK~VEDKERT z6s`lR$`hWnc;y521^II*!LPVcc zS_h4bX*DWWBSTv&>zrrvq!PIos0u7~`8W03!-sitx6S>AQE!CI46Zb@UIkIDysW_Z zfs_oobxZlxZUeYU+gJGY^_}CiAx!6cQ|_{rb?()X!4THGpur*Y_Mq1F^e8^2LfO3R z9O-Zke=Ql?GX$PWb-O^yHw@i8qBbKI+=ks$>UWIZJ@L@E!tSL>0f zt2hR2RMzP#j!=JFZANyUSP}+$c}0qB>Gd7Fw7W6HR@+hbM&)(8`AgjgDqT&CAL(uk z1rs)D{1u-M)J3_*#HQ)@4}M*EL^qx%>-q*grUZ@I=Ge*;x{9^ju8SE~`LR3A9O+O) zD3MHD6A6AUC2JKvVrwoQTad(M&$ez?2k_f)m8q+f7V;|x*DKRpFqP5 zx{62nlpe+fWp6;!mDCjU0<&ws-d|;|HAgy)Zli1z-yl6*M@h3Ba_!e9HllaL+%Jf& z37O_d8guSxW)om~Tw%J^K`7GFrF}SIK-cvc7xD$^aJJcio))9rXSFHcN6X*iy?Vy7 z1AJ1?$cS|Y;!jV#k)bEzifswCk!48AmCAPWhkN!lx$2l}A4`Nz(1y(!(&$&T?f7ELri|4=fn#v@eZiqA`e%Z8|u;_1@Abu&Xr*4Yon{%O`mAkmd z5XoG8w;>`B*4HL2jpHW`#_WGnyOJ8jhhxxzbF)3u%rQBV8`^*|jkRmhIjz!0i>zm5 z5t;pIc0GXE(gMPnW`-`TNQuqBpKF!UYIu5Zq*?CMU&In^1I9?@IWT1{5@hOjf9~6S zL$EPWMtmlg?+EVgPnXB?Bf-5BW%#@f0?r4iFwIMLyPPxWdQJi5WSULc_EI@#cq})C zgiVms-L7K|5Z6%qiVQ_e-5p}F+BeG>XV5a4MMv*h1+~zXFCW^9w;Yy+zrf2vLIY&1 zSNSs`A%6C_g})V&kgN%(avJD5Ojo%bjVn^;N$0~lfLdLpmw*9z(pT4kdR^rz0tV(u zhj?snQ;bY|r_7@sCUP{<*yu-3NHd!pNq(lqs%hXjTe^o=^d21iJk^oZFpCUkJF7o$ zp=$KAp_z`2DGPAUDFc?=s1A1}+BGF%y(G-QWXAmlFQ|T(@zJ}>HDNk2PW}*CQ zny&H+P|8cq-BWdyt^TBLg0Av=BtZ-FTsF~?oS;D(l<6EsrWM^JEJvEt0WYHpcF7qS zEmkSLqtZ<>jFc}Ex}^hN0XXI!BLEiU4?|C4MzmF$_Z;a`l8_W3hXi7!<)s?o?Aeqa~h(8m~=hg`qT#m4-7st%Wttd9oO zW;BIozFDEG*|&CG{H_t`PnR{G3OU7N z`*6uyh;it&5V{S*#!dHvNYjjkqL@yQSMl8T7%@_za3e*Sg8 zsKCSwQ=Vr<81E4gmWw$j!{iLCrD6pQO>no-9Re+f)^3l99e@VcF?XPtVJzq}#UQ>P zb?}qLhNuQtoyMJEwA8h;n`;wW-=gvr`G!1Q#VTGNF}mLf-R^b6RU_df9CD0#mvTS( zQ9KUUao`Gr6v{u27}e(oSR68s51|(&WT>3sy4@=bo*5eH1K!7!*kwa|_8^{bGIl9$ ze^T)>Q)rhd?N6uq7E^fdNcpKY0G@)bvNx!SO$GVz22YsAs1q<-{=i@d9-dwVKvT@UZ zgr4#&Xv?$5LOw-`Tq$f5UpioTU)TWm1k(du3i4~gs$y1yZnrCrl+dQ)wF6B2#DH)$ zoSzAL{>OmuvZbkt^UsS{q@Unrh(QWGy2T4I;5%4_w8uqhw^bzuX($VmZLpT$Z^cGo zR?V`%tWU70ue%M>F!%$iE5`JLdoq}x}k2H@Lg17N|%maiWTe-(P!qgg*tg!FE z4?G6)9Ac#PkQZ!Lw9VaHGC#pjnuiOI6mjjK;ljKko-`;$P^R*-LA{6A?j=EM6Pug^ zVFNTp7?3V3Cuz~o+ypd`EMx<^xbszX+kz&wy80g|rSb@re zkU+FUEf3&J9}TP*gU%wa@;!$VD+WK{!k++TL0A6-2~sV)sf?qyJ&b0)3Dv}i%D+w` zK3vy?(jIV8H_Ht+Adh@cOWj@x6kC*@$qH~9T{-2dV*(}_9(SO*)j!I34>X$C-& zpBlouSDu&-EoiZZdQc^{@|BUr>dF&hx`JPf#B%(i*vylMjvrBZ(d|@}?Xzp(J$h;u zq4yO*Kc8<@C{}(;rt_W?0@PqR2R>Fd#4qEo3=J)+I3d=|0H&^D128HtmW7CG?0EKQ zlhHbl<3o+x|LmPj^n@Hsop?mL4+h2pL#cOX7|0h9CApvY($~aSWk$~F z)}KoUo;U|V!O^47pf}Ht?1FB zu<5)cY6=_7o1*Ia4iGEb1?h2opn)(G|L2w=;t{?%`ezd+iOP$*ij$~0cY2=ab7g3m zm=CVR46S%=MR&gA7K45Z@in6IoMS+dFHidYGXM0J5#~deWrGmrju!*ODJrzH@&v*? zO##%3rVMBwYlk7jZ!L4Bs+hP;k7_ETA?JcQv#zhIU1trhQnQ&xwaKkAI|D3r@O&F` zsh`2=6F-y2lG!Q6kZhIigFUny0-25VZe6>u4oH)M;MtfQPLT_(H*qQr7?Vfk?RzK% zsW3M@C8J}oI7#KY9Jnl~{$5p}D_wJ0oS|tM@X5U@(W)9cU4y4Ha1#{bnz>LmR*^Fy zfHJ{y!g7%ei8#wJUFwN?!9xwNj&l<^^;Fd4+OWawldE;xdk5W!w(GeMCT~a zDbK-tnM9v>pUOSdy+kE0)S!DQVaSyGfWPcVNGMvIrCE7}fsk{l_!)n1L~-WIE7YMK zqfouR$_RD47MWui1fh5IbB)LNx)WnYtaz6CcAjMRx9LnK0f7?*Ll0Yo@o#_=!B@u& zQ6)IAta~{of&UaUG*kBs*$Iu`!GIl&kzK;}XDqt07_-O1uGvpL2IIEjNy0YN(gTXP z&c@_U$Lu--3`&C@;{_u_y8MV4y~rd5JjPdyyhSK|p1(YDgiw5(e>L(>;RNR?qk0Kx zk8sjKTw7@XtrxGI)jvWv!XQyC$NsbL71?WC9qMS)D>!TN7hQ!VF|M_j%D-I}kV51;v+q?BY}YW!l*G>ECj z>q!@l?T)9!U+?b{b!2k=8C8mSrXXKDKw{H0SbUZf$jT7wqZ(axx+h$xb;^D9SS`5P zgi^gHrB%5?rOY?D8cm6JZH=>q54_w9@AGCQ^8*tQ#Aa27uBWJ zgA1EI2K7tUhtVTiX+*>PA+3OX5{Jw z^T-F}0EHHlr|`g=7&uz1v<*YUCY6Fm^n#9tYET~<>RQF`Naz!O_p0kWKnTRkb^bF~ z@eK(PQTz$8k&FRklX`6jdk(WzY{TNF(&q@tvq?c;z$3<3Hb`&0#7`s)i@(##|*mtapLr(?~3__(pr!ma=23&)z-)4Y1@ zeBr%S{NmV1Ve=|(N?c<6h6a{jHV(&ixjes$|0i*Vutem_q#?rpKI73z!@Aj5%C3V= zDp<+yOj;luF5h`DsSgu=zrep6mm>6D%ZJ>$K*(Rt*WWsP`r~k_g7o;cDG%m}t%>!^ zx=Kr5gwC{-Gwy;HK5Z#NVz9X_fgQoHU@G8=6%relsiibvLmHYy8QGzhEHCmN<1Y}CJbtz=`B$IMW}gpHz{4E!0PmI@ zRu(xWSz)smlX$KzlXZwu*f0xgRGWPpL8U)KKPBkLe}*blfWG}_Xgon*_%n17L91nG z5$w(N>InSMpOHT$==?uJ4QfEA{27`_(D*+?s|Y$^8P}&6#*&~hb4f9ntUGG{CM#L- zKCU-#J&VhY>wa8wa81ND5?9|Wo}bcJIP^UKSBhEK`aIu~vOt)%j%!kfg!YHk{hOtK z`8qx+byDw-kc+{Vc;$ib#SDExVgvb|Z?EP5PF*_muH*0u^5o}v;sXD?*&-EIQNQp^(KZFtqWwiaxMfW# zMjghxmE41>6q>2cR_P(GOuK~ycT;3Sj!{uT*9tR5Ju>uGDab9i#8TIkVJ13QsEbFc zGW608)O9_K^#8S_P{1O*7>viov&t}PrT=V}$5Lh8Rs$X#S-G~gM)9C$38T=*+8$VLRebEc z6m=xqGl^wer8i}CZTXei&On!%iZC&lZh1LU{!OHuHTkm&Fip0{I^AHbE@SKh`&fho%53x^*gYk=mVCI zJtb@{`O6iDz+e-s=%niMq)`JMeZ@w^8IUXbI^`!GE&Zltu;(@(;wllP;qXo=RKO!A zhZ*FiUZ=FLBn*o7it-a9>qa3cmO9u4vnx$jpe-m?StY@Z3WlsWUfIt3`NNQz?}F}F-?YgR3WRd)?`Az9{rfV z>C10V7QX)%fA{vjWuJfm&47@=(@>3PmpK|`5Szm!K?A}-T(+n%Rhm5&avnrdeM2*l zNq}zeIyomBrDK3Dr99UmnLhq?gzma*I&z$6*9KJ7>B=f-QJ6GPSMfXKpEOigLE9Pd z^-WAy3IA3hO9`5Yv400aSf%sNcEB>tNw#e1E{M;MGtE3HN8D$>Afug>x7H$EZRDF9 zow*Qrv|SNEdl)ImLa;eDM+)~U!WE*|dsdnQy2v-mER>EmKUaoNK4{iP=&rYanAH1t1#L2`e$wTZZ@(ik5zf zmzUovroDksZ3z&!#+Gy2)UiVcf#%g&$%?mdoy0W(&kCke2`c(i9zG63d2-wiZ7Sb0 zH9W3Xo2ocI+pHpJXEPxmKd8E47+0RHh8}5YLZhymwU2OV7awAcU;%uhH6pOO3tIVE zA-~sZj0$|i=Nnab=ANFUQ`C*+j*-mVyNG$&Y2gJx{DKUH^vb<_hqX7n#e>$^E`<{n z4~!9mW54I>>>-KUiJq>Ins2D}As|xd4sbQ;U5x^wP0mMGUNiQY08NS?>ee~o+UjcJ zjK&FyQ77Is8u{JXLs%dFaQ3t88$KeZFyxywg>w_dc1Wqp&#-U5a$iy*|8LG6tdIxf z#+3oVwJ+^>*c&lOd15ukQ{Qe@$qyYc2V=)m>;3{1j;HSb3s8AH_26HCs^h7L{{mDW zPdy4?5>Usm{0c2&^^#3FQ={xz)HeJ-W=?dL?3p5-b9FN}bk9-|hCn4SZ(buOg?oZKG zMxjgXi7(`lc@Y{AD*b9t%r|^$UIhD=-G10&cGP{87Q=5{RvIg@~@j9{OMVtfoEx$RL%(^Wcr1UVk(Ks4V{O4=v)jrU9M$rng zBSYS{yTYu&lYe%}yDPjuCV8vXURw_D9kD3Jos8DllY-%!d{x9Bz01TV^4)ih zoYX33et$QyrWIB1w4yL1s?F}8fL#^)1t8@}bwC0^Y}A^5qJ@7LoZm5il4(VJ#C#JR zc-=fUBfNY;=%n#C7LO)CFpL9e@{lk)mXK0%P|e%p*ruaFvcf^o#0^^FzgasY&-K@`f(mZr*z zpko3_a6cmvt1vf`3o5<#n$HLC$zYGC+AdlBwJ|AwJz6}z(3q|EgDe-fMxzT?o>*qH z_-s&DJh|Fw(vcl-%rqiaJCyBC>zz!QG5*Zg{F&G@oU9U4W0cr}ivEVbTo@WSpK6MZ{@1#d%H?F`21UyM9lvOm8^WFT_wp>c~h3ZawZL@ zs9}dn%Fe!w_W!*~4rSh~l6Vr^CiKyNP{~Rn^(U3wOE6g_RQkF~a_tUc%917Pz)pJm zTOGU%gV1S2KnEBO=WfV;<=IKv&ZaO8Pwh(tzk#VR&jzU7##Cc+lwL)vpatnXZTz=k zFofx(5=5t^Uhw`b=W652`Mjb5Wn}lMPbr#xzM=s8HWa02_jdCl5R~XxGIW$=l?p(| zzMUv1$domfy2L+pt8d4YMg{=>d@;+jc??5y>~+8*gCyyIxrOqS2dq}lI&-lK(~5-L zY-#meV$U=hm6@dPo%ecjmgf>r>9@&RhKhQVb?!?BB3?@D4hhIXY&lwOIiWo2-eiW80T*go;y#4AO%HWo zbcDH$&{$YUkXw$5dt#X!D}M>)cg7f0jYf9ec^_6?TFG-gfPv#C`VetH{CZ> z8212gy6={LleYVOAVS*3QF~{Y^an!iXqnyUR6{d8i&Hh#AYqkaoqTq&DR3hmr28_s zt9WqP%uc9TNV}FJuG~dT*S7?Ufh|9J(q-dpmc$QyKAciCDV%*Fi)a`zIy7vyS(P6Z zA%yo!CG|qRO`47{IgAe4Wtt$3Mj;FUJNYfdoe~29A!Dl~%x=fxkxQcb)e=9CrxQry z^1D1VWHQagI3YfZFIf^}x;+FsSZ9_y|MeFo=8!w#fID$=GOu6K8~gfx_m=jXY~n82 zJMR767ClGc75oxTohGrkUQJq$&v?|DSMDPGi9;k zwB_sYAzb^7@F3GVu^$iJw_IPpG+{XWgG5l-|#)?vE7~+`;$WKO{722HNu1 zBaLhC;MeZISI01?f(3-JdWs)P7XFaKCU{f$$BsC*fNPxJ^ax!70c5DkONJ^O0r_XT zF5$mB3xxj^^I6M6h4saJ*|IwZjVh*X1l9Fp5hAln<7{|4rQKi^MN7l;_;1Um3IoUU zj0Xlq?Z1^yv*=d;7g`oq7?fB1ncI?;DPM&PeRsyZ^1k9O?1=CXuK;kvWSoB)0w7d!9RwG?(z^TI%PLq_2%o{s- ziI!$F^~Dd1D|fSa~s{%(gSD@X1@op*S!zat*WKl2ORhR*9ge=PCFRPxU|Q7TyN zi~Q_E;cP4K`mf1@|Brh>J?$qE$iyDd!rDgJZTs^c5ajlEdqCj56Nhm1Vb6cP!J+GH z`x#mc-UC)o`UU^w=3dZ>PWCPL{VPq_^DIv<9UQc*eaUhnH&^GMOmQR{|@I1P001TpGtu3<38d;SeDJpD0 zlCB}AsvuIf>{>Akv5yV#V_=b*(&hcargRfTqnO^9u2)FQZs+%|%|(XqdnZ?aY8>!qW-=c)wZwI_Jis!+qq&eG^O75&hvsm#LPTV)!&?;@;HV_4!P z=dTvhUnY4{Sr3;c0c zzqDnLXJ@t)lOdSp678&JeVQ$;n<&c(!S9<{%{puOKspl#7QrR#i8sCfW}ut&jGV8^hY9D`R-1)Be{l1f5d$v6OL6TF^V@ZdOsTWzv=nUNpRJAQ z)_2@qON>YCzdq2tdr*p=?S# zsB`_B)*K&w^wV3DA2D}{`Xcf8{o1DV9n?;sw5XNuxwCd89=xAw5)aagX0s8366a{6 z^0i`nr7g-&sM0SGxNM0~ej!eO5yEz-Z*r$!&GD$dBwFsQZBY##?aI7t@kp6_&UR@G zR!=yF*qHvJ0{A)N^zFE`9=!7@W^K#Pu{Nb|0%Le-^9t~$Z^Q1q@@q)Nqm{`;z3Zq8$&7-aM82*qSKX*?t;L$w=M^v?Eyd=gsn_O3z z=-e(Y-?kz|%-ZZR{3fFw!5|+cG>VBOray?o<<`IwKVHCtmP8uNR zNe{?esAyA9IywPN%+dNA(=Kzrq7$2Rt{T)NX1$p0$vP?}J%UE0Q`SYf0qrPW}Gp%*RFld7_gW=Ea3 z<#f;ry~MA$`wrbKX6u!8_;-}_NpHIh!&xPn|0`&VnEs;GleJ5#+`z}LH5Y7`J|O*O zZ3k|4UJj1?N@oG^r0*hKDw}ih4kwvAC?19SR}=0{mQFSwkBU?ctz8)*6I|*xa9t;W{QPRsNXx99| zKNp8`{kp<38*Br(a5aRv3-s;B?BI?hwxH-{__Q#vVc59MrB{N(tne0}hcUQ;*J;*< zVVKc*JV#?Z%g#1Vdfc==MWow5f5VD}SjEeBQ;B*8w5%Na@MMCQrUk=Xwcau6ixd8IIPYnX%3wR2C1qCvc8fJYMm!&iy

0yK1$QvkPoOy&29Uz|zClYC+` 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

YJjQ-SDw{iQE>-@+O&RKWp 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 delta 36078 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 Date: Thu, 12 Mar 2009 11:45:03 +0300 Subject: [PATCH 04/46] [7444] Fixed some recently added and old type conversion warnings. --- src/game/GameObject.cpp | 4 ++-- src/game/Map.cpp | 22 ++++++++++++---------- src/shared/revision_nr.h | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index 11ea2b8da..9d206a617 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -125,8 +125,8 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa int64 rotation = 0; - float f_rot1 = sin(ang / 2.0f); - int64 i_rot1 = f_rot1 / atan(pow(2.0f, -20.0f)); + double f_rot1 = sin(ang / 2.0f); + int64 i_rot1 = int64(f_rot1 / atan(pow(2.0f, -20.0f))); rotation |= (i_rot1 << 43 >> 43) & 0x00000000001FFFFF; //float f_rot2 = sin(0.0f / 2.0f); diff --git a/src/game/Map.cpp b/src/game/Map.cpp index f78871d8b..f7d5ab2d6 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -65,7 +65,8 @@ bool Map::ExistMap(uint32 mapid,int x,int y) map_fileheader header; fread(&header, sizeof(header), 1, pf); - if (header.mapMagic != MAP_MAGIC || header.versionMagic != MAP_VERSION_MAGIC) + if (header.mapMagic != uint32(MAP_MAGIC) || + header.versionMagic != uint32(MAP_VERSION_MAGIC)) { sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp); delete [] tmp; @@ -1081,7 +1082,8 @@ bool GridMap::loadData(char *filename) if (!in) return true; fread(&header, sizeof(header),1,in); - if (header.mapMagic == MAP_MAGIC && header.versionMagic == MAP_VERSION_MAGIC) + if (header.mapMagic == uint32(MAP_MAGIC) && + header.versionMagic == uint32(MAP_VERSION_MAGIC)) { // loadup area data if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize)) @@ -1132,11 +1134,11 @@ bool GridMap::loadAreaData(FILE *in, uint32 offset, uint32 size) map_areaHeader header; fseek(in, offset, SEEK_SET); fread(&header, sizeof(header), 1, in); - if (header.fourcc != MAP_AREA_MAGIC) + if (header.fourcc != uint32(MAP_AREA_MAGIC)) return false; m_gridArea = header.gridArea; - if (!(header.flags&MAP_AREA_NO_AREA)) + if (!(header.flags & MAP_AREA_NO_AREA)) { m_area_map = new uint16 [16*16]; fread(m_area_map, sizeof(uint16), 16*16, in); @@ -1149,13 +1151,13 @@ bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size) map_heightHeader header; fseek(in, offset, SEEK_SET); fread(&header, sizeof(header), 1, in); - if (header.fourcc != MAP_HEIGTH_MAGIC) + if (header.fourcc != uint32(MAP_HEIGTH_MAGIC)) return false; m_gridHeight = header.gridHeight; - if (!(header.flags&MAP_HEIGHT_NO_HIGHT)) + if (!(header.flags & MAP_HEIGHT_NO_HIGHT)) { - if ((header.flags&MAP_HEIGHT_AS_INT16)) + if ((header.flags & MAP_HEIGHT_AS_INT16)) { m_uint16_V9 = new uint16 [129*129]; m_uint16_V8 = new uint16 [128*128]; @@ -1164,7 +1166,7 @@ bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size) m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535; m_gridGetHeight = &GridMap::getHeightFromUint16; } - else if ((header.flags&MAP_HEIGHT_AS_INT8)) + else if ((header.flags & MAP_HEIGHT_AS_INT8)) { m_uint8_V9 = new uint8 [129*129]; m_uint8_V8 = new uint8 [128*128]; @@ -1192,7 +1194,7 @@ bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 size) map_liquidHeader header; fseek(in, offset, SEEK_SET); fread(&header, sizeof(header), 1, in); - if (header.fourcc != MAP_LIQUID_MAGIC) + if (header.fourcc != uint32(MAP_LIQUID_MAGIC)) return false; m_liquidType = header.liquidType; @@ -1529,7 +1531,7 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R } // For speed check as int values - int delta = (liquid_level - z) * 10; + int delta = int((liquid_level - z) * 10); // Get position delta if (delta > 20) // Under water diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 87878c0c4..2e7ea2dff 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7443" + #define REVISION_NR "7444" #endif // __REVISION_NR_H__ From b71759d2046a77b28027a77fe19240fa84ba7283 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Thu, 12 Mar 2009 13:50:52 +0300 Subject: [PATCH 05/46] [7445] Implement SPELL_EFFECT_JUMP2 used in some jump to target (unit/go/coordinates) spells. --- src/game/Spell.h | 1 + src/game/SpellEffects.cpp | 49 ++++++++++++++++++++++++++++++++++++++- src/shared/revision_nr.h | 2 +- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/game/Spell.h b/src/game/Spell.h index 2b70422ac..6b33e636f 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -249,6 +249,7 @@ class Spell void EffectSummonWild(uint32 i); void EffectSummonGuardian(uint32 i); void EffectHealMechanical(uint32 i); + void EffectJump(uint32 i); void EffectTeleUnitsFaceCaster(uint32 i); void EffectLearnSkill(uint32 i); void EffectAddHonor(uint32 i); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 7c78f05ba..5d3c54473 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -99,7 +99,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD &Spell::EffectUnused, // 41 SPELL_EFFECT_JUMP - &Spell::EffectUnused, // 42 SPELL_EFFECT_JUMP2 + &Spell::EffectJump, // 42 SPELL_EFFECT_JUMP2 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related @@ -1997,6 +1997,53 @@ void Spell::EffectTriggerMissileSpell(uint32 effect_idx) m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, 0, m_originalCasterGUID); } +void Spell::EffectJump(uint32 i) +{ + if(m_caster->isInFlight()) + return; + + // Init dest coordinates + float x,y,z,o; + if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + x = m_targets.m_destX; + y = m_targets.m_destY; + z = m_targets.m_destZ; + o = m_caster->GetOrientation(); + } + else if(unitTarget) + { + x = unitTarget->GetPositionX(); + y = unitTarget->GetPositionY(); + z = unitTarget->GetPositionZ(); + o = m_spellInfo->EffectImplicitTargetA[i] == TARGET_BEHIND_VICTIM + ? unitTarget->GetOrientation() + : m_caster->GetOrientation(); + } + else if(gameObjTarget) + { + x = gameObjTarget->GetPositionX(); + y = gameObjTarget->GetPositionY(); + z = gameObjTarget->GetPositionZ(); + o = m_caster->GetOrientation(); + } + else + return; + + + // Teleport + if(m_caster->GetTypeId() == TYPEID_PLAYER) + ((Player*)m_caster)->TeleportTo(m_caster->GetMapId(), x, y, z, o, + TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); + else + { + m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, x, y, z, o); + WorldPacket data; + m_caster->BuildTeleportAckMsg(&data, x, y, z, o); + m_caster->SendMessageToSet(&data, false); + } +} + void Spell::EffectTeleportUnits(uint32 i) { if(!unitTarget || unitTarget->isInFlight()) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 2e7ea2dff..cdb1df0c9 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7444" + #define REVISION_NR "7445" #endif // __REVISION_NR_H__ From 424c8b39dfca53f30dced4ae78659ffd8030fee4 Mon Sep 17 00:00:00 2001 From: Triply Date: Thu, 12 Mar 2009 13:33:46 +0100 Subject: [PATCH 06/46] [7446] Applied mangos coding style for AB and EY. Signed-off-by: Triply --- src/game/BattleGroundAB.cpp | 30 +++++++++++----------- src/game/BattleGroundAB.h | 50 ++++++++++++++++++------------------ src/game/BattleGroundEY.cpp | 15 +++++++++-- src/game/BattleGroundEY.h | 51 ++++++++++++++++++++----------------- src/shared/revision_nr.h | 2 +- 5 files changed, 82 insertions(+), 66 deletions(-) diff --git a/src/game/BattleGroundAB.cpp b/src/game/BattleGroundAB.cpp index dae2b20de..9922c56ea 100644 --- a/src/game/BattleGroundAB.cpp +++ b/src/game/BattleGroundAB.cpp @@ -48,7 +48,7 @@ void BattleGroundAB::Update(uint32 diff) if( GetStatus() == STATUS_IN_PROGRESS ) { - int team_points[2] = { 0, 0 }; + int team_points[BG_TEAMS_COUNT] = { 0, 0 }; for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) { @@ -88,24 +88,24 @@ void BattleGroundAB::Update(uint32 diff) { // FIXME: team and node names not localized SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node)); - PlaySoundToAll(SOUND_NODE_CAPTURED_ALLIANCE); + PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE); } else { // FIXME: team and node names not localized SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node)); - PlaySoundToAll(SOUND_NODE_CAPTURED_HORDE); + PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE); } } } - for (int team = 0; team < 2; ++team) + for (int team = 0; team < BG_TEAMS_COUNT; ++team) if( m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED ) ++team_points[team]; } // Accumulate points - for (int team = 0; team < 2; ++team) + for (int team = 0; team < BG_TEAMS_COUNT; ++team) { int points = team_points[team]; if( !points ) @@ -127,18 +127,18 @@ void BattleGroundAB::Update(uint32 diff) RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE); m_HonorScoreTics[team] -= m_HonorTics; } - if( !m_IsInformedNearVictory && m_TeamScores[team] > 1800 ) + if( !m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE ) { if( team == BG_TEAM_ALLIANCE ) SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); else SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); - PlaySoundToAll(SOUND_NEAR_VICTORY); + PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY); m_IsInformedNearVictory = true; } - if( m_TeamScores[team] > 2000 ) - m_TeamScores[team] = 2000; + if( m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE ) + m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE; if( team == BG_TEAM_ALLIANCE ) UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]); if( team == BG_TEAM_HORDE ) @@ -147,9 +147,9 @@ void BattleGroundAB::Update(uint32 diff) } // Test win condition - if( m_TeamScores[BG_TEAM_ALLIANCE] >= 2000 ) + if( m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE ) EndBattleGround(ALLIANCE); - if( m_TeamScores[BG_TEAM_HORDE] >= 2000 ) + if( m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE ) EndBattleGround(HORDE); } } @@ -313,7 +313,7 @@ void BattleGroundAB::FillInitialWorldStates(WorldPacket& data) // Team scores data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE); - data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_SCORE); + data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE); data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]); data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]); @@ -440,7 +440,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ else SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE); - sound = SOUND_NODE_CLAIMED; + sound = BG_AB_SOUND_NODE_CLAIMED; } // If node is contested else if( (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED) ) @@ -484,7 +484,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ else SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); } - sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE; + sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; } // If node is occupied, change to enemy-contested else @@ -506,7 +506,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ else SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); - sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE; + sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; } // If node is occupied again, send "X has taken the Y" msg. diff --git a/src/game/BattleGroundAB.h b/src/game/BattleGroundAB.h index 644556d0e..e9a255d10 100644 --- a/src/game/BattleGroundAB.h +++ b/src/game/BattleGroundAB.h @@ -75,17 +75,17 @@ enum BG_AB_NodeObjectId enum BG_AB_ObjectType { // for all 5 node points 8*5=40 objects - BG_AB_OBJECT_BANNER_NEUTRAL = 0, - BG_AB_OBJECT_BANNER_CONT_A = 1, - BG_AB_OBJECT_BANNER_CONT_H = 2, - BG_AB_OBJECT_BANNER_ALLY = 3, - BG_AB_OBJECT_BANNER_HORDE = 4, - BG_AB_OBJECT_AURA_ALLY = 5, - BG_AB_OBJECT_AURA_HORDE = 6, - BG_AB_OBJECT_AURA_CONTESTED = 7, + BG_AB_OBJECT_BANNER_NEUTRAL = 0, + BG_AB_OBJECT_BANNER_CONT_A = 1, + BG_AB_OBJECT_BANNER_CONT_H = 2, + BG_AB_OBJECT_BANNER_ALLY = 3, + BG_AB_OBJECT_BANNER_HORDE = 4, + BG_AB_OBJECT_AURA_ALLY = 5, + BG_AB_OBJECT_AURA_HORDE = 6, + BG_AB_OBJECT_AURA_CONTESTED = 7, //gates - BG_AB_OBJECT_GATE_A = 40, - BG_AB_OBJECT_GATE_H = 41, + BG_AB_OBJECT_GATE_A = 40, + BG_AB_OBJECT_GATE_H = 41, //buffs BG_AB_OBJECT_SPEEDBUFF_STABLES = 42, BG_AB_OBJECT_REGENBUFF_STABLES = 43, @@ -128,8 +128,8 @@ enum BG_AB_Timers enum BG_AB_Score { - BG_AB_MAX_TEAM_SCORE = 2000, - BG_AB_WARNING_SCORE = 1800 + BG_AB_WARNING_NEAR_VICTORY_SCORE = 1800, + BG_AB_MAX_TEAM_SCORE = 2000 }; /* do NOT change the order, else wrong behaviour */ @@ -162,18 +162,18 @@ enum BG_AB_NodeStatus enum BG_AB_Sounds { - SOUND_NODE_CLAIMED = 8192, - SOUND_NODE_CAPTURED_ALLIANCE = 8173, - SOUND_NODE_CAPTURED_HORDE = 8213, - SOUND_NODE_ASSAULTED_ALLIANCE = 8174, - SOUND_NODE_ASSAULTED_HORDE = 8212, - SOUND_NEAR_VICTORY = 8456 + BG_AB_SOUND_NODE_CLAIMED = 8192, + BG_AB_SOUND_NODE_CAPTURED_ALLIANCE = 8173, + BG_AB_SOUND_NODE_CAPTURED_HORDE = 8213, + BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE = 8174, + BG_AB_SOUND_NODE_ASSAULTED_HORDE = 8212, + BG_AB_SOUND_NEAR_VICTORY = 8456 }; -#define BG_AB_NotABBGWeekendHonorTicks 330 -#define BG_AB_ABBGWeekendHonorTicks 200 +#define BG_AB_NotABBGWeekendHonorTicks 330 +#define BG_AB_ABBGWeekendHonorTicks 200 #define BG_AB_NotABBGWeekendReputationTicks 200 -#define BG_AB_ABBGWeekendReputationTicks 150 +#define BG_AB_ABBGWeekendReputationTicks 150 // x, y, z, o const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] = { @@ -283,10 +283,10 @@ class BattleGroundAB : public BattleGround uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT]; BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT]; int32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT]; - uint32 m_TeamScores[2]; - uint32 m_lastTick[2]; - uint32 m_HonorScoreTics[2]; - uint32 m_ReputationScoreTics[2]; + uint32 m_TeamScores[BG_TEAMS_COUNT]; + uint32 m_lastTick[BG_TEAMS_COUNT]; + uint32 m_HonorScoreTics[BG_TEAMS_COUNT]; + uint32 m_ReputationScoreTics[BG_TEAMS_COUNT]; bool m_IsInformedNearVictory; uint32 m_HonorTics; uint32 m_ReputationTics; diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp index 4ba6953fb..ca3deb465 100644 --- a/src/game/BattleGroundEY.cpp +++ b/src/game/BattleGroundEY.cpp @@ -258,9 +258,20 @@ void BattleGroundEY::UpdatePointStatuses() void BattleGroundEY::UpdateTeamScore(uint32 Team) { uint32 score = GetTeamScore(Team); - if(score >= EY_MAX_TEAM_SCORE) + //TODO there should be some sound played when one team is near victory!! - and define variables + /*if( !m_IsInformedNearVictory && score >= BG_EY_WARNING_NEAR_VICTORY_SCORE ) { - score = EY_MAX_TEAM_SCORE; + if( Team == ALLIANCE ) + SendMessageToAll(LANG_BG_EY_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); + else + SendMessageToAll(LANG_BG_EY_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); + PlaySoundToAll(BG_EY_SOUND_NEAR_VICTORY); + m_IsInformedNearVictory = true; + }*/ + + if( score >= BG_EY_MAX_TEAM_SCORE ) + { + score = BG_EY_MAX_TEAM_SCORE; EndBattleGround(Team); } diff --git a/src/game/BattleGroundEY.h b/src/game/BattleGroundEY.h index 17b678e8f..ab44fac4f 100644 --- a/src/game/BattleGroundEY.h +++ b/src/game/BattleGroundEY.h @@ -23,9 +23,8 @@ class BattleGround; -#define EY_MAX_TEAM_SCORE 2000 -#define BG_EY_FLAG_RESPAWN_TIME (10*IN_MILISECONDS) //10 seconds -#define BG_EY_FPOINTS_TICK_TIME (2*IN_MILISECONDS) //2 seconds +#define BG_EY_FLAG_RESPAWN_TIME (10*IN_MILISECONDS) //10 seconds +#define BG_EY_FPOINTS_TICK_TIME (2*IN_MILISECONDS) //2 seconds enum BG_EY_WorldStates { @@ -71,11 +70,11 @@ enum BG_EY_ProgressBarConsts enum BG_EY_Sounds { //strange ids, but sure about them - BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212, - BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213, - BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174, - BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173, - BG_EY_SOUND_FLAG_RESET = 8192 + BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212, + BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213, + BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174, + BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173, + BG_EY_SOUND_FLAG_RESET = 8192 }; enum BG_EY_Spells @@ -86,18 +85,18 @@ enum BG_EY_Spells enum EYBattleGroundObjectEntry { - BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door - BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door - BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic) - BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand) - BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop) - BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance) - BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde) - BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral) - BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt - BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt - BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt - BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt + BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door + BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door + BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic) + BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand) + BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop) + BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance) + BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde) + BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral) + BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt + BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt + BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt + BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt }; enum EYBattleGroundPointsTrigger @@ -129,7 +128,7 @@ enum EYBattleGroundPoints DRAENEI_RUINS = 2, MAGE_TOWER = 3, - EY_PLAYERS_OUT_OF_POINTS = 4, + EY_PLAYERS_OUT_OF_POINTS = 4, EY_POINTS_MAX = 4 }; @@ -210,8 +209,14 @@ enum EYBattleGroundObjectTypes BG_EY_OBJECT_MAX = 59 }; -#define BG_EY_NotEYWeekendHonorTicks 330 -#define BG_EY_EYWeekendHonorTicks 200 +#define BG_EY_NotEYWeekendHonorTicks 330 +#define BG_EY_EYWeekendHonorTicks 200 + +enum BG_EY_Score +{ + BG_EY_WARNING_NEAR_VICTORY_SCORE = 1800, + BG_EY_MAX_TEAM_SCORE = 2000 +}; enum BG_EY_FlagState { diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index cdb1df0c9..e8811f5da 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7445" + #define REVISION_NR "7446" #endif // __REVISION_NR_H__ From b94c78474bd63c09fd6bc3fdb8d9789963f7bbb0 Mon Sep 17 00:00:00 2001 From: Triply Date: Thu, 12 Mar 2009 15:27:01 +0100 Subject: [PATCH 07/46] [7447] Fixed - do not let player who has higher level than Battleground->GetMaxLevel to enter battleground. Signed-off-by: Triply --- src/game/BattleGroundHandler.cpp | 130 ++++++++++++++----------------- src/shared/revision_nr.h | 2 +- 2 files changed, 59 insertions(+), 73 deletions(-) diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index 6afc9a07c..4c457b38a 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -127,7 +127,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) if( !_player->CanJoinToBattleground() ) { WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4); - data << (uint32) 0xFFFFFFFE; + data << uint32(0xFFFFFFFE); _player->GetSession()->SendPacket(&data); return; } @@ -299,25 +299,25 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action; - if(!sBattlemasterListStore.LookupEntry(bgTypeId_)) + if( !sBattlemasterListStore.LookupEntry(bgTypeId_) ) { - sLog.outError("Battleground: invalid bgtype (%u) received.",bgTypeId_); + sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_); // update battleground slots for the player to fix his UI and sent data. // this is a HACK, I don't know why the client starts sending invalid packets in the first place. // it usually happens with extremely high latency (if debugging / stepping in the code for example) - if(_player->InBattleGroundQueue()) + if( _player->InBattleGroundQueue() ) { // update all queues, send invitation info if player is invited, queue info if queued for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) { BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); - if(!bgQueueTypeId) + if( !bgQueueTypeId ) continue; BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); // if the player is not in queue, continue or no group information - this should never happen - if(itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo) + if( itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo ) continue; BattleGround * bg = NULL; @@ -326,7 +326,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated; uint8 status = 0; - if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID) + if( !itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID ) { // not invited to bg, get template bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); @@ -339,12 +339,8 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) status = STATUS_WAIT_JOIN; } - // if bg not found, then continue - if(!bg) - continue; - - // don't invite if already in the instance - if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()) + // if bg not found, then continue, don't invite if already in the instance + if( !bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()) ) continue; // re - invite player with proper data @@ -356,22 +352,20 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) return; } + //get GroupQueueInfo from BattleGroundQueue BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); - - BattleGroundQueueTypeId bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; - // get the bg what we were invited to - bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type); + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - if(itrPlayerStatus == qpMap.end()) + if( itrPlayerStatus == qpMap.end() ) { sLog.outError("Battleground: itrplayerstatus not found."); return; } - instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID; - // if action == 1, then instanceId is _required_ - if(!instanceId && action == 1) + instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID; + // if action == 1, then instanceId is required + if( !instanceId && action == 1 ) { sLog.outError("Battleground: instance not found."); return; @@ -380,56 +374,49 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId); // bg template might and must be used in case of leaving queue, when instance is not created yet - if(!bg && action == 0) + if( !bg && action == 0 ) bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - - if(!bg) + if( !bg ) { - sLog.outError("Battleground: bg not found for type id %u.",bgTypeId); + sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId); return; } - bgTypeId = bg->GetTypeID(); - - if(_player->InBattleGroundQueue()) + if( _player->InBattleGroundQueue() ) { - uint32 queueSlot = 0; - uint32 team = 0; - uint32 arenatype = 0; - uint32 israted = 0; - uint32 rating = 0; - uint32 opponentsRating = 0; - // get the team info from the queue + //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function! + uint32 team = itrPlayerStatus->second.GroupInfo->Team; + uint32 arenaType = itrPlayerStatus->second.GroupInfo->ArenaType; + uint32 isRated = itrPlayerStatus->second.GroupInfo->IsRated; + uint32 rating = itrPlayerStatus->second.GroupInfo->ArenaTeamRating; + uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating; - BattleGroundQueue::QueuedPlayersMap& qpMap2 = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; - BattleGroundQueue::QueuedPlayersMap::iterator pitr = qpMap2.find(_player->GetGUID()); - if (pitr !=qpMap2.end() && pitr->second.GroupInfo) + //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it + if( action == 1 && arenaType == 0) { - team = pitr->second.GroupInfo->Team; - arenatype = pitr->second.GroupInfo->ArenaType; - israted = pitr->second.GroupInfo->IsRated; - rating = pitr->second.GroupInfo->ArenaTeamRating; - opponentsRating = pitr->second.GroupInfo->OpponentsTeamRating; - } - else - { - sLog.outError("Battleground: Invalid player queue info!"); - return; - } - //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue - if( arenatype == 0 && !_player->CanJoinToBattleground() ) - { - sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); + //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue + if( !_player->CanJoinToBattleground() ) + { + //send bg command result to show nice message + WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4); + data2 << uint32(0xFFFFFFFE); + _player->GetSession()->SendPacket(&data2); + sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); + } + //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue + if( _player->getLevel() > bg->GetMaxLevel() ) + sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); action = 0; } + uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); WorldPacket data; - switch(action) + switch( action ) { - case 1: // port to battleground - if(!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId)) - return; // cheating? + case 1: // port to battleground + if( !_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId) ) + return; // cheating? // resurrect the player - if(!_player->isAlive()) + if( !_player->isAlive() ) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); @@ -440,14 +427,15 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) _player->GetMotionMaster()->MovementExpired(); _player->m_taxi.ClearTaxiDestinations(); } + //TODO FIX ME this call must be removed! _player->RemoveFromGroup(); - queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff - // also this required to prevent stuck at old battleground after SetBattleGroundId set to new + // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new if( BattleGround *currentBg = _player->GetBattleGround() ) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); @@ -459,30 +447,28 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player,team); - sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId); + sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); break; case 0: // leave queue - queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); - /* - if player leaves rated arena match before match start, it is counted as he played but he lost - */ - if (israted) + // if player leaves rated arena match before match start, it is counted as he played but he lost + if( isRated ) { ArenaTeam * at = objmgr.GetArenaTeamById(team); - if (at) + if( at ) { sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating); at->MemberLost(_player, opponentsRating); at->SaveToDB(); } } - _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); + _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, arenaType); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true); - // player left queue, we should update it, maybe now his group fits in - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(bgTypeId),arenatype,israted,rating); + // player left queue, we should update it - do not update Arena Queue + if( !arenaType ) + sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenaType, isRated, rating); SendPacket(&data); - sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetTypeID(),bgQueueTypeId); + sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); break; default: sLog.outError("Battleground port: unknown action %u", action); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index e8811f5da..6a4325192 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7446" + #define REVISION_NR "7447" #endif // __REVISION_NR_H__ From e1f069e5b9ab90a967811dc9e3a1a0e266f9cebd Mon Sep 17 00:00:00 2001 From: Triply Date: Thu, 12 Mar 2009 16:28:14 +0100 Subject: [PATCH 08/46] [7448] Fixed infinite honor gains in EoS. Problem reported by LickedLurk. Thx. Fixed Entering battleground bugged in [7447] Signed-off-by: Triply --- src/game/BattleGroundEY.cpp | 2 +- src/game/BattleGroundHandler.cpp | 5 ++++- src/shared/revision_nr.h | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp index ca3deb465..aefaf57c8 100644 --- a/src/game/BattleGroundEY.cpp +++ b/src/game/BattleGroundEY.cpp @@ -520,7 +520,7 @@ void BattleGroundEY::Reset() m_PointAddingTimer = 0; m_TowerCapCheckTimer = 0; bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call! - uint32 m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks; + m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks; for(uint8 i = 0; i < EY_POINTS_MAX; ++i) { diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index 4c457b38a..dee75a983 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -401,12 +401,15 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4); data2 << uint32(0xFFFFFFFE); _player->GetSession()->SendPacket(&data2); + action = 0; sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue if( _player->getLevel() > bg->GetMaxLevel() ) + { sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); - action = 0; + action = 0; + } } uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); WorldPacket data; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 6a4325192..eed557192 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7447" + #define REVISION_NR "7448" #endif // __REVISION_NR_H__ From 571c56ff07150185153ceaf29385075b5c64f123 Mon Sep 17 00:00:00 2001 From: Triply Date: Fri, 13 Mar 2009 00:08:02 +0100 Subject: [PATCH 09/46] [7449] Fixed BG queue invitation status showed on client. Fixed BG starting timer and BG ending timer. TODO: make bg queue update player's status each minute. Signed-off-by: Triply --- src/game/BattleGround.cpp | 18 +++++--- src/game/BattleGround.h | 2 +- src/game/BattleGroundHandler.cpp | 77 +++++++++++++++++++------------- src/game/BattleGroundMgr.cpp | 27 ++++++----- src/game/BattleGroundMgr.h | 3 +- src/shared/revision_nr.h | 2 +- 6 files changed, 76 insertions(+), 53 deletions(-) diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 35ad7b262..a2c192ad7 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -428,9 +428,10 @@ void BattleGround::Update(uint32 diff) if(GetStatus() == STATUS_WAIT_LEAVE) { // remove all players from battleground after 2 minutes - m_EndTime += diff; - if(m_EndTime >= TIME_TO_AUTOREMOVE) // 2 minutes + m_EndTime -= diff; + if( m_EndTime <= 0) { + m_EndTime = 0; BattleGroundPlayerMap::iterator itr, next; for(itr = m_Players.begin(); itr != m_Players.end(); itr = next) { @@ -443,6 +444,8 @@ void BattleGround::Update(uint32 diff) } } + //update start time + m_StartTime += diff; } void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O) @@ -633,7 +636,8 @@ void BattleGround::EndBattleGround(uint32 winner) } SetStatus(STATUS_WAIT_LEAVE); - m_EndTime = 0; + //we must set it this way, because end time is sent in packet! + m_EndTime = TIME_TO_AUTOREMOVE; // arena rating calculation if(isArena() && isRated()) @@ -716,7 +720,7 @@ void BattleGround::EndBattleGround(uint32 winner) plr->GetSession()->SendPacket(&data); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType()); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType()); plr->GetSession()->SendPacket(&data); plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1); } @@ -964,7 +968,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac if(SendPacket) { WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0); plr->GetSession()->SendPacket(&data); } @@ -1589,7 +1593,7 @@ void BattleGround::EndNow() { RemoveFromBGFreeSlotQueue(); SetStatus(STATUS_WAIT_LEAVE); - SetEndTime(TIME_TO_AUTOREMOVE); + SetEndTime(0); // inform invited players about the removal sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this); } @@ -1699,7 +1703,7 @@ void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player* plr) sBattleGroundMgr.BuildPvpLogDataPacket(&data, this); plr->GetSession()->SendPacket(&data); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType()); plr->GetSession()->SendPacket(&data); } diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h index c55a89afc..01cbf2d23 100644 --- a/src/game/BattleGround.h +++ b/src/game/BattleGround.h @@ -530,7 +530,7 @@ class BattleGround BattleGroundStatus m_Status; uint32 m_ClientInstanceID; //the instance-id which is sent to the client and without any other internal use uint32 m_StartTime; - uint32 m_EndTime; + int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself uint32 m_LastResurrectTime; BGQueueIdBasedOnLevel m_QueueId; uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5 diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index dee75a983..fceb9c015 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -173,7 +173,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) WorldPacket data; // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); member->GetSession()->SendPacket(&data); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data); @@ -191,7 +191,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) WorldPacket data; // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); SendPacket(&data); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); @@ -433,7 +433,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) //TODO FIX ME this call must be removed! _player->RemoveFromGroup(); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false); @@ -465,7 +465,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) } } _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, arenaType); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if( !arenaType ) @@ -510,40 +510,55 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) sLog.outDebug( "WORLD: Battleground status" ); WorldPacket data; - uint32 queueSlot = PLAYER_MAX_BATTLEGROUND_QUEUES; - - if(_player->InBattleGround()) - { - BattleGround *bg = _player->GetBattleGround(); - if(!bg) - return; - BattleGroundQueueTypeId bgQueueTypeId_tmp = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); - queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId_tmp); - if((bg->GetStatus() <= STATUS_IN_PROGRESS)) - { - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); - SendPacket(&data); - } - } - // we should update all queues? .. i'm not sure if this code is correct - for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) + // we must update all queues here + BattleGround *bg = NULL; + for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) { BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); - if(!bgQueueTypeId || i == queueSlot) //queueslot check in case we already send it in the above code + if( !bgQueueTypeId ) continue; BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); - uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId); - BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if(!bg) - continue; + uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId); + if( bgTypeId == _player->GetBattleGroundTypeId() ) + { + bg = _player->GetBattleGround(); + //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena + //so i must use bg pointer to get that information + if( bg && bg->GetArenaType() == arenaType ) + { + // this line is checked, i only don't know if GetStartTime is changing itself after bg end! + // send status in BattleGround + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType); + SendPacket(&data); + continue; + } + } + //we are sending update to player about queue - he can be invited there! + //get GroupQueueInfo for queue status BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - if(itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo) + if( itrPlayerStatus == qpMap.end() ) continue; - arenatype = itrPlayerStatus->second.GroupInfo->ArenaType; - uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTime()-itrPlayerStatus->second.GroupInfo->JoinTime, arenatype); - SendPacket(&data); + if( itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID ) + { + bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId); + if( !bg ) + continue; + uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime); + // send status invited to BattleGround + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); + SendPacket(&data); + } + else + { + BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); + if( !bg ) + continue; + uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); + // send status in BattleGround Queue + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(itrPlayerStatus->second.GroupInfo->JoinTime, getMSTime()), arenaType); + SendPacket(&data); + } } } diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index 2dd619802..dd04a7857 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -159,7 +159,8 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId ginfo->ArenaTeamId = arenateamid; ginfo->IsRated = isRated; ginfo->IsInvitedToBGInstanceGUID = 0; - ginfo->JoinTime = sWorld.GetGameTime() * IN_MILISECONDS; + ginfo->JoinTime = getMSTime(); + ginfo->RemoveInviteTime = 0; ginfo->Team = leader->GetTeam(); ginfo->ArenaTeamRating = arenaRating; ginfo->OpponentsTeamRating = 0; @@ -194,7 +195,7 @@ void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo) void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id) { - uint32 timeInQueue = (sWorld.GetGameTime() * IN_MILISECONDS) - ginfo->JoinTime; + uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime()); uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas! if( !ginfo->ArenaType ) { @@ -353,7 +354,7 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to // queue->removeplayer, it causes bugs WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); plr2->GetSession()->SendPacket(&data); } // then actually delete, this may delete the group as well! @@ -442,6 +443,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b // invite the player PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id); + ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME; sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(), bg->GetTypeID(), ginfo->Team); WorldPacket data; @@ -451,7 +453,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b sLog.outDebug("Battleground: invited plr %s (%u) to BG instance %u queueindex %u bgtype %u, I can't help it if they don't press the enter battle button.",plr->GetName(),plr->GetGUIDLow(),bg->GetInstanceID(),queueSlot,bg->GetTypeID()); // send status packet - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType); plr->GetSession()->SendPacket(&data); } return true; @@ -508,7 +510,7 @@ void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg) // remove player from queue, this might delete the ginfo as well! don't use that pointer after this! RemovePlayer(itr2->first, true); WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); plr->GetSession()->SendPacket(&data); } } @@ -1067,7 +1069,8 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) { WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITATION_REMIND_TIME, 0); + //here must be remaining time + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType); plr->GetSession()->SendPacket(&data); } } @@ -1106,7 +1109,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(), bg->GetQueueId()); WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); plr->GetSession()->SendPacket(&data); } } @@ -1226,7 +1229,7 @@ void BattleGroundMgr::Update(uint32 diff) } } -void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype) +void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype) { // we can be in 3 queues in same time... if(StatusID == 0) @@ -1240,11 +1243,11 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4)); *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time // uint64 in client - *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) ); + *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) ); *data << uint32(bg->GetClientInstanceID()); // alliance/horde for BG and skirmish/rated for Arenas // following displays the minimap-icon 0 = faction icon 1 = arenaicon - *data << uint8(bg->isArena()); + *data << uint8(bg->isRated()); /* *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!! switch(bg->GetTypeID()) // value depends on bg id { @@ -1301,7 +1304,7 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro { case STATUS_WAIT_QUEUE: // status_in_queue *data << uint32(Time1); // average wait time, milliseconds - *data << uint32(Time2); // time in queue, updated every minute? + *data << uint32(Time2); // time in queue, updated every minute!, milliseconds break; case STATUS_WAIT_JOIN: // status_invite *data << uint32(bg->GetMapId()); // map id @@ -1309,7 +1312,7 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro break; case STATUS_IN_PROGRESS: // status_in_progress *data << uint32(bg->GetMapId()); // map id - *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds + *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds *data << uint32(Time2); // time from bg start, milliseconds *data << uint8(0x1); // unk sometimes 0x0! break; diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h index 6e6dd3141..b706ba955 100644 --- a/src/game/BattleGroundMgr.h +++ b/src/game/BattleGroundMgr.h @@ -48,6 +48,7 @@ struct GroupQueueInfo // stores informatio uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG uint32 ArenaTeamId; // team id if rated match uint32 JoinTime; // time when group was added + uint32 RemoveInviteTime; // time when we will remove invite for players in group uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG uint32 ArenaTeamRating; // if rated match, inited to the rating of the team uint32 OpponentsTeamRating; // for rated arena matches @@ -184,7 +185,7 @@ class BattleGroundMgr void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId); void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value); void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg); - void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0); + void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype); void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid); void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index eed557192..79012bc1f 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7448" + #define REVISION_NR "7449" #endif // __REVISION_NR_H__ From 3a5d59c0c74ca6651a670e30a3af4f2a748f57f0 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Fri, 13 Mar 2009 16:57:14 +0300 Subject: [PATCH 10/46] [7450] Fixes and improvements in TARGET_BEHIND_VICTIM, SPELL_EFFECT_JUMP2, SPELL_EFFECT_TELEPORT_UNITS work. * Move near teleport code for player/creature in Unit::NearTeleportTo * Allow correctly seelct target and end point orientation for script casted spells with TARGET_BEHIND_VICTIM * Replace use BuildTeleportAckMsg by BuildHeartBeatMsg for creature teleports. BuildTeleportAckMsg set active mover for targeted player to affected creature and "freeze" player. --- src/game/Spell.cpp | 32 +++++++++-- src/game/SpellEffects.cpp | 111 ++++++++++++++++---------------------- src/game/Unit.cpp | 16 ++++++ src/game/Unit.h | 2 + src/shared/revision_nr.h | 2 +- 5 files changed, 93 insertions(+), 70 deletions(-) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 04fc0ae65..df4530399 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -426,6 +426,21 @@ void Spell::FillTargetMap() // but need it support in some know cases switch(m_spellInfo->EffectImplicitTargetA[i]) { + case TARGET_SELF: + switch(m_spellInfo->EffectImplicitTargetB[i]) + { + case 0: + SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); + break; + case TARGET_BEHIND_VICTIM: // use B case that not dependent from from A in fact + SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); + break; + default: + SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); + SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); + break; + } + break; case TARGET_CASTER_COORDINATES: // Note: this hack with search required until GO casting not implemented // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support @@ -2051,8 +2066,15 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) }break; case TARGET_BEHIND_VICTIM: { - Unit *pTarget = m_caster->getVictim(); - if(!pTarget && m_caster->GetTypeId() == TYPEID_PLAYER) + Unit *pTarget = NULL; + + // explicit cast data from client or server-side cast + // some spell at client send caster + if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=m_caster) + pTarget = m_targets.getUnitTarget(); + else if(m_caster->getVictim()) + pTarget = m_caster->getVictim(); + else if(m_caster->GetTypeId() == TYPEID_PLAYER) pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); if(pTarget) @@ -2060,9 +2082,13 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) float _target_x, _target_y, _target_z; pTarget->GetClosePoint(_target_x, _target_y, _target_z, m_caster->GetObjectSize(), CONTACT_DISTANCE, M_PI); if(pTarget->IsWithinLOS(_target_x,_target_y,_target_z)) + { + TagUnitMap.push_back(m_caster); m_targets.setDestination(_target_x, _target_y, _target_z); + } } - }break; + break; + } case TARGET_DYNAMIC_OBJECT_COORDINATES: { // if parent spell create dynamic object extract area from it diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 5d3c54473..2ca158838 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -2009,39 +2009,41 @@ void Spell::EffectJump(uint32 i) x = m_targets.m_destX; y = m_targets.m_destY; z = m_targets.m_destZ; - o = m_caster->GetOrientation(); + + if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_BEHIND_VICTIM) + { + // explicit cast data from client or server-side cast + // some spell at client send caster + Unit* pTarget = NULL; + if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=m_caster) + pTarget = m_targets.getUnitTarget(); + else if(unitTarget->getVictim()) + pTarget = m_caster->getVictim(); + else if(m_caster->GetTypeId() == TYPEID_PLAYER) + pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); + + o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation(); + } + else + o = m_caster->GetOrientation(); } else if(unitTarget) { - x = unitTarget->GetPositionX(); - y = unitTarget->GetPositionY(); - z = unitTarget->GetPositionZ(); - o = m_spellInfo->EffectImplicitTargetA[i] == TARGET_BEHIND_VICTIM - ? unitTarget->GetOrientation() - : m_caster->GetOrientation(); + unitTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE); + o = m_caster->GetOrientation(); } else if(gameObjTarget) { - x = gameObjTarget->GetPositionX(); - y = gameObjTarget->GetPositionY(); - z = gameObjTarget->GetPositionZ(); + gameObjTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE); o = m_caster->GetOrientation(); } - else - return; - - - // Teleport - if(m_caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)m_caster)->TeleportTo(m_caster->GetMapId(), x, y, z, o, - TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); else { - m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, x, y, z, o); - WorldPacket data; - m_caster->BuildTeleportAckMsg(&data, x, y, z, o); - m_caster->SendMessageToSet(&data, false); + sLog.outError( "Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id ); + return; } + + m_caster->NearTeleportTo(x,y,z,o,true); } void Spell::EffectTeleportUnits(uint32 i) @@ -2062,45 +2064,38 @@ void Spell::EffectTeleportUnits(uint32 i) } case TARGET_TABLE_X_Y_Z_COORDINATES: { - // TODO: Only players can teleport? - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); if(!st) { sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u", m_spellInfo->Id ); return; } - ((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0); + + if(st->target_mapId==unitTarget->GetMapId()) + unitTarget->NearTeleportTo(st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster); + else if(unitTarget->GetTypeId()==TYPEID_PLAYER) + ((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0); break; } case TARGET_BEHIND_VICTIM: { - // Get selected target for player (or victim for units) Unit *pTarget = NULL; - if(m_caster->GetTypeId() == TYPEID_PLAYER) - pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); - else - pTarget = m_caster->getVictim(); - // No target present - return - if (!pTarget) - return; + + // explicit cast data from client or server-side cast + // some spell at client send caster + if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=unitTarget) + pTarget = m_targets.getUnitTarget(); + else if(unitTarget->getVictim()) + pTarget = unitTarget->getVictim(); + else if(unitTarget->GetTypeId() == TYPEID_PLAYER) + pTarget = ObjectAccessor::GetUnit(*unitTarget, ((Player*)unitTarget)->GetSelection()); + // Init dest coordinates - uint32 mapid = m_caster->GetMapId(); float x = m_targets.m_destX; float y = m_targets.m_destY; float z = m_targets.m_destZ; - float orientation = pTarget->GetOrientation(); - // Teleport - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - { - m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation); - WorldPacket data; - unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation); - unitTarget->SendMessageToSet(&data, false); - } + float orientation = pTarget ? pTarget->GetOrientation() : unitTarget->GetOrientation(); + unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster); return; } default: @@ -2118,15 +2113,7 @@ void Spell::EffectTeleportUnits(uint32 i) float z = m_targets.m_destZ; float orientation = unitTarget->GetOrientation(); // Teleport - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - { - m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation); - WorldPacket data; - unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation); - unitTarget->SendMessageToSet(&data, false); - } + unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster); return; } } @@ -3787,16 +3774,12 @@ void Spell::EffectTeleUnitsFaceCaster(uint32 i) if(unitTarget->isInFlight()) return; - uint32 mapid = m_caster->GetMapId(); float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); float fx,fy,fz; m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation()); + unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget==m_caster); } void Spell::EffectLearnSkill(uint32 i) @@ -5800,7 +5783,6 @@ void Spell::EffectMomentMove(uint32 i) if( m_spellInfo->rangeIndex== 1) //self range { - uint32 mapid = m_caster->GetMapId(); float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); // before caster @@ -5810,7 +5792,7 @@ void Spell::EffectMomentMove(uint32 i) unitTarget->GetPosition(ox,oy,oz); float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case - if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5)) + if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(unitTarget->GetMapId(), ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5)) { fx = fx2; fy = fy2; @@ -5818,10 +5800,7 @@ void Spell::EffectMomentMove(uint32 i) unitTarget->UpdateGroundPositionZ(fx,fy,fz); } - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation()); + unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(),unitTarget==m_caster); } } diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 42815fdd5..e933d29ae 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -11373,3 +11373,19 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update) if(Pet* pet = GetPet()) pet->SetPhaseMask(newPhaseMask,true); } + +void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool casting /*= false*/ ) +{ + if(GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0)); + else + { + GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation); + + WorldPacket data; + // Work strange for many spells: triggered active mover set for targeted player to creature + //BuildTeleportAckMsg(&data, x, y, z, orientation); + BuildHeartBeatMsg(&data); + SendMessageToSet(&data, false); + } +} \ No newline at end of file diff --git a/src/game/Unit.h b/src/game/Unit.h index 362ead84b..0c7bc672b 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1066,6 +1066,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false); void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo); + void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false); + void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags); void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 79012bc1f..342ea9b0f 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7449" + #define REVISION_NR "7450" #endif // __REVISION_NR_H__ From 037840d5ba10d80c2131ef50a34027fd743b7165 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Fri, 13 Mar 2009 19:18:10 +0300 Subject: [PATCH 11/46] [7451] Implement correct work SPELL_AURA_PERIODIC_MANA_LEECH for percent mana cost spells. This is fix work of spell 3034 and 5138. --- src/game/SpellAuras.cpp | 29 ++++++++++++++++++++--------- src/shared/revision_nr.h | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 8e4c19084..478c1ae93 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -5919,6 +5919,15 @@ void Aura::PeriodicTick() } case SPELL_AURA_PERIODIC_MANA_LEECH: { + if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue >= MAX_POWERS) + return; + + Powers power = Powers(m_modifier.m_miscvalue); + + // power type might have changed between aura applying and tick (druid's shapeshift) + if(m_target->getPowerType() != power) + return; + Unit *pCaster = GetCaster(); if(!pCaster) return; @@ -5937,18 +5946,20 @@ void Aura::PeriodicTick() // ignore non positive values (can be result apply spellmods to aura damage uint32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0; + // Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana) + // It's mana percent cost spells, m_modifier.m_amount is percent drain from target + if (m_spellProto->ManaCostPercentage) + { + // max value + uint32 maxmana = pCaster->GetMaxPower(power) * pdamage * 2 / 100; + pdamage = m_target->GetMaxPower(power) * pdamage / 100; + if(pdamage > maxmana) + pdamage = maxmana; + } + sLog.outDetail("PeriodicTick: %u (TypeId: %u) power leech of %u (TypeId: %u) for %u dmg inflicted by %u", GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId()); - if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue >= MAX_POWERS) - break; - - Powers power = Powers(m_modifier.m_miscvalue); - - // power type might have changed between aura applying and tick (druid's shapeshift) - if(m_target->getPowerType() != power) - break; - int32 drain_amount = m_target->GetPower(power) > pdamage ? pdamage : m_target->GetPower(power); // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 342ea9b0f..7349eca03 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7450" + #define REVISION_NR "7451" #endif // __REVISION_NR_H__ From 4e4db62da320ab67924a0240b9295d3338eefd51 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Fri, 13 Mar 2009 20:22:47 +0300 Subject: [PATCH 12/46] [7452] Drop from DB broken action button data detected at loading. --- src/game/Player.cpp | 19 +++++++++++++------ src/game/Player.h | 2 +- src/shared/revision_nr.h | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 9abcebfb9..1a2f91053 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -5358,12 +5358,12 @@ void Player::SendInitialActionButtons() sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() ); } -void Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc) +bool Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc) { if(button >= MAX_ACTION_BUTTONS) { sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() ); - return; + return false; } // check cheating with adding non-known spells to action bar @@ -5372,13 +5372,13 @@ void Player::addActionButton(const uint8 button, const uint16 action, const uint if(!sSpellStore.LookupEntry(action)) { sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() ); - return; + return false; } if(!HasSpell(action)) { sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() ); - return; + return false; } } @@ -5396,6 +5396,7 @@ void Player::addActionButton(const uint8 button, const uint16 action, const uint }; sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button ); + return true; } void Player::removeActionButton(uint8 button) @@ -14789,9 +14790,15 @@ void Player::_LoadActions(QueryResult *result) uint8 button = fields[0].GetUInt8(); - addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8()); + if(addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8())) + m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED; + else + { + sLog.outError( " ...at loading, and will deleted in DB also"); - m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED; + // Will deleted in DB at next save (it can create data until save but marked as deleted) + m_actionButtons[button].uState = ACTIONBUTTON_DELETED; + } } while( result->NextRow() ); diff --git a/src/game/Player.h b/src/game/Player.h index d224c5bd6..4bea09710 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1530,7 +1530,7 @@ class MANGOS_DLL_SPEC Player : public Unit m_cinematic = cine; } - void addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc); + bool addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc); void removeActionButton(uint8 button); void SendInitialActionButtons(); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 7349eca03..c71b496fa 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7451" + #define REVISION_NR "7452" #endif // __REVISION_NR_H__ From bc57ab7c58a26161d7c4a478b96b3ef57ef76482 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Fri, 13 Mar 2009 22:22:52 +0300 Subject: [PATCH 13/46] [7453] Fixed some example data in mangos.sql --- sql/mangos.sql | 36 +++++++++++++++++++----------------- src/shared/revision_nr.h | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/sql/mangos.sql b/sql/mangos.sql index 9c54def8b..3dc799bad 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -639,6 +639,8 @@ CREATE TABLE `creature_model_info` ( LOCK TABLES `creature_model_info` WRITE; /*!40000 ALTER TABLE `creature_model_info` DISABLE KEYS */; +INSERT INTO `creature_model_info` VALUES +(10045, 1, 1.5, 2, 0); /*!40000 ALTER TABLE `creature_model_info` ENABLE KEYS */; UNLOCK TABLES; @@ -830,7 +832,7 @@ CREATE TABLE `creature_template` ( LOCK TABLES `creature_template` WRITE; /*!40000 ALTER TABLE `creature_template` DISABLE KEYS */; INSERT INTO `creature_template` VALUES -(1,1,10045,0,10045,0,'Waypoint(Only GM can see it)','Visual',NULL,1,1,64,64,0,0,0,35,35,0,0.91,1,0,14,15,0,100,2000,2200,4096,0,0,0,0,0,0,1.76,2.42,100,8,5242886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,3,1.0,1.0,0,1,0,0,0x82,''); +(1,0,10045,0,10045,0,'Waypoint(Only GM can see it)','Visual',NULL,1,1,64,64,0,0,0,35,35,0,0.91,1,0,14,15,0,100,2000,2200,4096,0,0,0,0,0,0,1.76,2.42,100,8,5242886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,3,1.0,1.0,0,1,0,0,0x82,''); /*!40000 ALTER TABLE `creature_template` ENABLE KEYS */; UNLOCK TABLES; @@ -1706,7 +1708,7 @@ INSERT INTO `item_template` VALUES (56,4,1,-1,'Apprentice\'s Robe',12647,0,0,1,5,1,20,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (57,4,1,-1,'Acolyte\'s Robe',12645,0,0,1,5,1,20,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (59,4,0,-1,'Acolyte\'s Shoes',3261,1,0,1,5,1,8,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(117,0,0,-1,'Tough Jerky',2473,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(117,0,0,-1,'Tough Jerky',2473,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (120,4,1,-1,'Thug Pants',10006,0,0,1,4,1,7,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (121,4,0,-1,'Thug Boots',10008,1,0,1,4,1,8,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (127,4,0,-1,'Trapper\'s Shirt',9996,1,0,1,1,1,4,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), @@ -1716,13 +1718,13 @@ INSERT INTO `item_template` VALUES (148,4,0,-1,'Rugged Trapper\'s Shirt',9976,1,0,1,1,1,4,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (153,4,2,-1,'Primitive Kilt',10050,0,0,1,5,1,7,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,8,0,0,0,0,0,30,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (154,4,0,-1,'Primitive Mantle',10058,1,0,1,1,1,4,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(159,0,0,-1,'Refreshing Spring Water',18084,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,430,0,-1,0,-1,59,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(159,0,0,-1,'Refreshing Spring Water',18084,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,430,0,-1,0,-1,59,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (1395,4,1,-1,'Apprentice\'s Pants',9924,0,0,1,5,1,7,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (1396,4,1,-1,'Acolyte\'s Pants',3260,0,0,1,4,1,7,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(2070,0,0,-1,'Darnassian Bleu',6353,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(2070,0,0,-1,'Darnassian Bleu',6353,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (2092,2,15,-1,'Worn Dagger',6442,1,0,1,35,7,13,2047,255,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1600,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,1,3,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(2101,1,2,-1,'Light Quiver',21328,1,0,1,4,1,18,2047,255,1,1,0,0,0,0,0,0,0,0,1,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,14824,1,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(2102,1,3,-1,'Small Ammo Pouch',1816,1,0,1,4,1,18,2047,255,1,1,0,0,0,0,0,0,0,0,1,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,14824,1,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(2101,11,2,-1,'Light Quiver',21328,1,0,1,4,1,18,2047,255,1,1,0,0,0,0,0,0,0,0,1,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,14824,1,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(2102,11,3,-1,'Small Ammo Pouch',1816,1,0,1,4,1,18,2047,255,1,1,0,0,0,0,0,0,0,0,1,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,14824,1,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (2105,4,0,-1,'Thug Shirt',10005,1,0,1,5,1,4,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (2361,2,5,-1,'Battleworn Hammer',8690,1,0,1,45,9,17,2047,255,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2900,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,2,1,0,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (2362,4,6,-1,'Worn Wooden Shield',18730,0,0,1,7,1,14,32767,511,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,1,4,0,0,1,0,20,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), @@ -1730,11 +1732,11 @@ INSERT INTO `item_template` VALUES (2508,2,3,-1,'Old Blunderbuss',6606,1,0,1,27,5,26,2047,255,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2300,3,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,1,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (2512,6,2,-1,'Rough Arrow',5996,1,0,1,10,0,24,2047,255,5,1,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (2516,6,3,-1,'Light Shot',5998,1,0,1,10,0,24,2047,255,5,1,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(2947,2,16,-1,'Small Throwing Knife',16754,1,0,1,15,0,25,2047,255,3,1,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2000,4,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(2947,15,0,-1,'Small Throwing Knife',16754,1,0,1,15,0,0,2047,255,3,1,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2000,4,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (3661,2,10,-1,'Handcrafted Staff',18530,1,0,1,45,9,17,2047,255,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2900,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,2,2,0,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(4536,0,0,-1,'Shiny Red Apple',6410,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(4540,0,0,-1,'Tough Hunk of Bread',6399,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(4604,0,0,-1,'Forest Mushroom Cap',15852,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(4536,0,0,-1,'Shiny Red Apple',6410,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(4540,0,0,-1,'Tough Hunk of Bread',6399,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(4604,0,0,-1,'Forest Mushroom Cap',15852,1,0,6,25,1,0,2047,255,5,1,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,433,0,-1,0,-1,11,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (6096,4,0,-1,'Apprentice\'s Shirt',2163,1,0,1,1,1,4,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (6097,4,0,-1,'Acolyte\'s Shirt',2470,1,0,1,1,1,4,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (6098,4,1,-1,'Neophyte\'s Robe',12679,0,0,1,4,1,20,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), @@ -1750,14 +1752,14 @@ INSERT INTO `item_template` VALUES (6139,4,1,-1,'Novice\'s Robe',12684,0,0,1,4,1,20,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (6140,4,1,-1,'Apprentice\'s Robe',12649,0,0,1,4,1,20,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (6144,4,1,-1,'Neophyte\'s Robe',12680,0,0,1,5,1,20,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,7,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(6948,15,0,-1,'Hearthstone',6418,1,64,1,0,0,0,32767,511,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8690,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(6948,15,0,-1,'Hearthstone',6418,1,64,1,0,0,0,32767,511,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8690,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,'',0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (12282,2,1,-1,'Worn Battleaxe',22291,1,0,1,43,8,17,2047,255,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2900,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,1,1,0,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(14646,12,0,-1,'Northshire Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5805,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(14647,12,0,-1,'Coldridge Valley Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5841,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(14648,12,0,-1,'Shadowglen Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5842,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(14649,12,0,-1,'Valley of Trials Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5843,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(14650,12,0,-1,'Camp Narache Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5844,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), -(14651,12,0,-1,'Deathknell Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5847,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(14646,12,0,-1,'Northshire Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5805,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(14647,12,0,-1,'Coldridge Valley Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5841,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(14648,12,0,-1,'Shadowglen Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5842,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(14649,12,0,-1,'Valley of Trials Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5843,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(14650,12,0,-1,'Camp Narache Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5844,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), +(14651,12,0,-1,'Deathknell Gift Voucher',18499,1,0,1,0,0,0,2047,255,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,'',0,0,0,5847,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (25861,2,16,-1,'Crude Throwing Axe',20777,1,0,1,15,0,25,2047,255,3,1,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2000,4,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,'internalItemHandler',0,0,0,0,0), (34648,4,4,-1,'Acherus Knight\'s Greaves',51496,2,32768,1,51,10,8,-1,-1,60,55,0,0,0,0,0,0,0,0,1,0,3,4,10,7,12,3,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,392,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,-1,0,0,0,0,-1,0,-1,0,0,0,0,-1,0,-1,0,0,0,0,-1,0,-1,0,0,0,0,-1,0,-1,1,'',0,0,0,0,0,6,0,0,0,0,0,55,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,'',0,0,0,0), (34649,4,4,-1,'Acherus Knight\'s Gauntlets',51498,2,32768,1,34,6,10,-1,-1,60,55,0,0,0,0,0,0,0,0,1,0,3,4,15,7,6,32,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,356,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,-1,0,0,0,0,-1,0,-1,0,0,0,0,-1,0,-1,0,0,0,0,-1,0,-1,0,0,0,0,-1,0,-1,1,'',0,0,0,0,0,6,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,'',0,0,0,0), diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index c71b496fa..f42b47d3f 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7452" + #define REVISION_NR "7453" #endif // __REVISION_NR_H__ From f280c9677044aed545900bb882f062e84305ea51 Mon Sep 17 00:00:00 2001 From: Lightguard Date: Sat, 14 Mar 2009 00:12:10 +0300 Subject: [PATCH 14/46] [7454] Support scripting for dummy spell effects. Note: scripting calls specially added in end of function for allow calling only if internal implementaion absent for dummy effect. Signed-off-by: VladimirMangos --- src/bindings/universal/ScriptMgr.cpp | 30 ++++++++++++++++++++++++++++ src/bindings/universal/ScriptMgr.h | 6 +++++- src/game/ScriptCalls.cpp | 3 +++ src/game/ScriptCalls.h | 6 ++++++ src/game/SpellEffects.cpp | 13 ++++++++++-- src/shared/revision_nr.h | 2 +- 6 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/bindings/universal/ScriptMgr.cpp b/src/bindings/universal/ScriptMgr.cpp index 2045386ac..e607469b9 100644 --- a/src/bindings/universal/ScriptMgr.cpp +++ b/src/bindings/universal/ScriptMgr.cpp @@ -274,6 +274,36 @@ InstanceData* CreateInstanceData(Map *map) return tmpscript->GetInstanceData(map); } +MANGOS_DLL_EXPORT +bool EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget ) +{ + Script *tmpscript = m_scripts[gameObjTarget->GetGOInfo()->ScriptId]; + + if (!tmpscript || !tmpscript->pEffectDummyGameObj) return false; + + return tmpscript->pEffectDummyGameObj(caster, spellId,effIndex,gameObjTarget); +} + +MANGOS_DLL_EXPORT +bool EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget ) +{ + Script *tmpscript = m_scripts[crTarget->GetScriptId()]; + + if (!tmpscript || !tmpscript->pEffectDummyCreature) return false; + + return tmpscript->pEffectDummyCreature(caster, spellId,effIndex,crTarget); +} + +MANGOS_DLL_EXPORT +bool EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget ) +{ + Script *tmpscript = m_scripts[itemTarget->GetProto()->ScriptId]; + + if (!tmpscript || !tmpscript->pEffectDummyItem) return false; + + return tmpscript->pEffectDummyItem(caster, spellId,effIndex,itemTarget); +} + void ScriptedAI::UpdateAI(const uint32) { //Check if we have a current target diff --git a/src/bindings/universal/ScriptMgr.h b/src/bindings/universal/ScriptMgr.h index 4da14aabd..37b32c79b 100644 --- a/src/bindings/universal/ScriptMgr.h +++ b/src/bindings/universal/ScriptMgr.h @@ -41,7 +41,8 @@ struct Script pGossipHello(NULL), pQuestAccept(NULL), pGossipSelect(NULL), pGossipSelectWithCode(NULL), pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), pChooseReward(NULL), pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), pGOQuestAccept(NULL), - pGOChooseReward(NULL), pReceiveEmote(NULL), pItemUse(NULL), GetAI(NULL) + pGOChooseReward(NULL), pReceiveEmote(NULL), pItemUse(NULL), pEffectDummyGameObj(NULL), pEffectDummyCreature(NULL), + pEffectDummyItem(NULL), GetAI(NULL) {} std::string Name; @@ -64,6 +65,9 @@ struct Script bool (*pGOChooseReward )(Player *player, GameObject *_GO, Quest const*_Quest, uint32 opt ); bool (*pReceiveEmote )(Player *player, Creature *_Creature, uint32 emote ); bool (*pItemUse )(Player *player, Item* _Item, SpellCastTargets const& targets); + bool (*pEffectDummyGameObj )(Unit*, uint32, uint32, GameObject* ); + bool (*pEffectDummyCreature )(Unit*, uint32, uint32, Creature* ); + bool (*pEffectDummyItem )(Unit*, uint32, uint32, Item* ); CreatureAI* (*GetAI)(Creature *_Creature); InstanceData* (*GetInstanceData)(Map*); diff --git a/src/game/ScriptCalls.cpp b/src/game/ScriptCalls.cpp index b4b953f3c..ec67773ec 100644 --- a/src/game/ScriptCalls.cpp +++ b/src/game/ScriptCalls.cpp @@ -74,6 +74,9 @@ bool LoadScriptingModule(char const* libName) ||!(testScript->GOQuestAccept =(scriptCallGOQuestAccept )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"GOQuestAccept" )) ||!(testScript->ReceiveEmote =(scriptCallReceiveEmote )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"ReceiveEmote" )) ||!(testScript->ItemUse =(scriptCallItemUse )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"ItemUse" )) + ||!(testScript->EffectDummyGameObj =(scriptCallEffectDummyGameObj )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyGameObj" )) + ||!(testScript->EffectDummyCreature =(scriptCallEffectDummyCreature )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyCreature" )) + ||!(testScript->EffectDummyItem =(scriptCallEffectDummyItem )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyItem" )) ||!(testScript->GetAI =(scriptCallGetAI )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"GetAI" )) ||!(testScript->CreateInstanceData =(scriptCallCreateInstanceData )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"CreateInstanceData" )) ) diff --git a/src/game/ScriptCalls.h b/src/game/ScriptCalls.h index b075693f8..11aade7e7 100644 --- a/src/game/ScriptCalls.h +++ b/src/game/ScriptCalls.h @@ -56,6 +56,9 @@ typedef bool(MANGOS_IMPORT * scriptCallGOQuestAccept)(Player *player, GameObject typedef bool(MANGOS_IMPORT * scriptCallGOChooseReward)(Player *player, GameObject *, Quest const*, uint32 opt ); typedef bool(MANGOS_IMPORT * scriptCallReceiveEmote) ( Player *player, Creature *_Creature, uint32 emote ); typedef bool(MANGOS_IMPORT * scriptCallItemUse) (Player *player, Item *_Item, SpellCastTargets const& targets); +typedef bool(MANGOS_IMPORT * scriptCallEffectDummyGameObj) (Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget); +typedef bool(MANGOS_IMPORT * scriptCallEffectDummyCreature) (Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget); +typedef bool(MANGOS_IMPORT * scriptCallEffectDummyItem) (Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget); typedef CreatureAI* (MANGOS_IMPORT * scriptCallGetAI) ( Creature *_Creature ); typedef InstanceData* (MANGOS_IMPORT * scriptCallCreateInstanceData) (Map *map); @@ -82,6 +85,9 @@ typedef struct scriptCallGOQuestAccept GOQuestAccept; scriptCallReceiveEmote ReceiveEmote; scriptCallItemUse ItemUse; + scriptCallEffectDummyGameObj EffectDummyGameObj; + scriptCallEffectDummyCreature EffectDummyCreature; + scriptCallEffectDummyItem EffectDummyItem; scriptCallGetAI GetAI; scriptCallCreateInstanceData CreateInstanceData; diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 2ca158838..99c0811ba 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -1116,7 +1116,7 @@ void Spell::EffectDummy(uint32 i) return; unitTarget->CastSpell(unitTarget, 58419, true); - break; + return; } case 58420: // Portal to Stormwind { @@ -1124,7 +1124,7 @@ void Spell::EffectDummy(uint32 i) return; unitTarget->CastSpell(unitTarget, 58421, true); - break; + return; } } @@ -1747,6 +1747,15 @@ void Spell::EffectDummy(uint32 i) m_caster->AddPetAura(petSpell); return; } + + // Script based implementation. Must be used only for not good for implementation in core spell effects + // So called only for not proccessed cases + if(gameObjTarget) + Script->EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget); + else if(unitTarget && unitTarget->GetTypeId()==TYPEID_UNIT) + Script->EffectDummyCreature(m_caster, m_spellInfo->Id, i, (Creature*)unitTarget); + else if(itemTarget) + Script->EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget); } void Spell::EffectTriggerSpellWithValue(uint32 i) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index f42b47d3f..b2abad1cc 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7453" + #define REVISION_NR "7454" #endif // __REVISION_NR_H__ From b45b075668a87b04a4e9368fc197aa373f42d971 Mon Sep 17 00:00:00 2001 From: Triply Date: Sat, 14 Mar 2009 16:57:49 +0100 Subject: [PATCH 15/46] [7455] Implemented condition that player can be in 2 groups in 1 time - BG raid and normal group / raid. Patch is tested, but can cause problems / unexpected behaviour. TODO: set raid leader of battleground raid to raid leader who entered BG TODO: when player leaves group, he is removed from GroupQueueInfo, and for him is created new GroupQueueInfo in normal queue. Signed-off-by: Triply --- src/game/BattleGround.cpp | 2 +- src/game/BattleGroundHandler.cpp | 2 - src/game/ChatHandler.cpp | 36 +++++++---- src/game/Group.cpp | 107 ++++++++++++++++++++++++------- src/game/Group.h | 2 +- src/game/GroupHandler.cpp | 38 +++++------ src/game/Player.cpp | 40 +++++++++++- src/game/Player.h | 8 +++ src/game/Unit.h | 2 +- src/shared/revision_nr.h | 2 +- 10 files changed, 171 insertions(+), 68 deletions(-) diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index a2c192ad7..45ab6cf8d 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -1159,7 +1159,7 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, if(group->IsMember(plr_guid)) { uint8 subgroup = group->GetMemberGroup(plr_guid); - plr->SetGroup(group, subgroup); + plr->SetBattleGroundRaid(group, subgroup); } else GetBgRaid(team)->AddMember(plr_guid, plr->GetName()); diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index fceb9c015..1dfed434c 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -430,8 +430,6 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) _player->GetMotionMaster()->MovementExpired(); _player->m_taxi.ClearTaxiDestinations(); } - //TODO FIX ME this call must be removed! - _player->RemoveFromGroup(); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); _player->GetSession()->SendPacket(&data); diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index 1bde9d37d..76069aee6 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -232,13 +232,15 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; - Group *group = GetPlayer()->GetGroup(); - if(!group) + // if player is in battleground, he cannot say to battleground members by /p + Group *group = GetPlayer()->GetOriginalGroup(); + // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid, then return + if( !group && (!(group = GetPlayer()->GetGroup()) || group->isBGGroup()) ) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL); - group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID())); + group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID())); } break; case CHAT_MSG_GUILD: @@ -312,13 +314,15 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; - Group *group = GetPlayer()->GetGroup(); - if(!group || !group->isRaidGroup()) + // if player is in battleground, he cannot say to battleground members by /ra + Group *group = GetPlayer()->GetOriginalGroup(); + // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid or his group isn't raid, then return + if( !group && !(group = GetPlayer()->GetGroup()) || group->isBGGroup() || !group->isRaidGroup() ) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_RAID_LEADER: { @@ -338,13 +342,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; - Group *group = GetPlayer()->GetGroup(); - if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID())) + // if player is in battleground, he cannot say to battleground members by /ra + Group *group = GetPlayer()->GetOriginalGroup(); + if( !group && !(group = GetPlayer()->GetGroup()) || group->isBGGroup() || !group->isRaidGroup() ) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_RAID_WARNING: { @@ -363,8 +368,9 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) return; WorldPacket data; + //in battleground, raid warning is sent only to players in battleground - code is ok ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_BATTLEGROUND: @@ -379,13 +385,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; + //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() Group *group = GetPlayer()->GetGroup(); - if(!group || !group->isRaidGroup()) + if(!group || !group->isBGGroup()) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_BATTLEGROUND_LEADER: @@ -400,13 +407,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; + //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() Group *group = GetPlayer()->GetGroup(); - if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID())) + if(!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID())) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_CHANNEL: diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 21695b754..de26cb666 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -201,7 +201,8 @@ void Group::ConvertToRaid() _initRaidSubGroupsCounter(); - if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); + if(!isBGGroup()) + CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); SendUpdate(); // update quest related GO states (quest activity dependent from raid membership) @@ -212,7 +213,12 @@ void Group::ConvertToRaid() bool Group::AddInvite(Player *player) { - if(!player || player->GetGroupInvite() || player->GetGroup()) + if( !player || player->GetGroupInvite() ) + return false; + Group* group = player->GetGroup(); + if( group && group->isBGGroup() ) + group = player->GetOriginalGroup(); + if( group ) return false; RemoveInvite(player); @@ -323,9 +329,17 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method) player->GetSession()->SendPacket( &data ); } - data.Initialize(SMSG_GROUP_LIST, 24); - data << uint64(0) << uint64(0) << uint64(0); - player->GetSession()->SendPacket(&data); + //we already removed player from group and in player->GetGroup() is his original group! + if( Group* group = player->GetGroup() ) + { + group->SendUpdate(); + } + else + { + data.Initialize(SMSG_GROUP_LIST, 24); + data << uint64(0) << uint64(0) << uint64(0); + player->GetSession()->SendPacket(&data); + } _homebindIfInstance(player); } @@ -334,7 +348,7 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method) { WorldPacket data(SMSG_GROUP_SET_LEADER, (m_memberSlots.front().name.size()+1)); data << m_memberSlots.front().name; - BroadcastPacket(&data); + BroadcastPacket(&data, true); } SendUpdate(); @@ -357,7 +371,7 @@ void Group::ChangeLeader(const uint64 &guid) WorldPacket data(SMSG_GROUP_SET_LEADER, slot->name.size()+1); data << slot->name; - BroadcastPacket(&data); + BroadcastPacket(&data, true); SendUpdate(); } @@ -371,13 +385,26 @@ void Group::Disband(bool hideDestroy) if(!player) continue; - player->SetGroup(NULL); + //we cannot call _removeMember because it would invalidate member iterator + if (player) + { + //if we are removing player from battleground raid + if( isBGGroup() ) + player->RemoveFromBattleGroundRaid(); + else + { + //we can remove player who is in battleground from his original group + if( player->GetOriginalGroup() == this ) + player->SetOriginalGroup(NULL); + else + player->SetGroup(NULL); + } + } // quest related GO state dependent from raid membership if(isRaidGroup()) player->UpdateForQuestsGO(); - if(!player->GetSession()) continue; @@ -388,9 +415,17 @@ void Group::Disband(bool hideDestroy) player->GetSession()->SendPacket(&data); } - data.Initialize(SMSG_GROUP_LIST, 24); - data << uint64(0) << uint64(0) << uint64(0); - player->GetSession()->SendPacket(&data); + //we already removed player from group and in player->GetGroup() is his original group, send update + if( Group* group = player->GetGroup() ) + { + group->SendUpdate(); + } + else + { + data.Initialize(SMSG_GROUP_LIST, 24); + data << uint64(0) << uint64(0) << uint64(0); + player->GetSession()->SendPacket(&data); + } _homebindIfInstance(player); } @@ -838,7 +873,7 @@ void Group::SetTargetIcon(uint8 id, uint64 guid) data << (uint8)0; data << id; data << guid; - BroadcastPacket(&data); + BroadcastPacket(&data, true); } void Group::GetDataForXPAtKill(Unit const* victim, uint32& count,uint32& sum_level, Player* & member_with_max_level, Player* & not_gray_member_with_max_level) @@ -891,7 +926,7 @@ void Group::SendUpdate() for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) { player = objmgr.GetPlayer(citr->guid); - if(!player || !player->GetSession()) + if(!player || !player->GetSession() || player->GetGroup() != this ) continue; // guess size WorldPacket data(SMSG_GROUP_LIST, (1+1+1+1+8+4+GetMembersCount()*20)); @@ -905,11 +940,14 @@ void Group::SendUpdate() { if(citr->guid == citr2->guid) continue; + Player* member = objmgr.GetPlayer(citr2->guid); + uint8 onlineState = (member) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE; + onlineState = onlineState | ((isBGGroup()) ? MEMBER_STATUS_PVP : 0); data << citr2->name; data << (uint64)citr2->guid; // online-state - data << (uint8)(objmgr.GetPlayer(citr2->guid) ? 1 : 0); + data << (uint8)(onlineState); data << (uint8)(citr2->group); // groupid data << (uint8)(citr2->assistant?0x01:0); // 0x2 main assist, 0x4 main tank } @@ -943,12 +981,12 @@ void Group::UpdatePlayerOutOfRange(Player* pPlayer) } } -void Group::BroadcastPacket(WorldPacket *packet, int group, uint64 ignore) +void Group::BroadcastPacket(WorldPacket *packet, bool ignorePlayersInBGRaid, int group, uint64 ignore) { for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { Player *pl = itr->getSource(); - if(!pl || (ignore != 0 && pl->GetGUID() == ignore)) + if(!pl || (ignore != 0 && pl->GetGUID() == ignore) || (ignorePlayersInBGRaid && pl->GetGroup() != this) ) continue; if (pl->GetSession() && (group==-1 || itr->getSubGroup()==group)) @@ -1027,7 +1065,15 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u if(player) { player->SetGroupInvite(NULL); - player->SetGroup(this, group); + //if player is in group and he is being added to BG raid group, then call SetBattleGroundRaid() + if( player->GetGroup() && isBGGroup() ) + player->SetBattleGroundRaid(this, group); + //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() + else if ( player->GetGroup() ) + player->SetOriginalGroup(this, group); + //if player is not in group, then call set group + else + player->SetGroup(this, group); // if the same group invites the player back, cancel the homebind timer InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDifficulty()); if(bind && bind->save->GetInstanceId() == player->GetInstanceId()) @@ -1054,7 +1100,17 @@ bool Group::_removeMember(const uint64 &guid) Player *player = objmgr.GetPlayer(guid); if (player) { - player->SetGroup(NULL); + //if we are removing player from battleground raid + if( isBGGroup() ) + player->RemoveFromBattleGroundRaid(); + else + { + //we can remove player who is in battleground from his original group + if( player->GetOriginalGroup() == this ) + player->SetOriginalGroup(NULL); + else + player->SetGroup(NULL); + } } _removeRolls(guid); @@ -1246,12 +1302,17 @@ void Group::ChangeMembersGroup(Player *player, const uint8 &group) return; if(_setMembersGroup(player->GetGUID(), group)) { - uint8 prevSubGroup; - prevSubGroup = player->GetSubGroup(); - + uint8 prevSubGroup = player->GetSubGroup(); + if( player->GetGroup() == this ) + player->GetGroupRef().setSubGroup(group); + //if player is in BG raid, it is possible that he is also in normal raid - and that normal raid is stored in m_originalGroup reference + else + { + prevSubGroup = player->GetOriginalSubGroup(); + player->GetOriginalGroupRef().setSubGroup(group); + } SubGroupCounterDecrease(prevSubGroup); - player->GetGroupRef().setSubGroup(group); SendUpdate(); } } diff --git a/src/game/Group.h b/src/game/Group.h index 0fb107735..478b7c5cb 100644 --- a/src/game/Group.h +++ b/src/game/Group.h @@ -291,7 +291,7 @@ class MANGOS_DLL_SPEC Group void SendUpdate(); void UpdatePlayerOutOfRange(Player* pPlayer); // ignore: GUID of player that will be ignored - void BroadcastPacket(WorldPacket *packet, int group=-1, uint64 ignore=0); + void BroadcastPacket(WorldPacket *packet, bool ignorePlayersInBGRaid, int group=-1, uint64 ignore=0); void BroadcastReadyCheck(WorldPacket *packet); void OfflineReadyCheck(); diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index 44fa9c290..d1de13ad3 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -55,12 +55,6 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) std::string membername; recv_data >> membername; - if(_player->InBattleGround()) - { - SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_INVITE_RESTRICTED); - return; - } - // attempt add selected player // cheating @@ -97,15 +91,20 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) return; } + Group *group = GetPlayer()->GetGroup(); + if( group && group->isBGGroup() ) + group = GetPlayer()->GetOriginalGroup(); + + Group *group2 = player->GetGroup(); + if( group2 && group2->isBGGroup() ) + group2 = player->GetOriginalGroup(); // player already in another group or invited - if(player->GetGroup() || player->GetGroupInvite() ) + if( group2 || player->GetGroupInvite() ) { SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_ALREADY_IN_GROUP); return; } - Group *group = GetPlayer()->GetGroup(); - if(group) { // not have permissions for invite @@ -114,7 +113,6 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_YOU_NOT_LEADER); return; } - // not have place if(group->IsFull()) { @@ -185,27 +183,20 @@ void WorldSession::HandleGroupAcceptOpcode( WorldPacket & /*recv_data*/ ) Player* leader = objmgr.GetPlayer(group->GetLeaderGUID()); - if(leader && leader->InBattleGround()) - { - SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_INVITE_RESTRICTED); - return; - } - // forming a new group, create it if(!group->IsCreated()) { - if(leader) group->RemoveInvite(leader); + if( leader ) + group->RemoveInvite(leader); group->Create(group->GetLeaderGUID(), group->GetLeaderName()); objmgr.AddGroup(group); } - // everything's fine, do it + // everything's fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! if(!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName())) return; uint8 subgroup = group->GetMemberGroup(GetPlayer()->GetGUID()); - - GetPlayer()->SetGroup(group, subgroup); } void WorldSession::HandleGroupDeclineOpcode( WorldPacket & /*recv_data*/ ) @@ -424,7 +415,7 @@ void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data) data << GetPlayer()->GetGUID(); data << x; data << y; - GetPlayer()->GetGroup()->BroadcastPacket(&data, -1, GetPlayer()->GetGUID()); + GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID()); } void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) @@ -451,7 +442,7 @@ void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) data << roll; data << GetPlayer()->GetGUID(); if(GetPlayer()->GetGroup()) - GetPlayer()->GetGroup()->BroadcastPacket(&data); + GetPlayer()->GetGroup()->BroadcastPacket(&data, false); else SendPacket(&data); } @@ -512,6 +503,7 @@ void WorldSession::HandleGroupChangeSubGroupOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,1+1); + // we will get correct pointer for group here, so we don't have to check if group is BG raid Group *group = GetPlayer()->GetGroup(); if(!group) return; @@ -604,7 +596,7 @@ void WorldSession::HandleRaidReadyCheckOpcode( WorldPacket & recv_data ) // everything's fine, do it WorldPacket data(MSG_RAID_READY_CHECK, 8); data << GetPlayer()->GetGUID(); - group->BroadcastPacket(&data, -1); + group->BroadcastPacket(&data, false, -1); group->OfflineReadyCheck(); } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 1a2f91053..9cbcafa21 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -12286,7 +12286,7 @@ void Player::SendNewItem(Item *item, uint32 count, bool received, bool created, data << GetItemCount(item->GetEntry()); // count of items in inventory if (broadcast && GetGroup()) - GetGroup()->BroadcastPacket(&data); + GetGroup()->BroadcastPacket(&data, true); else GetSession()->SendPacket(&data); } @@ -18319,7 +18319,8 @@ void Player::ClearComboPoints() void Player::SetGroup(Group *group, int8 subgroup) { - if(group == NULL) m_group.unlink(); + if(group == NULL) + m_group.unlink(); else { // never use SetGroup without a subgroup unless you specify NULL for group @@ -19414,6 +19415,41 @@ PartyResult Player::CanUninviteFromGroup() const return PARTY_RESULT_OK; } +void Player::SetBattleGroundRaid(Group* group, int8 subgroup) +{ + //we must move references from m_group to m_originalGroup + SetOriginalGroup(GetGroup(), GetSubGroup()); + + m_group.unlink(); + m_group.link(group, this); + m_group.setSubGroup((uint8)subgroup); +} + +void Player::RemoveFromBattleGroundRaid() +{ + //remove existing reference + m_group.unlink(); + if( Group* group = GetOriginalGroup() ) + { + m_group.link(group, this); + m_group.setSubGroup(GetOriginalSubGroup()); + } + SetOriginalGroup(NULL); +} + +void Player::SetOriginalGroup(Group *group, int8 subgroup) +{ + if( group == NULL ) + m_originalGroup.unlink(); + else + { + // never use SetOriginalGroup without a subgroup unless you specify NULL for group + assert(subgroup >= 0); + m_originalGroup.link(group, this); + m_originalGroup.setSubGroup((uint8)subgroup); + } +} + void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) { LiquidData liquid_status; diff --git a/src/game/Player.h b/src/game/Player.h index 4bea09710..5a0b1560f 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -2131,6 +2131,13 @@ class MANGOS_DLL_SPEC Player : public Unit void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); } Player* GetNextRandomRaidMember(float radius); PartyResult CanUninviteFromGroup() const; + // BattleGround Group System + void SetBattleGroundRaid(Group *group, int8 subgroup = -1); + void RemoveFromBattleGroundRaid(); + Group * GetOriginalGroup() { return m_originalGroup.getTarget(); } + GroupReference& GetOriginalGroupRef() { return m_originalGroup; } + uint8 GetOriginalSubGroup() const { return m_originalGroup.getSubGroup(); } + void SetOriginalGroup(Group *group, int8 subgroup = -1); GridReference &GetGridRef() { return m_gridRef; } MapReference &GetMapRef() { return m_mapRef; } @@ -2374,6 +2381,7 @@ class MANGOS_DLL_SPEC Player : public Unit // Groups GroupReference m_group; + GroupReference m_originalGroup; Group *m_groupInvite; uint32 m_groupUpdateMask; uint64 m_auraUpdateMask; diff --git a/src/game/Unit.h b/src/game/Unit.h index 0c7bc672b..633700600 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -75,7 +75,7 @@ enum SpellAuraInterruptFlags AURA_INTERRUPT_FLAG_MOUNTING = 0x00020000, // 17 removed by mounting AURA_INTERRUPT_FLAG_NOT_SEATED = 0x00040000, // 18 removed by standing up AURA_INTERRUPT_FLAG_CHANGE_MAP = 0x00080000, // 19 leaving map/getting teleported - AURA_INTERRUPT_FLAG_UNK20 = 0x00100000, // 20 + AURA_INTERRUPT_FLAG_IMMUNE_OR_STEALTH = 0x00100000, // 20 removed when player on himself casts immunity spell or vanish? AURA_INTERRUPT_FLAG_UNK21 = 0x00200000, // 21 AURA_INTERRUPT_FLAG_UNK22 = 0x00400000, // 22 AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT = 0x00800000, // 23 removed by entering pvp combat diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b2abad1cc..d8329e68d 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7454" + #define REVISION_NR "7455" #endif // __REVISION_NR_H__ From 7cc704149a0419e9cbf180ca7ef340a09a1f1b65 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sat, 14 Mar 2009 19:02:20 +0300 Subject: [PATCH 16/46] Small cleanups in item checks code. --- src/game/Item.h | 9 +- src/game/ItemPrototype.h | 3 + src/game/Player.cpp | 225 +++++++++++++++++---------------------- 3 files changed, 105 insertions(+), 132 deletions(-) diff --git a/src/game/Item.h b/src/game/Item.h index b3afa1124..2f7376aae 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -285,13 +285,10 @@ class MANGOS_DLL_SPEC Item : public Object uState = state; } - bool hasQuest(uint32 quest_id) const - { - ItemPrototype const *itemProto = GetProto(); - return itemProto && itemProto->StartQuest == quest_id; - } + bool hasQuest(uint32 quest_id) const { return GetProto()->StartQuest == quest_id; } bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; } - + bool IsPotion() const { return GetProto()->IsPotion(); } + bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); } private: uint8 m_slot; Bag *m_container; diff --git a/src/game/ItemPrototype.h b/src/game/ItemPrototype.h index 3335f3247..0fe2455d6 100644 --- a/src/game/ItemPrototype.h +++ b/src/game/ItemPrototype.h @@ -656,6 +656,9 @@ struct ItemPrototype } return 0; } + + bool IsPotion() const { return Class==ITEM_CLASS_CONSUMABLE && SubClass==ITEM_SUBCLASS_POTION; } + bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAGS_CONJURED); } }; struct ItemLocale diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 9cbcafa21..1dd3016e1 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -754,9 +754,9 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 } // if this is ammo then use it - uint8 msg = CanUseAmmo( pItem->GetProto()->ItemId ); + uint8 msg = CanUseAmmo( pItem->GetEntry() ); if( msg == EQUIP_ERR_OK ) - SetAmmo( pItem->GetProto()->ItemId ); + SetAmmo( pItem->GetEntry() ); } } } @@ -10948,60 +10948,60 @@ void Player::DestroyItem( uint8 bag, uint8 slot, bool update ) void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check) { sLog.outDebug( "STORAGE: DestroyItemCount item = %u, count = %u", item, count); - Item *pItem; - ItemPrototype const *pProto; uint32 remcount = 0; // in inventory for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) + if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) { - if( pItem->GetCount() + remcount <= count ) + if (pItem->GetEntry() == item) { - // all items in inventory can unequipped - remcount += pItem->GetCount(); - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + if (pItem->GetCount() + remcount <= count) + { + // all items in inventory can unequipped + remcount += pItem->GetCount(); + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - if(remcount >=count) + if (remcount >=count) + return; + } + else + { + ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); + pItem->SetCount( pItem->GetCount() - count + remcount ); + if (IsInWorld() & update) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); return; - } - else - { - pProto = pItem->GetProto(); - ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); - pItem->SetCount( pItem->GetCount() - count + remcount ); - if( IsInWorld() & update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - return; + } } } } for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) + if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) { - if( pItem->GetCount() + remcount <= count ) + if (pItem->GetEntry() == item) { - // all keys can be unequipped - remcount += pItem->GetCount(); - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + if (pItem->GetCount() + remcount <= count) + { + // all keys can be unequipped + remcount += pItem->GetCount(); + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - if(remcount >=count) + if (remcount >=count) + return; + } + else + { + ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); + pItem->SetCount( pItem->GetCount() - count + remcount ); + if (IsInWorld() & update) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); return; - } - else - { - pProto = pItem->GetProto(); - ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); - pItem->SetCount( pItem->GetCount() - count + remcount ); - if( IsInWorld() & update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - return; + } } } } @@ -11013,27 +11013,28 @@ void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool uneq { for(uint32 j = 0; j < pBag->GetBagSize(); j++) { - pItem = pBag->GetItemByPos(j); - if( pItem && pItem->GetEntry() == item ) + if(Item* pItem = pBag->GetItemByPos(j)) { - // all items in bags can be unequipped - if( pItem->GetCount() + remcount <= count ) + if (pItem->GetEntry() == item) { - remcount += pItem->GetCount(); - DestroyItem( i, j, update ); + // all items in bags can be unequipped + if (pItem->GetCount() + remcount <= count) + { + remcount += pItem->GetCount(); + DestroyItem( i, j, update ); - if(remcount >=count) + if (remcount >=count) + return; + } + else + { + ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); + pItem->SetCount( pItem->GetCount() - count + remcount ); + if (IsInWorld() && update) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); return; - } - else - { - pProto = pItem->GetProto(); - ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); - pItem->SetCount( pItem->GetCount() - count + remcount ); - if( IsInWorld() && update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - return; + } } } } @@ -11043,29 +11044,30 @@ void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool uneq // in equipment and bag list for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) + if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) { - if( pItem->GetCount() + remcount <= count ) + if (pItem && pItem->GetEntry() == item) { - if(!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i,false) == EQUIP_ERR_OK ) + if (pItem->GetCount() + remcount <= count) { - remcount += pItem->GetCount(); - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + if (!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i,false) == EQUIP_ERR_OK ) + { + remcount += pItem->GetCount(); + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - if(remcount >=count) - return; + if (remcount >=count) + return; + } + } + else + { + ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); + pItem->SetCount( pItem->GetCount() - count + remcount ); + if (IsInWorld() & update) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); + return; } - } - else - { - pProto = pItem->GetProto(); - ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); - pItem->SetCount( pItem->GetCount() - count + remcount ); - if( IsInWorld() & update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - return; } } } @@ -11077,40 +11079,28 @@ void Player::DestroyZoneLimitedItem( bool update, uint32 new_zone ) // in inventory for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } + if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone)) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } + if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone)) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); // in inventory bags for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { + if (Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) for(uint32 j = 0; j < pBag->GetBagSize(); j++) - { - Item* pItem = pBag->GetItemByPos(j); - if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) - DestroyItem( i, j, update); - } - } - } + if (Item* pItem = pBag->GetItemByPos(j)) + if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone)) + DestroyItem( i, j, update); // in equipment and bag list for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } + if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone)) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); } void Player::DestroyConjuredItems( bool update ) @@ -11121,40 +11111,23 @@ void Player::DestroyConjuredItems( bool update ) // in inventory for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetProto() && - (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && - (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } + if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if (pItem->IsConjuredConsumable()) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); // in inventory bags for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { + if (Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) for(uint32 j = 0; j < pBag->GetBagSize(); j++) - { - Item* pItem = pBag->GetItemByPos(j); - if( pItem && pItem->GetProto() && - (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && - (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) - DestroyItem( i, j, update); - } - } - } + if (Item* pItem = pBag->GetItemByPos(j)) + if (pItem->IsConjuredConsumable()) + DestroyItem( i, j, update); // in equipment and bag list for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetProto() && - (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && - (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } + if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if (pItem->IsConjuredConsumable()) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); } void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update ) From 435b53c853f31cac95e178f4588017fa3de4454b Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sat, 14 Mar 2009 19:11:46 +0300 Subject: [PATCH 17/46] [7456] Batter check for items with delayed cooldown. This must solve problems with some still stuck until relogin items. --- src/game/Spell.cpp | 7 +++---- src/shared/revision_nr.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index df4530399..23795e56e 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -2567,12 +2567,11 @@ void Spell::SendSpellCooldown() Player* _player = (Player*)m_caster; - // mana/health potions, disabled by client - if (m_spellInfo->Category==SPELLCATEGORY_HEALTH_MANA_POTIONS) + // mana/health/etc potions, disabled by client (until combat out as declarate) + if (m_CastItem && m_CastItem->IsPotion()) { // need in some way provided data for Spell::finish SendCooldownEvent - if(m_CastItem) - _player->SetLastPotionId(m_CastItem->GetEntry()); + _player->SetLastPotionId(m_CastItem->GetEntry()); return; } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index d8329e68d..f81c4b84c 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7455" + #define REVISION_NR "7456" #endif // __REVISION_NR_H__ From 74006886e9af0599734a5d2abc25b34923418db5 Mon Sep 17 00:00:00 2001 From: Triply Date: Sat, 14 Mar 2009 20:20:28 +0100 Subject: [PATCH 18/46] [7457] Fixed set Bg raid leader to party or raid leader who entered Bg. Removed useless code from my previous patch. Signed-off-by: Triply --- src/game/BattleGround.cpp | 7 ++++++- src/game/Group.cpp | 19 ++++++++----------- src/shared/revision_nr.h | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 45ab6cf8d..1d0c34ad5 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -1162,7 +1162,12 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, plr->SetBattleGroundRaid(group, subgroup); } else - GetBgRaid(team)->AddMember(plr_guid, plr->GetName()); + { + group->AddMember(plr_guid, plr->GetName()); + if( Group* originalGroup = plr->GetOriginalGroup() ) + if( originalGroup->IsLeader(plr_guid) ) + group->ChangeLeader(plr_guid); + } } } diff --git a/src/game/Group.cpp b/src/game/Group.cpp index de26cb666..e6e01aa13 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -386,19 +386,16 @@ void Group::Disband(bool hideDestroy) continue; //we cannot call _removeMember because it would invalidate member iterator - if (player) + //if we are removing player from battleground raid + if( isBGGroup() ) + player->RemoveFromBattleGroundRaid(); + else { - //if we are removing player from battleground raid - if( isBGGroup() ) - player->RemoveFromBattleGroundRaid(); + //we can remove player who is in battleground from his original group + if( player->GetOriginalGroup() == this ) + player->SetOriginalGroup(NULL); else - { - //we can remove player who is in battleground from his original group - if( player->GetOriginalGroup() == this ) - player->SetOriginalGroup(NULL); - else - player->SetGroup(NULL); - } + player->SetGroup(NULL); } // quest related GO state dependent from raid membership diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index f81c4b84c..be55dc98e 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7456" + #define REVISION_NR "7457" #endif // __REVISION_NR_H__ From 9b1216f21c2ae40e4aeb43df31356fd26f436b93 Mon Sep 17 00:00:00 2001 From: =Neo2003 Date: Sat, 14 Mar 2009 23:14:11 +0300 Subject: [PATCH 19/46] [7458] Not reset/set some data at attack target switch that expected do at any target lost. Signed-off-by: VladimirMangos --- src/game/Unit.cpp | 24 ++++++++++++++---------- src/game/Unit.h | 2 +- src/shared/revision_nr.h | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index e933d29ae..4fb8ff6b0 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -7132,6 +7132,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack) if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE); + // in fighting already if (m_attacking) { if (m_attacking == victim) @@ -7145,7 +7146,16 @@ bool Unit::Attack(Unit *victim, bool meleeAttack) } return false; } - AttackStop(); + + // remove old target data + AttackStop(true); + } + // new battle + else + { + // set position before any AI calls/assistance + if(GetTypeId()==TYPEID_UNIT) + ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); } //Set our target @@ -7154,10 +7164,6 @@ bool Unit::Attack(Unit *victim, bool meleeAttack) if(meleeAttack) addUnitState(UNIT_STAT_MELEE_ATTACKING); - // set position before any AI calls/assistance - if(GetTypeId()==TYPEID_UNIT) - ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); - m_attacking = victim; m_attacking->_addAttacker(this); @@ -7184,7 +7190,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack) return true; } -bool Unit::AttackStop() +bool Unit::AttackStop(bool targetSwitch /*=false*/) { if (!m_attacking) return false; @@ -7201,11 +7207,9 @@ bool Unit::AttackStop() InterruptSpell(CURRENT_MELEE_SPELL); - if( GetTypeId()==TYPEID_UNIT ) - { - // reset call assistance + // reset only at real combat stop + if(!targetSwitch && GetTypeId()==TYPEID_UNIT ) ((Creature*)this)->SetNoCallAssistance(false); - } SendAttackStop(victim); diff --git a/src/game/Unit.h b/src/game/Unit.h index 633700600..2cdd76892 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -850,7 +850,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject } bool Attack(Unit *victim, bool meleeAttack); void CastStop(uint32 except_spellid = 0); - bool AttackStop(); + bool AttackStop(bool targetSwitch = false); void RemoveAllAttackers(); AttackerSet const& getAttackers() const { return m_attackers; } bool isAttackingPlayer() const; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index be55dc98e..e13fce7d4 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7457" + #define REVISION_NR "7458" #endif // __REVISION_NR_H__ From e4a5a471784dcdc805dc518fdac4c68d4489199e Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sat, 14 Mar 2009 23:28:38 +0300 Subject: [PATCH 20/46] [7459] Support case when movegen at own Finilize add another movegen. --- src/game/MotionMaster.cpp | 48 +++++++++++++++++++++------------------ src/shared/revision_nr.h | 2 +- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp index b2f99f968..ce20d5cd7 100644 --- a/src/game/MotionMaster.cpp +++ b/src/game/MotionMaster.cpp @@ -43,8 +43,8 @@ MotionMaster::Initialize() while(!empty()) { MovementGenerator *curr = top(); - curr->Finalize(*i_owner); pop(); + curr->Finalize(*i_owner); if( !isStatic( curr ) ) delete curr; } @@ -66,8 +66,8 @@ MotionMaster::~MotionMaster() while(!empty()) { MovementGenerator *curr = top(); - curr->Finalize(*i_owner); pop(); + curr->Finalize(*i_owner); if( !isStatic( curr ) ) delete curr; } @@ -117,8 +117,8 @@ MotionMaster::DirectClean(bool reset) while( !empty() && size() > 1 ) { MovementGenerator *curr = top(); - curr->Finalize(*i_owner); pop(); + curr->Finalize(*i_owner); if( !isStatic( curr ) ) delete curr; } @@ -142,8 +142,8 @@ MotionMaster::DelayedClean() while( !empty() && size() > 1 ) { MovementGenerator *curr = top(); - curr->Finalize(*i_owner); pop(); + curr->Finalize(*i_owner); if( !isStatic( curr ) ) m_expList->push_back(curr); } @@ -156,23 +156,26 @@ MotionMaster::DirectExpire(bool reset) return; MovementGenerator *curr = top(); - curr->Finalize(*i_owner); pop(); + // also drop stored under top() targeted motions + while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE ) + { + MovementGenerator *temp = top(); + pop(); + temp ->Finalize(*i_owner); + delete temp; + } + + // it can add another motions instead + curr->Finalize(*i_owner); + if( !isStatic(curr) ) delete curr; - assert( !empty() ); - while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE ) - { - // Should check if target is still valid? If not valid it will crash. - curr = top(); - curr->Finalize(*i_owner); - pop(); - delete curr; - } if( empty() ) Initialize(); + if (reset) top()->Reset(*i_owner); } @@ -183,23 +186,24 @@ MotionMaster::DelayedExpire() return; MovementGenerator *curr = top(); - curr->Finalize(*i_owner); pop(); if(!m_expList) m_expList = new ExpireList(); - if( !isStatic(curr) ) - m_expList->push_back(curr); - + // also drop stored under top() targeted motions while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE ) { - // Should check if target is still valid? If not valid it will crash. - curr = top(); - curr->Finalize(*i_owner); + MovementGenerator *temp = top(); pop(); - m_expList->push_back(curr); + temp ->Finalize(*i_owner); + m_expList->push_back(temp ); } + + curr->Finalize(*i_owner); + + if( !isStatic(curr) ) + m_expList->push_back(curr); } void MotionMaster::MoveIdle() diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index e13fce7d4..de966162a 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7458" + #define REVISION_NR "7459" #endif // __REVISION_NR_H__ From 7dd997617eaa778c880b9828032f1c94166a6d11 Mon Sep 17 00:00:00 2001 From: Triply Date: Sat, 14 Mar 2009 22:31:10 +0100 Subject: [PATCH 21/46] [7460] Fixed possible cheating in rated arena by ressurection after relog. Fix: Do not allow to remove insignia from players in arena! Fixed ending arena match when last player of team logs out. Signed-off-by: Triply --- src/game/BattleGround.cpp | 11 ++++++++--- src/game/Player.cpp | 2 +- src/shared/revision_nr.h | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 1d0c34ad5..2dfd9c557 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -1200,7 +1200,11 @@ void BattleGround::EventPlayerLoggedOut(Player* player) if( isBattleGround() ) EventPlayerDroppedFlag(player); else - CheckArenaWinConditions(); + { + //1 player is logging out, if it is the last, then end arena! + if( GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())) ) + EndBattleGround(GetOtherTeam(player->GetTeam())); + } } } @@ -1668,8 +1672,9 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer ) } } - // to be able to remove insignia - player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE ); + // to be able to remove insignia -- ONLY IN BattleGrounds + if( !isArena() ) + player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE ); } // return the player's team based on battlegroundplayer info diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 1dd3016e1..142bc30e0 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -4044,7 +4044,7 @@ void Player::CreateCorpse() flags |= CORPSE_FLAG_HIDE_HELM; if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) flags |= CORPSE_FLAG_HIDE_CLOAK; - if(InBattleGround()) + if(InBattleGround() && !InArena()) flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, flags ); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index de966162a..7a62db96d 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7459" + #define REVISION_NR "7460" #endif // __REVISION_NR_H__ From 991376067d58adfa8f08489f1d3232569ed9ad87 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sun, 15 Mar 2009 02:51:07 +0300 Subject: [PATCH 22/46] Replace hack code in Spell::EffectOpenLock by generic way for check lock key items/skills --- src/game/SharedDefines.h | 16 +++++ src/game/Spell.cpp | 24 +++----- src/game/SpellEffects.cpp | 122 +++++++++++++++++++------------------- 3 files changed, 86 insertions(+), 76 deletions(-) diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 981444368..3ea0cf44b 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -1696,6 +1696,8 @@ inline uint8 ClassByQuestSort(int32 QuestSort) enum SkillType { + SKILL_NONE = 0, + SKILL_FROST = 6, SKILL_FIRE = 8, SKILL_ARMS = 26, @@ -1850,6 +1852,20 @@ enum SkillType #define MAX_SKILL_TYPE 789 +inline SkillType SkillByLockType(LockType locktype) +{ + switch(locktype) + { + case LOCKTYPE_PICKLOCK: return SKILL_LOCKPICKING; + case LOCKTYPE_HERBALISM: return SKILL_HERBALISM; + case LOCKTYPE_MINING: return SKILL_MINING; + case LOCKTYPE_FISHING: return SKILL_FISHING; + case LOCKTYPE_INSCRIPTION: return SKILL_INSCRIPTION; + default: break; + } + return SKILL_NONE; +} + inline uint32 SkillByQuestSort(int32 QuestSort) { switch(QuestSort) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 23795e56e..c440aee50 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -4172,6 +4172,7 @@ uint8 Spell::CanCast(bool strict) { // check for lock - key pair (checked by client also, just prevent cheating bool ok_key = false; + bool req_key = false; for(int it = 0; it < 8; ++it) { switch(lockInfo->Type[it]) @@ -4180,6 +4181,7 @@ uint8 Spell::CanCast(bool strict) break; case LOCK_KEY_ITEM: { + req_key = true; if(lockInfo->Index[it]) { if(m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[it]) @@ -4189,30 +4191,22 @@ uint8 Spell::CanCast(bool strict) } case LOCK_KEY_SKILL: { + req_key = true; if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->Index[it]) break; - switch(lockInfo->Index[it]) - { - case LOCKTYPE_HERBALISM: - if(((Player*)m_caster)->HasSkill(SKILL_HERBALISM)) - ok_key =true; - break; - case LOCKTYPE_MINING: - if(((Player*)m_caster)->HasSkill(SKILL_MINING)) - ok_key =true; - break; - default: - ok_key =true; - break; - } + SkillType skill = SkillByLockType(LockType(lockInfo->Index[it])); + if(skill==SKILL_NONE) + ok_key =true; + else if(((Player*)m_caster)->HasSkill(skill)) + ok_key =true; } } if(ok_key) break; } - if(!ok_key) + if(!ok_key && req_key) return SPELL_FAILED_BAD_TARGETS; } diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 99c0811ba..9f7054e2b 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -2943,7 +2943,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype) player->SendLoot(guid, loottype); } -void Spell::EffectOpenLock(uint32 /*i*/) +void Spell::EffectOpenLock(uint32 effIndex) { if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) { @@ -2953,7 +2953,6 @@ void Spell::EffectOpenLock(uint32 /*i*/) Player* player = (Player*)m_caster; - LootType loottype = LOOT_CORPSE; uint32 lockId = 0; uint64 guid = 0; @@ -3002,7 +3001,7 @@ void Spell::EffectOpenLock(uint32 /*i*/) if(!lockId) // possible case for GO and maybe for items. { - SendLoot(guid, loottype); + SendLoot(guid, LOOT_CORPSE); return; } @@ -3017,74 +3016,75 @@ void Spell::EffectOpenLock(uint32 /*i*/) return; } - // check key - for(int i = 0; i < 8; ++i) + bool reqKey = false; // some locks not have reqs + + for(int j = 0; j < 8; ++j) { - // Type==1 This means lockInfo->Index[i] is an item - if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i]) + switch(lockInfo->Type[j]) { - SendLoot(guid, loottype); - return; + // check key item (many fit cases can be) + case LOCK_KEY_ITEM: + if(lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[j]) + { + SendLoot(guid, LOOT_CORPSE); + return; + } + reqKey = true; + break; + // check key skill (only single first fit case can be) + case LOCK_KEY_SKILL: + { + reqKey = true; + + // wrong locktype, skip + if(uint32(m_spellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j]) + continue; + + SkillType skillId = SkillByLockType(LockType(lockInfo->Index[j])); + + if ( skillId != SKILL_NONE ) + { + // skill bonus provided by casting spell (mostly item spells) + uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1); + uint32 reqSkillValue = lockInfo->Skill[j]; + + if ( player->GetSkillValue(skillId) + spellSkillBonus < reqSkillValue ) + { + SendCastResult(SPELL_FAILED_LOW_CASTLEVEL); + return; + } + + // update skill if really known + if(uint32 SkillValue = player->GetPureSkillValue(skillId)) + { + if(gameObjTarget) + { + // Allow one skill-up until respawned + if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) && + player->UpdateGatherSkill(skillId, SkillValue, reqSkillValue) ) + gameObjTarget->AddToSkillupList( player->GetGUIDLow() ); + } + else if(itemTarget) + { + // Do one skill-up + player->UpdateGatherSkill(skillId, SkillValue, reqSkillValue); + } + } + } + + SendLoot(guid, LOOT_SKINNING); + return; + } } } - uint32 SkillId = 0; - // Check and skill-up skill - if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL ) - SkillId = m_spellInfo->EffectMiscValue[1]; - // pickpocketing spells - else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK ) - SkillId = SKILL_LOCKPICKING; - - // skill bonus provided by casting spell (mostly item spells) - uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1); - - uint32 reqSkillValue = lockInfo->Skill[0]; - - if(lockInfo->Skill[1]) // required pick lock skill applying - { - if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?) - { - SendCastResult(SPELL_FAILED_FIZZLE); - return; - } - - reqSkillValue = lockInfo->Skill[1]; - } - else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target + if(reqKey) { SendCastResult(SPELL_FAILED_BAD_TARGETS); return; } - if ( SkillId ) - { - loottype = LOOT_SKINNING; - if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue ) - { - SendCastResult(SPELL_FAILED_LOW_CASTLEVEL); - return; - } - - // update skill if really known - if(uint32 SkillValue = player->GetPureSkillValue(SkillId)) - { - if(gameObjTarget) - { - // Allow one skill-up until respawned - if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) && - player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) ) - gameObjTarget->AddToSkillupList( player->GetGUIDLow() ); - } - else if(itemTarget) - { - // Do one skill-up - player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue); - } - } - } - - SendLoot(guid, loottype); + SendLoot(guid, LOOT_SKINNING); } void Spell::EffectSummonChangeItem(uint32 i) From afe5eb3e1da6f1e660959a304f8affd797f9033f Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sun, 15 Mar 2009 23:23:45 +0300 Subject: [PATCH 23/46] [7461] Give proper honor amount at item based AddHonor spells cast. --- src/game/SpellEffects.cpp | 17 +++++++++++++---- src/shared/revision_nr.h | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 9f7054e2b..40a066997 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -3809,17 +3809,26 @@ void Spell::EffectAddHonor(uint32 /*i*/) if(unitTarget->GetTypeId() != TYPEID_PLAYER) return; - uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage); - sLog.outDebug("SpellEffect::AddHonor called for spell_id %u, that rewards %u honor points to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow()); + // not scale value for item based reward (/10 value expected) + if(m_CastItem) + { + ((Player*)unitTarget)->RewardHonor(NULL, 1, damage/10); + sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),((Player*)unitTarget)->GetGUIDLow()); + return; + } // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80 - if( damage <= 50 ) + if( damage <= 50) + { + uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage); ((Player*)unitTarget)->RewardHonor(NULL, 1, honor_reward); + sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow()); + } else { //maybe we have correct honor_gain in damage already ((Player*)unitTarget)->RewardHonor(NULL, 1, damage); - sLog.outError("SpellEffect::AddHonor called for spell_id %u, that rewards %d * honor for one honorable kill and it is too much (%u of honor) for player: %u", m_spellInfo->Id, damage, honor_reward, ((Player*)unitTarget)->GetGUIDLow()); + sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow()); } } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 7a62db96d..6597e9892 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7460" + #define REVISION_NR "7461" #endif // __REVISION_NR_H__ From 57c415f5e15859c18ea003e6df1b90515e627fff Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sun, 15 Mar 2009 23:35:27 +0300 Subject: [PATCH 24/46] [7462] Lost part of "[7456] Batter check for items with delayed cooldown.". Now not only mana/health potion will restore cooldown counting at combat end. --- src/game/Spell.cpp | 4 ++-- src/shared/revision_nr.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index c440aee50..1203b2653 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -2770,8 +2770,8 @@ void Spell::finish(bool ok) ((Player*)m_caster)->ClearComboPoints(); } - // mana/health potions, disabled by client, send event "not in combat" - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->Category == SPELLCATEGORY_HEALTH_MANA_POTIONS) + // potions disabled by client, send event "not in combat" if need + if (m_caster->GetTypeId() == TYPEID_PLAYER) ((Player*)m_caster)->UpdatePotionCooldown(this); // call triggered spell only at successful cast (after clear combo points -> for add some if need) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 6597e9892..1504b5a01 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7461" + #define REVISION_NR "7462" #endif // __REVISION_NR_H__ From 9def5df2d7252dcf8586c49c67d586eb2ed9a5ce Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sun, 15 Mar 2009 23:55:34 +0300 Subject: [PATCH 25/46] [7463] Make basic preparations for replace 0 as ok spell cast value by more correct value. Currently 0 used ast OK value for spell cast checks BUT 0 = SPELL_FAILED_AFFECTING_COMBAT So another values need used. This required lot code changes. This is first step. --- src/game/SharedDefines.h | 187 +++++++++++++++++++++++++++++++++++++++ src/game/Spell.h | 1 + src/game/SpellMgr.h | 186 -------------------------------------- src/shared/revision_nr.h | 2 +- 4 files changed, 189 insertions(+), 187 deletions(-) diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 3ea0cf44b..6ef7b646b 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -681,6 +681,193 @@ enum SpellEffects TOTAL_SPELL_EFFECTS = 160 }; +enum SpellCastResult +{ + SPELL_CAST_OK = 0, //FIXME: used as success result currently + SPELL_FAILED_AFFECTING_COMBAT = 0, //FIXME: used as success result currently + SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1, + SPELL_FAILED_ALREADY_AT_FULL_MANA = 2, + SPELL_FAILED_ALREADY_AT_FULL_POWER = 3, + SPELL_FAILED_ALREADY_BEING_TAMED = 4, + SPELL_FAILED_ALREADY_HAVE_CHARM = 5, + SPELL_FAILED_ALREADY_HAVE_SUMMON = 6, + SPELL_FAILED_ALREADY_OPEN = 7, + SPELL_FAILED_AURA_BOUNCED = 8, + SPELL_FAILED_AUTOTRACK_INTERRUPTED = 9, + SPELL_FAILED_BAD_IMPLICIT_TARGETS = 10, + SPELL_FAILED_BAD_TARGETS = 11, + SPELL_FAILED_CANT_BE_CHARMED = 12, + SPELL_FAILED_CANT_BE_DISENCHANTED = 13, + SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 14, + SPELL_FAILED_CANT_BE_MILLED = 15, + SPELL_FAILED_CANT_BE_PROSPECTED = 16, + SPELL_FAILED_CANT_CAST_ON_TAPPED = 17, + SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 18, + SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 19, + SPELL_FAILED_CANT_STEALTH = 20, + SPELL_FAILED_CASTER_AURASTATE = 21, + SPELL_FAILED_CASTER_DEAD = 22, + SPELL_FAILED_CHARMED = 23, + SPELL_FAILED_CHEST_IN_USE = 24, + SPELL_FAILED_CONFUSED = 25, + SPELL_FAILED_DONT_REPORT = 26, + SPELL_FAILED_EQUIPPED_ITEM = 27, + SPELL_FAILED_EQUIPPED_ITEM_CLASS = 28, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 29, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 30, + SPELL_FAILED_ERROR = 31, + SPELL_FAILED_FIZZLE = 32, + SPELL_FAILED_FLEEING = 33, + SPELL_FAILED_FOOD_LOWLEVEL = 34, + SPELL_FAILED_HIGHLEVEL = 35, + SPELL_FAILED_HUNGER_SATIATED = 36, + SPELL_FAILED_IMMUNE = 37, + SPELL_FAILED_INCORRECT_AREA = 38, + SPELL_FAILED_INTERRUPTED = 39, + SPELL_FAILED_INTERRUPTED_COMBAT = 40, + SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 41, + SPELL_FAILED_ITEM_GONE = 42, + SPELL_FAILED_ITEM_NOT_FOUND = 43, + SPELL_FAILED_ITEM_NOT_READY = 44, + SPELL_FAILED_LEVEL_REQUIREMENT = 45, + SPELL_FAILED_LINE_OF_SIGHT = 46, + SPELL_FAILED_LOWLEVEL = 47, + SPELL_FAILED_LOW_CASTLEVEL = 48, + SPELL_FAILED_MAINHAND_EMPTY = 49, + SPELL_FAILED_MOVING = 50, + SPELL_FAILED_NEED_AMMO = 51, + SPELL_FAILED_NEED_AMMO_POUCH = 52, + SPELL_FAILED_NEED_EXOTIC_AMMO = 53, + SPELL_FAILED_NEED_MORE_ITEMS = 54, + SPELL_FAILED_NOPATH = 55, + SPELL_FAILED_NOT_BEHIND = 56, + SPELL_FAILED_NOT_FISHABLE = 57, + SPELL_FAILED_NOT_FLYING = 58, + SPELL_FAILED_NOT_HERE = 59, + SPELL_FAILED_NOT_INFRONT = 60, + SPELL_FAILED_NOT_IN_CONTROL = 61, + SPELL_FAILED_NOT_KNOWN = 62, + SPELL_FAILED_NOT_MOUNTED = 63, + SPELL_FAILED_NOT_ON_TAXI = 64, + SPELL_FAILED_NOT_ON_TRANSPORT = 65, + SPELL_FAILED_NOT_READY = 66, + SPELL_FAILED_NOT_SHAPESHIFT = 67, + SPELL_FAILED_NOT_STANDING = 68, + SPELL_FAILED_NOT_TRADEABLE = 69, + SPELL_FAILED_NOT_TRADING = 70, + SPELL_FAILED_NOT_UNSHEATHED = 71, + SPELL_FAILED_NOT_WHILE_GHOST = 72, + SPELL_FAILED_NOT_WHILE_LOOTING = 73, + SPELL_FAILED_NO_AMMO = 74, + SPELL_FAILED_NO_CHARGES_REMAIN = 75, + SPELL_FAILED_NO_CHAMPION = 76, + SPELL_FAILED_NO_COMBO_POINTS = 77, + SPELL_FAILED_NO_DUELING = 78, + SPELL_FAILED_NO_ENDURANCE = 79, + SPELL_FAILED_NO_FISH = 80, + SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 81, + SPELL_FAILED_NO_MOUNTS_ALLOWED = 82, + SPELL_FAILED_NO_PET = 83, + SPELL_FAILED_NO_POWER = 84, + SPELL_FAILED_NOTHING_TO_DISPEL = 85, + SPELL_FAILED_NOTHING_TO_STEAL = 86, + SPELL_FAILED_ONLY_ABOVEWATER = 87, + SPELL_FAILED_ONLY_DAYTIME = 88, + SPELL_FAILED_ONLY_INDOORS = 89, + SPELL_FAILED_ONLY_MOUNTED = 90, + SPELL_FAILED_ONLY_NIGHTTIME = 91, + SPELL_FAILED_ONLY_OUTDOORS = 92, + SPELL_FAILED_ONLY_SHAPESHIFT = 93, + SPELL_FAILED_ONLY_STEALTHED = 94, + SPELL_FAILED_ONLY_UNDERWATER = 95, + SPELL_FAILED_OUT_OF_RANGE = 96, + SPELL_FAILED_PACIFIED = 97, + SPELL_FAILED_POSSESSED = 98, + SPELL_FAILED_REAGENTS = 99, + SPELL_FAILED_REQUIRES_AREA = 100, + SPELL_FAILED_REQUIRES_SPELL_FOCUS = 101, + SPELL_FAILED_ROOTED = 102, + SPELL_FAILED_SILENCED = 103, + SPELL_FAILED_SPELL_IN_PROGRESS = 104, + SPELL_FAILED_SPELL_LEARNED = 105, + SPELL_FAILED_SPELL_UNAVAILABLE = 106, + SPELL_FAILED_STUNNED = 107, + SPELL_FAILED_TARGETS_DEAD = 108, + SPELL_FAILED_TARGET_AFFECTING_COMBAT = 109, + SPELL_FAILED_TARGET_AURASTATE = 110, + SPELL_FAILED_TARGET_DUELING = 111, + SPELL_FAILED_TARGET_ENEMY = 112, + SPELL_FAILED_TARGET_ENRAGED = 113, + SPELL_FAILED_TARGET_FRIENDLY = 114, + SPELL_FAILED_TARGET_IN_COMBAT = 115, + SPELL_FAILED_TARGET_IS_PLAYER = 116, + SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 117, + SPELL_FAILED_TARGET_NOT_DEAD = 118, + SPELL_FAILED_TARGET_NOT_IN_PARTY = 119, + SPELL_FAILED_TARGET_NOT_LOOTED = 120, + SPELL_FAILED_TARGET_NOT_PLAYER = 121, + SPELL_FAILED_TARGET_NO_POCKETS = 122, + SPELL_FAILED_TARGET_NO_WEAPONS = 123, + SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 124, + SPELL_FAILED_TARGET_UNSKINNABLE = 125, + SPELL_FAILED_THIRST_SATIATED = 126, + SPELL_FAILED_TOO_CLOSE = 127, + SPELL_FAILED_TOO_MANY_OF_ITEM = 128, + SPELL_FAILED_TOTEM_CATEGORY = 129, + SPELL_FAILED_TOTEMS = 130, + SPELL_FAILED_TRY_AGAIN = 131, + SPELL_FAILED_UNIT_NOT_BEHIND = 132, + SPELL_FAILED_UNIT_NOT_INFRONT = 133, + SPELL_FAILED_WRONG_PET_FOOD = 134, + SPELL_FAILED_NOT_WHILE_FATIGUED = 135, + SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 136, + SPELL_FAILED_NOT_WHILE_TRADING = 137, + SPELL_FAILED_TARGET_NOT_IN_RAID = 138, + SPELL_FAILED_TARGET_FREEFORALL = 139, + SPELL_FAILED_NO_EDIBLE_CORPSES = 140, + SPELL_FAILED_ONLY_BATTLEGROUNDS = 141, + SPELL_FAILED_TARGET_NOT_GHOST = 142, + SPELL_FAILED_TRANSFORM_UNUSABLE = 143, + SPELL_FAILED_WRONG_WEATHER = 144, + SPELL_FAILED_DAMAGE_IMMUNE = 145, + SPELL_FAILED_PREVENTED_BY_MECHANIC = 146, + SPELL_FAILED_PLAY_TIME = 147, + SPELL_FAILED_REPUTATION = 148, + SPELL_FAILED_MIN_SKILL = 149, + SPELL_FAILED_NOT_IN_ARENA = 150, + SPELL_FAILED_NOT_ON_SHAPESHIFT = 151, + SPELL_FAILED_NOT_ON_STEALTHED = 152, + SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 153, + SPELL_FAILED_NOT_ON_MOUNTED = 154, + SPELL_FAILED_TOO_SHALLOW = 155, + SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 156, + SPELL_FAILED_TARGET_IS_TRIVIAL = 157, + SPELL_FAILED_BM_OR_INVISGOD = 158, + SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 159, + SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 160, + SPELL_FAILED_NOT_IDLE = 161, + SPELL_FAILED_NOT_INACTIVE = 162, + SPELL_FAILED_PARTIAL_PLAYTIME = 163, + SPELL_FAILED_NO_PLAYTIME = 164, + SPELL_FAILED_NOT_IN_BATTLEGROUND = 165, + SPELL_FAILED_NOT_IN_RAID_INSTANCE = 166, + SPELL_FAILED_ONLY_IN_ARENA = 167, + SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 168, + SPELL_FAILED_ON_USE_ENCHANT = 169, + SPELL_FAILED_NOT_ON_GROUND = 170, + SPELL_FAILED_CUSTOM_ERROR = 171, + SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 172, + SPELL_FAILED_TOO_MANY_SOCKETS = 173, + SPELL_FAILED_INVALID_GLYPH = 174, + SPELL_FAILED_UNIQUE_GLYPH = 175, + SPELL_FAILED_GLYPH_SOCKET_LOCKED = 176, + SPELL_FAILED_NO_VALID_TARGETS = 177, + SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178, + SPELL_FAILED_NOT_IN_BARBERSHOP = 179, + SPELL_FAILED_FISHING_TOO_LOW = 180, + SPELL_FAILED_UNKNOWN = 181 +}; + // Spell aura states enum AuraState { // (C) used in caster aura state (T) used in target aura state diff --git a/src/game/Spell.h b/src/game/Spell.h index 6b33e636f..5e030cee5 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -20,6 +20,7 @@ #define __SPELL_H #include "GridDefines.h" +#include "SharedDefines.h" class WorldSession; class Unit; diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 952b42c19..5e300b6f5 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -37,192 +37,6 @@ class Spell; extern SQLStorage sSpellThreatStore; -enum SpellFailedReason -{ - SPELL_FAILED_AFFECTING_COMBAT = 0, - SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1, - SPELL_FAILED_ALREADY_AT_FULL_MANA = 2, - SPELL_FAILED_ALREADY_AT_FULL_POWER = 3, - SPELL_FAILED_ALREADY_BEING_TAMED = 4, - SPELL_FAILED_ALREADY_HAVE_CHARM = 5, - SPELL_FAILED_ALREADY_HAVE_SUMMON = 6, - SPELL_FAILED_ALREADY_OPEN = 7, - SPELL_FAILED_AURA_BOUNCED = 8, - SPELL_FAILED_AUTOTRACK_INTERRUPTED = 9, - SPELL_FAILED_BAD_IMPLICIT_TARGETS = 10, - SPELL_FAILED_BAD_TARGETS = 11, - SPELL_FAILED_CANT_BE_CHARMED = 12, - SPELL_FAILED_CANT_BE_DISENCHANTED = 13, - SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 14, - SPELL_FAILED_CANT_BE_MILLED = 15, - SPELL_FAILED_CANT_BE_PROSPECTED = 16, - SPELL_FAILED_CANT_CAST_ON_TAPPED = 17, - SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 18, - SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 19, - SPELL_FAILED_CANT_STEALTH = 20, - SPELL_FAILED_CASTER_AURASTATE = 21, - SPELL_FAILED_CASTER_DEAD = 22, - SPELL_FAILED_CHARMED = 23, - SPELL_FAILED_CHEST_IN_USE = 24, - SPELL_FAILED_CONFUSED = 25, - SPELL_FAILED_DONT_REPORT = 26, - SPELL_FAILED_EQUIPPED_ITEM = 27, - SPELL_FAILED_EQUIPPED_ITEM_CLASS = 28, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 29, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 30, - SPELL_FAILED_ERROR = 31, - SPELL_FAILED_FIZZLE = 32, - SPELL_FAILED_FLEEING = 33, - SPELL_FAILED_FOOD_LOWLEVEL = 34, - SPELL_FAILED_HIGHLEVEL = 35, - SPELL_FAILED_HUNGER_SATIATED = 36, - SPELL_FAILED_IMMUNE = 37, - SPELL_FAILED_INCORRECT_AREA = 38, - SPELL_FAILED_INTERRUPTED = 39, - SPELL_FAILED_INTERRUPTED_COMBAT = 40, - SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 41, - SPELL_FAILED_ITEM_GONE = 42, - SPELL_FAILED_ITEM_NOT_FOUND = 43, - SPELL_FAILED_ITEM_NOT_READY = 44, - SPELL_FAILED_LEVEL_REQUIREMENT = 45, - SPELL_FAILED_LINE_OF_SIGHT = 46, - SPELL_FAILED_LOWLEVEL = 47, - SPELL_FAILED_LOW_CASTLEVEL = 48, - SPELL_FAILED_MAINHAND_EMPTY = 49, - SPELL_FAILED_MOVING = 50, - SPELL_FAILED_NEED_AMMO = 51, - SPELL_FAILED_NEED_AMMO_POUCH = 52, - SPELL_FAILED_NEED_EXOTIC_AMMO = 53, - SPELL_FAILED_NEED_MORE_ITEMS = 54, - SPELL_FAILED_NOPATH = 55, - SPELL_FAILED_NOT_BEHIND = 56, - SPELL_FAILED_NOT_FISHABLE = 57, - SPELL_FAILED_NOT_FLYING = 58, - SPELL_FAILED_NOT_HERE = 59, - SPELL_FAILED_NOT_INFRONT = 60, - SPELL_FAILED_NOT_IN_CONTROL = 61, - SPELL_FAILED_NOT_KNOWN = 62, - SPELL_FAILED_NOT_MOUNTED = 63, - SPELL_FAILED_NOT_ON_TAXI = 64, - SPELL_FAILED_NOT_ON_TRANSPORT = 65, - SPELL_FAILED_NOT_READY = 66, - SPELL_FAILED_NOT_SHAPESHIFT = 67, - SPELL_FAILED_NOT_STANDING = 68, - SPELL_FAILED_NOT_TRADEABLE = 69, - SPELL_FAILED_NOT_TRADING = 70, - SPELL_FAILED_NOT_UNSHEATHED = 71, - SPELL_FAILED_NOT_WHILE_GHOST = 72, - SPELL_FAILED_NOT_WHILE_LOOTING = 73, - SPELL_FAILED_NO_AMMO = 74, - SPELL_FAILED_NO_CHARGES_REMAIN = 75, - SPELL_FAILED_NO_CHAMPION = 76, - SPELL_FAILED_NO_COMBO_POINTS = 77, - SPELL_FAILED_NO_DUELING = 78, - SPELL_FAILED_NO_ENDURANCE = 79, - SPELL_FAILED_NO_FISH = 80, - SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 81, - SPELL_FAILED_NO_MOUNTS_ALLOWED = 82, - SPELL_FAILED_NO_PET = 83, - SPELL_FAILED_NO_POWER = 84, - SPELL_FAILED_NOTHING_TO_DISPEL = 85, - SPELL_FAILED_NOTHING_TO_STEAL = 86, - SPELL_FAILED_ONLY_ABOVEWATER = 87, - SPELL_FAILED_ONLY_DAYTIME = 88, - SPELL_FAILED_ONLY_INDOORS = 89, - SPELL_FAILED_ONLY_MOUNTED = 90, - SPELL_FAILED_ONLY_NIGHTTIME = 91, - SPELL_FAILED_ONLY_OUTDOORS = 92, - SPELL_FAILED_ONLY_SHAPESHIFT = 93, - SPELL_FAILED_ONLY_STEALTHED = 94, - SPELL_FAILED_ONLY_UNDERWATER = 95, - SPELL_FAILED_OUT_OF_RANGE = 96, - SPELL_FAILED_PACIFIED = 97, - SPELL_FAILED_POSSESSED = 98, - SPELL_FAILED_REAGENTS = 99, - SPELL_FAILED_REQUIRES_AREA = 100, - SPELL_FAILED_REQUIRES_SPELL_FOCUS = 101, - SPELL_FAILED_ROOTED = 102, - SPELL_FAILED_SILENCED = 103, - SPELL_FAILED_SPELL_IN_PROGRESS = 104, - SPELL_FAILED_SPELL_LEARNED = 105, - SPELL_FAILED_SPELL_UNAVAILABLE = 106, - SPELL_FAILED_STUNNED = 107, - SPELL_FAILED_TARGETS_DEAD = 108, - SPELL_FAILED_TARGET_AFFECTING_COMBAT = 109, - SPELL_FAILED_TARGET_AURASTATE = 110, - SPELL_FAILED_TARGET_DUELING = 111, - SPELL_FAILED_TARGET_ENEMY = 112, - SPELL_FAILED_TARGET_ENRAGED = 113, - SPELL_FAILED_TARGET_FRIENDLY = 114, - SPELL_FAILED_TARGET_IN_COMBAT = 115, - SPELL_FAILED_TARGET_IS_PLAYER = 116, - SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 117, - SPELL_FAILED_TARGET_NOT_DEAD = 118, - SPELL_FAILED_TARGET_NOT_IN_PARTY = 119, - SPELL_FAILED_TARGET_NOT_LOOTED = 120, - SPELL_FAILED_TARGET_NOT_PLAYER = 121, - SPELL_FAILED_TARGET_NO_POCKETS = 122, - SPELL_FAILED_TARGET_NO_WEAPONS = 123, - SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 124, - SPELL_FAILED_TARGET_UNSKINNABLE = 125, - SPELL_FAILED_THIRST_SATIATED = 126, - SPELL_FAILED_TOO_CLOSE = 127, - SPELL_FAILED_TOO_MANY_OF_ITEM = 128, - SPELL_FAILED_TOTEM_CATEGORY = 129, - SPELL_FAILED_TOTEMS = 130, - SPELL_FAILED_TRY_AGAIN = 131, - SPELL_FAILED_UNIT_NOT_BEHIND = 132, - SPELL_FAILED_UNIT_NOT_INFRONT = 133, - SPELL_FAILED_WRONG_PET_FOOD = 134, - SPELL_FAILED_NOT_WHILE_FATIGUED = 135, - SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 136, - SPELL_FAILED_NOT_WHILE_TRADING = 137, - SPELL_FAILED_TARGET_NOT_IN_RAID = 138, - SPELL_FAILED_TARGET_FREEFORALL = 139, - SPELL_FAILED_NO_EDIBLE_CORPSES = 140, - SPELL_FAILED_ONLY_BATTLEGROUNDS = 141, - SPELL_FAILED_TARGET_NOT_GHOST = 142, - SPELL_FAILED_TRANSFORM_UNUSABLE = 143, - SPELL_FAILED_WRONG_WEATHER = 144, - SPELL_FAILED_DAMAGE_IMMUNE = 145, - SPELL_FAILED_PREVENTED_BY_MECHANIC = 146, - SPELL_FAILED_PLAY_TIME = 147, - SPELL_FAILED_REPUTATION = 148, - SPELL_FAILED_MIN_SKILL = 149, - SPELL_FAILED_NOT_IN_ARENA = 150, - SPELL_FAILED_NOT_ON_SHAPESHIFT = 151, - SPELL_FAILED_NOT_ON_STEALTHED = 152, - SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 153, - SPELL_FAILED_NOT_ON_MOUNTED = 154, - SPELL_FAILED_TOO_SHALLOW = 155, - SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 156, - SPELL_FAILED_TARGET_IS_TRIVIAL = 157, - SPELL_FAILED_BM_OR_INVISGOD = 158, - SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 159, - SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 160, - SPELL_FAILED_NOT_IDLE = 161, - SPELL_FAILED_NOT_INACTIVE = 162, - SPELL_FAILED_PARTIAL_PLAYTIME = 163, - SPELL_FAILED_NO_PLAYTIME = 164, - SPELL_FAILED_NOT_IN_BATTLEGROUND = 165, - SPELL_FAILED_NOT_IN_RAID_INSTANCE = 166, - SPELL_FAILED_ONLY_IN_ARENA = 167, - SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 168, - SPELL_FAILED_ON_USE_ENCHANT = 169, - SPELL_FAILED_NOT_ON_GROUND = 170, - SPELL_FAILED_CUSTOM_ERROR = 171, - SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 172, - SPELL_FAILED_TOO_MANY_SOCKETS = 173, - SPELL_FAILED_INVALID_GLYPH = 174, - SPELL_FAILED_UNIQUE_GLYPH = 175, - SPELL_FAILED_GLYPH_SOCKET_LOCKED = 176, - SPELL_FAILED_NO_VALID_TARGETS = 177, - SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178, - SPELL_FAILED_NOT_IN_BARBERSHOP = 179, - SPELL_FAILED_FISHING_TOO_LOW = 180, - SPELL_FAILED_UNKNOWN = 181 -}; - // only used in code enum SpellCategories { diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 1504b5a01..12446a513 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7462" + #define REVISION_NR "7463" #endif // __REVISION_NR_H__ From 4aaf758ab7da3ef4ed962f0fedc7fab3a9fe2348 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 00:41:38 +0300 Subject: [PATCH 26/46] [7464] Move check of spell using for lock open to single function. Remove more hacks. --- src/game/Spell.cpp | 179 +++++++++++++---------------- src/game/Spell.h | 1 + src/game/SpellEffects.cpp | 109 +++++------------- src/shared/Database/DBCStructure.h | 10 +- src/shared/revision_nr.h | 2 +- 5 files changed, 115 insertions(+), 186 deletions(-) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 1203b2653..50b322b06 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -4161,114 +4161,31 @@ uint8 Spell::CanCast(bool strict) return SPELL_FAILED_TRY_AGAIN; // get the lock entry - LockEntry const *lockInfo = NULL; + uint32 lockId = 0; if (GameObject* go=m_targets.getGOTarget()) - lockInfo = sLockStore.LookupEntry(go->GetLockId()); + lockId = go->GetLockId(); else if(Item* itm=m_targets.getItemTarget()) - lockInfo = sLockStore.LookupEntry(itm->GetProto()->LockID); + lockId = itm->GetProto()->LockID; + + SkillType skillId =SKILL_NONE; + int32 reqSkillValue = 0; + int32 skillValue = 0; // check lock compatibility - if (lockInfo) - { - // check for lock - key pair (checked by client also, just prevent cheating - bool ok_key = false; - bool req_key = false; - for(int it = 0; it < 8; ++it) - { - switch(lockInfo->Type[it]) - { - case LOCK_KEY_NONE: - break; - case LOCK_KEY_ITEM: - { - req_key = true; - if(lockInfo->Index[it]) - { - if(m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[it]) - ok_key =true; - break; - } - } - case LOCK_KEY_SKILL: - { - req_key = true; - if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->Index[it]) - break; - - SkillType skill = SkillByLockType(LockType(lockInfo->Index[it])); - if(skill==SKILL_NONE) - ok_key =true; - else if(((Player*)m_caster)->HasSkill(skill)) - ok_key =true; - } - } - if(ok_key) - break; - } - - if(!ok_key && req_key) - return SPELL_FAILED_BAD_TARGETS; - } + SpellCastResult res = CanOpenLock(i,lockId,skillId,reqSkillValue,skillValue); + if(res != SPELL_CAST_OK) + return res; // chance for fail at orange mining/herb/LockPicking gathering attempt - if (!m_selfContainer || ((*m_selfContainer) != this)) - break; - - // get the skill value of the player - int32 SkillValue = 0; - bool canFailAtMax = true; - if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_HERBALISM) + // second check prevent fail at rechecks + if(skillId != SKILL_NONE && (!m_selfContainer || ((*m_selfContainer) != this))) { - SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_HERBALISM); - canFailAtMax = false; + bool canFailAtMax = skillId != SKILL_HERBALISM && skillId != SKILL_MINING; + + // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill) + if((canFailAtMax || skillValue < sWorld.GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue-25, skillValue+37)) + return SPELL_FAILED_TRY_AGAIN; } - else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_MINING) - { - SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_MINING); - canFailAtMax = false; - } - else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) - SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_LOCKPICKING); - - // castitem check: rogue using skeleton keys. the skill values should not be added in this case. - if(m_CastItem) - SkillValue = 0; - - // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value) - SkillValue += m_currentBasePoints[i]+1; - - // get the required lock value - int32 ReqValue=0; - if (lockInfo) - { - // check for lock - key pair - bool ok = false; - for(int it = 0; it < 8; ++it) - { - if(lockInfo->Type[it]==LOCK_KEY_ITEM && lockInfo->Index[it] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[it]) - { - // if so, we're good to go - ok = true; - break; - } - } - if(ok) - break; - - if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) - ReqValue = lockInfo->Skill[1]; - else - ReqValue = lockInfo->Skill[0]; - } - - // skill doesn't meet the required value - if (ReqValue > SkillValue) - return SPELL_FAILED_LOW_CASTLEVEL; - - // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill) - if((canFailAtMax || SkillValue < sWorld.GetConfigMaxSkillValue()) && ReqValue > irand(SkillValue-25, SkillValue+37)) - return SPELL_FAILED_TRY_AGAIN; - break; } case SPELL_EFFECT_SUMMON_DEAD_PET: @@ -5631,3 +5548,65 @@ bool SpellEvent::IsDeletable() const { return m_Spell->IsDeletable(); } + +SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue) +{ + if(!lockId) // possible case for GO and maybe for items. + return SPELL_CAST_OK; + + // Get LockInfo + LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); + + if (!lockInfo) + return SPELL_FAILED_BAD_TARGETS; + + bool reqKey = false; // some locks not have reqs + + for(int j = 0; j < 8; ++j) + { + switch(lockInfo->Type[j]) + { + // check key item (many fit cases can be) + case LOCK_KEY_ITEM: + if(lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[j]) + return SPELL_CAST_OK; + reqKey = true; + break; + // check key skill (only single first fit case can be) + case LOCK_KEY_SKILL: + { + reqKey = true; + + // wrong locktype, skip + if(uint32(m_spellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j]) + continue; + + skillId = SkillByLockType(LockType(lockInfo->Index[j])); + + if ( skillId != SKILL_NONE ) + { + // skill bonus provided by casting spell (mostly item spells) + // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value) + uint32 spellSkillBonus = uint32(m_currentBasePoints[effIndex]+1); + reqSkillValue = lockInfo->Skill[j]; + + // castitem check: rogue using skeleton keys. the skill values should not be added in this case. + skillValue = m_CastItem || m_caster->GetTypeId()!= TYPEID_PLAYER ? + 0 : ((Player*)m_caster)->GetSkillValue(skillId); + + skillValue += spellSkillBonus; + + if (skillValue < reqSkillValue) + return SPELL_FAILED_LOW_CASTLEVEL; + } + + return SPELL_CAST_OK; + } + } + } + + if(reqKey) + return SPELL_FAILED_BAD_TARGETS; + + return SPELL_CAST_OK; +} diff --git a/src/game/Spell.h b/src/game/Spell.h index 5e030cee5..245a7dde3 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -548,6 +548,7 @@ class Spell void DoAllEffectOnTarget(GOTargetInfo *target); void DoAllEffectOnTarget(ItemTargetInfo *target); bool IsAliveUnitPresentInTargetList(); + SpellCastResult CanOpenLock(uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue); // ------------------------------------------- //List For Triggered Spells diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 40a066997..39cf076c3 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -2999,92 +2999,39 @@ void Spell::EffectOpenLock(uint32 effIndex) return; } - if(!lockId) // possible case for GO and maybe for items. + SkillType skillId = SKILL_NONE; + int32 reqSkillValue = 0; + int32 skillValue; + + SpellCastResult res = CanOpenLock(effIndex,lockId,skillId,reqSkillValue,skillValue); + if(res != SPELL_CAST_OK) { - SendLoot(guid, LOOT_CORPSE); - return; - } - - // Get LockInfo - LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); - - if (!lockInfo) - { - sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!", - (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId); - SendCastResult(SPELL_FAILED_BAD_TARGETS); - return; - } - - bool reqKey = false; // some locks not have reqs - - for(int j = 0; j < 8; ++j) - { - switch(lockInfo->Type[j]) - { - // check key item (many fit cases can be) - case LOCK_KEY_ITEM: - if(lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[j]) - { - SendLoot(guid, LOOT_CORPSE); - return; - } - reqKey = true; - break; - // check key skill (only single first fit case can be) - case LOCK_KEY_SKILL: - { - reqKey = true; - - // wrong locktype, skip - if(uint32(m_spellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j]) - continue; - - SkillType skillId = SkillByLockType(LockType(lockInfo->Index[j])); - - if ( skillId != SKILL_NONE ) - { - // skill bonus provided by casting spell (mostly item spells) - uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1); - uint32 reqSkillValue = lockInfo->Skill[j]; - - if ( player->GetSkillValue(skillId) + spellSkillBonus < reqSkillValue ) - { - SendCastResult(SPELL_FAILED_LOW_CASTLEVEL); - return; - } - - // update skill if really known - if(uint32 SkillValue = player->GetPureSkillValue(skillId)) - { - if(gameObjTarget) - { - // Allow one skill-up until respawned - if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) && - player->UpdateGatherSkill(skillId, SkillValue, reqSkillValue) ) - gameObjTarget->AddToSkillupList( player->GetGUIDLow() ); - } - else if(itemTarget) - { - // Do one skill-up - player->UpdateGatherSkill(skillId, SkillValue, reqSkillValue); - } - } - } - - SendLoot(guid, LOOT_SKINNING); - return; - } - } - } - - if(reqKey) - { - SendCastResult(SPELL_FAILED_BAD_TARGETS); + SendCastResult(res); return; } SendLoot(guid, LOOT_SKINNING); + + // not allow use skill grou at item base open + if(!m_CastItem && skillId != SKILL_NONE) + { + // update skill if really known + if(uint32 pureSkillValue = player->GetPureSkillValue(skillId)) + { + if(gameObjTarget) + { + // Allow one skill-up until respawned + if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) && + player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue) ) + gameObjTarget->AddToSkillupList( player->GetGUIDLow() ); + } + else if(itemTarget) + { + // Do one skill-up + player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue); + } + } + } } void Spell::EffectSummonChangeItem(uint32 i) diff --git a/src/shared/Database/DBCStructure.h b/src/shared/Database/DBCStructure.h index 9f8154554..9519c9e63 100644 --- a/src/shared/Database/DBCStructure.h +++ b/src/shared/Database/DBCStructure.h @@ -974,13 +974,15 @@ struct ItemSetEntry uint32 required_skill_value; // 52 m_requiredSkillRank }; +#define MAX_LOCK_CASE 8 + struct LockEntry { uint32 ID; // 0 m_ID - uint32 Type[8]; // 1-8 m_Type - uint32 Index[8]; // 9-16 m_Index - uint32 Skill[8]; // 17-24 m_Skill - //uint32 Action[8]; // 25-32 m_Action + uint32 Type[MAX_LOCK_CASE]; // 1-8 m_Type + uint32 Index[MAX_LOCK_CASE]; // 9-16 m_Index + uint32 Skill[MAX_LOCK_CASE]; // 17-24 m_Skill + //uint32 Action[MAX_LOCK_CASE]; // 25-32 m_Action }; struct MailTemplateEntry diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 12446a513..ce3f52cf1 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7463" + #define REVISION_NR "7464" #endif // __REVISION_NR_H__ From 78879cc634b0b74e6a3f6352374368eb426ac8e8 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 09:36:26 +0300 Subject: [PATCH 27/46] [7465] More fixes in SPELL_CAST_OK use. --- src/game/Spell.cpp | 204 +++++++++++++++++++-------------------- src/game/Spell.h | 10 +- src/shared/revision_nr.h | 2 +- 3 files changed, 108 insertions(+), 108 deletions(-) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 50b322b06..c09df3187 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -2269,8 +2269,6 @@ void Spell::cast(bool skipCheck) { SetExecutedCurrently(true); - uint8 castResult = 0; - // update pointers base at GUIDs to prevent access to non-existed already object UpdatePointers(); @@ -2285,8 +2283,8 @@ void Spell::cast(bool skipCheck) if(m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster) m_caster->SetInFront(m_targets.getUnitTarget()); - castResult = CheckPower(); - if(castResult != 0) + uint8 castResult = CheckPower(); + if(castResult != SPELL_CAST_OK) { SendCastResult(castResult); finish(false); @@ -3375,30 +3373,28 @@ void Spell::TakePower() m_caster->SetLastManaUse(getMSTime()); } -uint8 Spell::CheckRuneCost(uint32 runeCostID) +SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) { if(m_caster->GetTypeId() != TYPEID_PLAYER) - return 0; + return SPELL_CAST_OK; Player *plr = (Player*)m_caster; if(plr->getClass() != CLASS_DEATH_KNIGHT) - return 0; + return SPELL_CAST_OK; SpellRuneCostEntry const *src = sSpellRuneCostStore.LookupEntry(runeCostID); if(!src) - return 0; + return SPELL_CAST_OK; if(src->NoRuneCost()) - return 0; + return SPELL_CAST_OK; int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death for(uint32 i = 0; i < RUNE_DEATH; ++i) - { runeCost[i] = src->RuneCost[i]; - } runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later @@ -3406,23 +3402,17 @@ uint8 Spell::CheckRuneCost(uint32 runeCostID) { uint8 rune = plr->GetCurrentRune(i); if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0)) - { runeCost[rune]--; - } } for(uint32 i = 0; i < RUNE_DEATH; ++i) - { if(runeCost[i] > 0) - { runeCost[RUNE_DEATH] += runeCost[i]; - } - } if(runeCost[RUNE_DEATH] > MAX_RUNES) return SPELL_FAILED_NO_POWER; // not sure if result code is correct - return 0; + return SPELL_CAST_OK; } void Spell::TakeRunePower() @@ -3821,8 +3811,11 @@ uint8 Spell::CanCast(bool strict) // always (except passive spells) check items (focus object can be required for any type casts) if(!IsPassiveSpell(m_spellInfo->Id)) - if(uint8 castResult = CheckItems()) + { + SpellCastResult castResult = CheckItems(); + if(castResult != SPELL_CAST_OK) return castResult; + } //ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38 if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example) @@ -3960,17 +3953,24 @@ uint8 Spell::CanCast(bool strict) } if(!m_IsTriggeredSpell) - if(uint8 castResult = CheckRange(strict)) + { + SpellCastResult castResult = CheckRange(strict); + if(castResult != SPELL_CAST_OK) return castResult; + } { - if(uint8 castResult = CheckPower()) + SpellCastResult castResult = CheckPower(); + if(castResult != SPELL_CAST_OK) return castResult; } if(!m_IsTriggeredSpell) // triggered spell not affected by stun/etc - if(uint8 castResult = CheckCasterAuras()) + { + SpellCastResult castResult = CheckCasterAuras(); + if(castResult != SPELL_CAST_OK) return castResult; + } for (int i = 0; i < 3; i++) { @@ -4472,13 +4472,13 @@ int16 Spell::PetCanCast(Unit* target) return -1; //this allows to check spell fail 0, in combat } -uint8 Spell::CheckCasterAuras() const +SpellCastResult Spell::CheckCasterAuras() const { // Flag drop spells totally immuned to caster auras // FIXME: find more nice check for all totally immuned spells // AttributesEx3 & 0x10000000? if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991) - return 0; + return SPELL_CAST_OK; uint8 school_immune = 0; uint32 mechanic_immune = 0; @@ -4503,7 +4503,7 @@ uint8 Spell::CheckCasterAuras() const } //Check whether the cast should be prevented by any state you might have. - uint8 prevented_reason = 0; + SpellCastResult prevented_reason = SPELL_CAST_OK; // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out uint32 unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS); // Get unit state if(unitflag & UNIT_FLAG_STUNNED && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED)) @@ -4567,7 +4567,7 @@ uint8 Spell::CheckCasterAuras() const else return prevented_reason; } - return 0; // all ok + return SPELL_CAST_OK; } bool Spell::CanAutoCast(Unit* target) @@ -4609,12 +4609,13 @@ bool Spell::CanAutoCast(Unit* target) return false; //target invalid } -uint8 Spell::CheckRange(bool strict) +SpellCastResult Spell::CheckRange(bool strict) { float range_mod; // self cast doesn't need range checking -- also for Starshards fix - if (m_spellInfo->rangeIndex == 1) return 0; + if (m_spellInfo->rangeIndex == 1) + return SPELL_CAST_OK; if (strict) //add radius of caster range_mod = 1.25; @@ -4652,7 +4653,7 @@ uint8 Spell::CheckRange(bool strict) return SPELL_FAILED_TOO_CLOSE; } - return 0; // ok + return SPELL_CAST_OK; } int32 Spell::CalculatePowerCost() @@ -4723,18 +4724,18 @@ int32 Spell::CalculatePowerCost() return powerCost; } -uint8 Spell::CheckPower() +SpellCastResult Spell::CheckPower() { // item cast not used power if(m_CastItem) - return 0; + return SPELL_CAST_OK; // health as power used - need check health amount if(m_spellInfo->powerType == POWER_HEALTH) { if(m_caster->GetHealth() <= m_powerCost) return SPELL_FAILED_CASTER_AURASTATE; - return 0; + return SPELL_CAST_OK; } // Check valid power type if( m_spellInfo->powerType >= MAX_POWERS ) @@ -4743,8 +4744,8 @@ uint8 Spell::CheckPower() return SPELL_FAILED_UNKNOWN; } - uint8 failReason = CheckRuneCost(m_spellInfo->runeCostID); - if(failReason) + SpellCastResult failReason = CheckRuneCost(m_spellInfo->runeCostID); + if(failReason != SPELL_CAST_OK) return failReason; // Check power amount @@ -4752,90 +4753,85 @@ uint8 Spell::CheckPower() if(m_caster->GetPower(powerType) < m_powerCost) return SPELL_FAILED_NO_POWER; else - return 0; + return SPELL_CAST_OK; } -uint8 Spell::CheckItems() +SpellCastResult Spell::CheckItems() { if (m_caster->GetTypeId() != TYPEID_PLAYER) - return 0; + return SPELL_CAST_OK; - uint32 itemid, itemcount; Player* p_caster = (Player*)m_caster; + // cast item checks if(m_CastItem) { - itemid = m_CastItem->GetEntry(); + uint32 itemid = m_CastItem->GetEntry(); if( !p_caster->HasItemCount(itemid,1) ) return SPELL_FAILED_ITEM_NOT_READY; - else + + ItemPrototype const *proto = m_CastItem->GetProto(); + if(!proto) + return SPELL_FAILED_ITEM_NOT_READY; + + for (int i = 0; i<5; i++) + if (proto->Spells[i].SpellCharges) + if(m_CastItem->GetSpellCharges(i)==0) + return SPELL_FAILED_NO_CHARGES_REMAIN; + + // consumable cast item checks + if (proto->Class == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget()) { - ItemPrototype const *proto = m_CastItem->GetProto(); - if(!proto) - return SPELL_FAILED_ITEM_NOT_READY; - - for (int i = 0; i<5; i++) + // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example + SpellCastResult failReason = SPELL_CAST_OK; + for (int i = 0; i < 3; i++) { - if (proto->Spells[i].SpellCharges) - { - if(m_CastItem->GetSpellCharges(i)==0) - return SPELL_FAILED_NO_CHARGES_REMAIN; - } - } + // skip check, pet not required like checks, and for TARGET_PET m_targets.getUnitTarget() is not the real target but the caster + if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_PET) + continue; - uint32 ItemClass = proto->Class; - if (ItemClass == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget()) - { - // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example - uint8 failReason = 0; - for (int i = 0; i < 3; i++) + if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) { - // skip check, pet not required like checks, and for TARGET_PET m_targets.getUnitTarget() is not the real target but the caster - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_PET) + if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth()) + { + failReason = SPELL_FAILED_ALREADY_AT_FULL_HEALTH; continue; - - if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) - { - if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth()) - { - failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_HEALTH; - continue; - } - else - { - failReason = 0; - break; - } } - - // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... - if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) + else { - if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - { - failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; - continue; - } - - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); - if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) - { - failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; - continue; - } - else - { - failReason = 0; - break; - } + failReason = SPELL_CAST_OK; + break; + } + } + + // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... + if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) + { + if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + { + failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; + continue; + } + + Powers power = Powers(m_spellInfo->EffectMiscValue[i]); + if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) + { + failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; + continue; + } + else + { + failReason = SPELL_CAST_OK; + break; } } - if (failReason) - return failReason; } + if (failReason != SPELL_CAST_OK) + return failReason; } } + // check target item if(m_targets.getItemTargetGUID()) { if(m_caster->GetTypeId() != TYPEID_PLAYER) @@ -4854,6 +4850,7 @@ uint8 Spell::CheckItems() return SPELL_FAILED_EQUIPPED_ITEM_CLASS; } + // check spell focus object if(m_spellInfo->RequiresSpellFocus) { CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); @@ -4869,11 +4866,12 @@ uint8 Spell::CheckItems() cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap()); if(!ok) - return (uint8)SPELL_FAILED_REQUIRES_SPELL_FOCUS; + return SPELL_FAILED_REQUIRES_SPELL_FOCUS; focusObject = ok; // game object found in range } + // check reagents if (!p_caster->CanNoReagentCast(m_spellInfo)) { for(uint32 i=0;i<8;i++) @@ -4881,8 +4879,8 @@ uint8 Spell::CheckItems() if(m_spellInfo->Reagent[i] <= 0) continue; - itemid = m_spellInfo->Reagent[i]; - itemcount = m_spellInfo->ReagentCount[i]; + uint32 itemid = m_spellInfo->Reagent[i]; + uint32 itemcount = m_spellInfo->ReagentCount[i]; // if CastItem is also spell reagent if( m_CastItem && m_CastItem->GetEntry() == itemid ) @@ -4902,10 +4900,11 @@ uint8 Spell::CheckItems() } } if( !p_caster->HasItemCount(itemid,itemcount) ) - return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54 + return SPELL_FAILED_ITEM_NOT_READY; //0x54 } } + // check totem-item requirements (items presence in inventory) uint32 totems = 2; for(int i=0;i<2;++i) { @@ -4920,9 +4919,9 @@ uint8 Spell::CheckItems() totems -= 1; } if(totems != 0) - return (uint8)SPELL_FAILED_TOTEMS; //0x7C + return SPELL_FAILED_TOTEMS; //0x7C - //Check items for TotemCategory + // Check items for TotemCategory (items presence in inventory) uint32 TotemCategory = 2; for(int i=0;i<2;++i) { @@ -4938,8 +4937,9 @@ uint8 Spell::CheckItems() TotemCategory -= 1; } if(TotemCategory != 0) - return (uint8)SPELL_FAILED_TOTEM_CATEGORY; //0x7B + return SPELL_FAILED_TOTEM_CATEGORY; //0x7B + // special checks for spell effects for(int i = 0; i < 3; i++) { switch (m_spellInfo->Effect[i]) @@ -5141,7 +5141,7 @@ uint8 Spell::CheckItems() } } - return uint8(0); + return SPELL_CAST_OK; } void Spell::Delayed() diff --git a/src/game/Spell.h b/src/game/Spell.h index 245a7dde3..7a04ac76b 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -333,7 +333,6 @@ class Spell void cast(bool skipCheck = false); void finish(bool ok = true); void TakePower(); - uint8 CheckRuneCost(uint32 runeCostID); void TakeRunePower(); void TakeReagents(); void TakeCastItem(); @@ -349,10 +348,11 @@ class Spell void _handle_immediate_phase(); void _handle_finish_phase(); - uint8 CheckItems(); - uint8 CheckRange(bool strict); - uint8 CheckPower(); - uint8 CheckCasterAuras() const; + SpellCastResult CheckItems(); + SpellCastResult CheckRange(bool strict); + SpellCastResult CheckPower(); + SpellCastResult CheckRuneCost(uint32 runeCostID); + SpellCastResult CheckCasterAuras() const; int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(m_spellInfo,i,m_currentBasePoints[i],target); } int32 CalculatePowerCost(); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index ce3f52cf1..c3dc5a3aa 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7464" + #define REVISION_NR "7465" #endif // __REVISION_NR_H__ From c1b0e7d57a1b3d9a69d7c95d5e89a93eabb4e724 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 11:20:23 +0300 Subject: [PATCH 28/46] [7466] Use SpellCastResult in SpellMgr.* functions --- src/game/Player.cpp | 6 +++--- src/game/Spell.cpp | 19 +++++++------------ src/game/SpellMgr.cpp | 28 ++++++++++++++-------------- src/game/SpellMgr.h | 4 ++-- src/shared/revision_nr.h | 2 +- 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 142bc30e0..f8ececd49 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -7022,7 +7022,7 @@ void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply if(apply) { // Cannot be used in this stance/form - if(GetErrorAtShapeshiftedCast(spellInfo, m_form)!=0) + if(GetErrorAtShapeshiftedCast(spellInfo, m_form) != SPELL_CAST_OK) return; if(form_change) // check aura active state from other form @@ -7056,7 +7056,7 @@ void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply if(form_change) // check aura compatibility { // Cannot be used in this stance/form - if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==0) + if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==SPELL_CAST_OK) return; // and remove only not compatible at form change } @@ -19255,7 +19255,7 @@ void Player::UpdateAreaDependentAuras( uint32 newArea ) for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) { // use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date - if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this)!=0) + if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this) != SPELL_CAST_OK) RemoveAura(iter); else ++iter; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index c09df3187..b7ff25389 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -3616,7 +3616,8 @@ uint8 Spell::CanCast(bool strict) if (checkForm) { // Cannot be used in this stance/form - if(uint8 shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form)) + SpellCastResult shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form); + if(shapeError != SPELL_CAST_OK) return shapeError; if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura())) @@ -3676,14 +3677,10 @@ uint8 Spell::CanCast(bool strict) // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode // this case can be triggered if rank not found (too low-level target for first rank) if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) - { for(int i=0;i<3;i++) - { if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) if(target->getLevel() + 10 < m_spellInfo->spellLevel) return SPELL_FAILED_LOWLEVEL; - } - } } else if (m_caster->GetTypeId()==TYPEID_PLAYER) // Target - is player caster { @@ -3748,10 +3745,8 @@ uint8 Spell::CanCast(bool strict) } if(IsPositiveSpell(m_spellInfo->Id)) - { if(target->IsImmunedToSpell(m_spellInfo)) return SPELL_FAILED_TARGET_AURASTATE; - } //Must be behind the target. if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) ) @@ -3773,10 +3768,9 @@ uint8 Spell::CanCast(bool strict) // check if target is in combat if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) - { return SPELL_FAILED_TARGET_AFFECTING_COMBAT; - } } + // Spell casted only on battleground if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) && m_caster->GetTypeId()==TYPEID_PLAYER) if(!((Player*)m_caster)->InBattleGround()) @@ -3795,9 +3789,10 @@ uint8 Spell::CanCast(bool strict) uint32 zone, area; m_caster->GetZoneAndAreaId(zone,area); - if (uint8 res= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area, - m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL)) - return res; + SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area, + m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL); + if(locRes != SPELL_CAST_OK) + return locRes; // not let players cast spells at mount (and let do it to creatures) if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell && diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index f333db815..1cf471095 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -535,13 +535,13 @@ bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId) return false; } -uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) +SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) { // talents that learn spells can have stance requirements that need ignore // (this requirement only for client-side stance show in talent description) if( GetTalentSpellCost(spellInfo->Id) > 0 && (spellInfo->Effect[0]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[1]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[2]==SPELL_EFFECT_LEARN_SPELL) ) - return 0; + return SPELL_CAST_OK; uint32 stanceMask = (form ? 1 << (form - 1) : 0); @@ -549,7 +549,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) return SPELL_FAILED_NOT_SHAPESHIFT; if (stanceMask & spellInfo->Stances) // can explicitly be casted in this stance - return 0; + return SPELL_CAST_OK; bool actAsShifted = false; if (form > 0) @@ -558,7 +558,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) if (!shapeInfo) { sLog.outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form); - return 0; + return SPELL_CAST_OK; } actAsShifted = !(shapeInfo->flags1 & 1); // shapeshift acts as normal form for spells } @@ -577,7 +577,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) return SPELL_FAILED_ONLY_SHAPESHIFT; } - return 0; + return SPELL_CAST_OK; } void SpellMgr::LoadSpellTargetPositions() @@ -2559,7 +2559,7 @@ void SpellMgr::LoadSpellAreas() sLog.outString( ">> Loaded %u spell area requirements", count ); } -uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player) +SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player) { // normal case if( spellInfo->AreaGroupId > 0) @@ -2585,7 +2585,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) { if(itr->second.IsFitToRequirements(player,zone_id,area_id)) - return 0; + return SPELL_CAST_OK; } return SPELL_FAILED_INCORRECT_AREA; } @@ -2595,9 +2595,9 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint { case 23333: // Warsong Flag case 23335: // Silverwing Flag - return map_id == 489 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; + return map_id == 489 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; case 34976: // Netherstorm Flag - return map_id == 566 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; + return map_id == 566 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; case 2584: // Waiting to Resurrect case 22011: // Spirit Heal Channel case 22012: // Spirit Heal @@ -2610,7 +2610,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint if(!mapEntry) return SPELL_FAILED_INCORRECT_AREA; - return mapEntry->IsBattleGround() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; + return mapEntry->IsBattleGround() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 44521: // Preparation { @@ -2625,7 +2625,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint return SPELL_FAILED_REQUIRES_AREA; BattleGround* bg = player->GetBattleGround(); - return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; + return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 32724: // Gold Team (Alliance) case 32725: // Green Team (Alliance) @@ -2636,7 +2636,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint if(!mapEntry) return SPELL_FAILED_INCORRECT_AREA; - return mapEntry->IsBattleArena() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; + return mapEntry->IsBattleArena() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 32727: // Arena Preparation { @@ -2651,11 +2651,11 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint return SPELL_FAILED_REQUIRES_AREA; BattleGround* bg = player->GetBattleGround(); - return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; + return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } } - return 0; + return SPELL_CAST_OK; } void SpellMgr::LoadSkillLineAbilityMap() diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 5e300b6f5..2f0a6afc4 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -242,7 +242,7 @@ inline bool IsAutoRepeatRangedSpell(SpellEntry const* spellInfo) return (spellInfo->Attributes & SPELL_ATTR_RANGED) && (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG); } -uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form); +SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form); inline bool IsChanneledSpell(SpellEntry const* spellInfo) { @@ -810,7 +810,7 @@ class SpellMgr return NULL; } - uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL); + SpellCastResult GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL); SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const { diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index c3dc5a3aa..7a28879b5 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7465" + #define REVISION_NR "7466" #endif // __REVISION_NR_H__ From 0e987bf59e228768e5689e6b3021b4670d2ca037 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 13:12:51 +0300 Subject: [PATCH 29/46] [7467] Use SpellCastResult and replace CanCast by CheckCast. Note: proper way to check: if(spell->CheckCast(...)==SPELL_CAST_OK) --- src/game/Pet.cpp | 2 +- src/game/Spell.cpp | 132 +++++++++++++++++++------------------- src/game/Spell.h | 7 +- src/game/SpellEffects.cpp | 6 +- src/game/Unit.cpp | 2 +- src/shared/revision_nr.h | 2 +- 6 files changed, 75 insertions(+), 76 deletions(-) diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 7ae39ebb3..0b2c31e77 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -294,7 +294,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool AIM_Initialize(); map->Add((Creature*)this); - // Spells should be loaded after pet is added to map, because in CanCast is check on it + // Spells should be loaded after pet is added to map, because in CheckCast is check on it _LoadSpells(); _LoadSpellCooldowns(); diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index b7ff25389..b09b7200b 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -409,7 +409,7 @@ void Spell::FillTargetMap() if(m_spellInfo->Effect[i]==0) continue; - // targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT filled in Spell::canCast call + // targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT filled in Spell::CheckCast call if( m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT_COORDINATES || m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT || m_spellInfo->EffectImplicitTargetB[i] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[i] != TARGET_SELF ) @@ -466,7 +466,7 @@ void Spell::FillTargetMap() case 0: SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); break; - case TARGET_SCRIPT_COORDINATES: // B case filled in canCast but we need fill unit list base at A case + case TARGET_SCRIPT_COORDINATES: // B case filled in CheckCast but we need fill unit list base at A case SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); break; default: @@ -2182,8 +2182,8 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura) // Fill cost data m_powerCost = CalculatePowerCost(); - uint8 result = CanCast(true); - if(result != 0 && !IsAutoRepeat()) //always cast autorepeat dummy for triggering + SpellCastResult result = CheckCast(true); + if(result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering { if(triggeredByAura) { @@ -2198,7 +2198,7 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura) // Prepare data for triggers prepareDataForTriggerSystem(); - // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail) + // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail) m_casttime = GetSpellCastTime(m_spellInfo, this); // set timer base at cast time @@ -2283,7 +2283,7 @@ void Spell::cast(bool skipCheck) if(m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster) m_caster->SetInFront(m_targets.getUnitTarget()); - uint8 castResult = CheckPower(); + SpellCastResult castResult = CheckPower(); if(castResult != SPELL_CAST_OK) { SendCastResult(castResult); @@ -2295,8 +2295,8 @@ void Spell::cast(bool skipCheck) // triggered cast called from Spell::prepare where it was already checked if(!skipCheck) { - castResult = CanCast(false); - if(castResult != 0) + castResult = CheckCast(false); + if(castResult != SPELL_CAST_OK) { SendCastResult(castResult); finish(false); @@ -2781,65 +2781,65 @@ void Spell::finish(bool ok) m_caster->AttackStop(); } -void Spell::SendCastResult(uint8 result) +void Spell::SendCastResult(SpellCastResult result) { + if(result == SPELL_CAST_OK) + return; + if (m_caster->GetTypeId() != TYPEID_PLAYER) return; if(((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time return; - if(result != 0) + WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); + data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) + data << uint32(m_spellInfo->Id); + data << uint8(result); // problem + switch (result) { - WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); - data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) - data << uint32(m_spellInfo->Id); - data << uint8(result); // problem - switch (result) - { - case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(m_spellInfo->RequiresSpellFocus); - break; - case SPELL_FAILED_REQUIRES_AREA: - // hardcode areas limitation case - switch(m_spellInfo->Id) - { - case 41617: // Cenarion Mana Salve - case 41619: // Cenarion Healing Salve - data << uint32(3905); - break; - case 41618: // Bottled Nethergon Energy - case 41620: // Bottled Nethergon Vapor - data << uint32(3842); - break; - case 45373: // Bloodberry Elixir - data << uint32(4075); - break; - default: // default case (don't must be) - data << uint32(0); - break; - } - break; - case SPELL_FAILED_TOTEMS: - if(m_spellInfo->Totem[0]) - data << uint32(m_spellInfo->Totem[0]); - if(m_spellInfo->Totem[1]) - data << uint32(m_spellInfo->Totem[1]); - break; - case SPELL_FAILED_TOTEM_CATEGORY: - if(m_spellInfo->TotemCategory[0]) - data << uint32(m_spellInfo->TotemCategory[0]); - if(m_spellInfo->TotemCategory[1]) - data << uint32(m_spellInfo->TotemCategory[1]); - break; - case SPELL_FAILED_EQUIPPED_ITEM_CLASS: - data << uint32(m_spellInfo->EquippedItemClass); - data << uint32(m_spellInfo->EquippedItemSubClassMask); - //data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); - break; - } - ((Player*)m_caster)->GetSession()->SendPacket(&data); + case SPELL_FAILED_REQUIRES_SPELL_FOCUS: + data << uint32(m_spellInfo->RequiresSpellFocus); + break; + case SPELL_FAILED_REQUIRES_AREA: + // hardcode areas limitation case + switch(m_spellInfo->Id) + { + case 41617: // Cenarion Mana Salve + case 41619: // Cenarion Healing Salve + data << uint32(3905); + break; + case 41618: // Bottled Nethergon Energy + case 41620: // Bottled Nethergon Vapor + data << uint32(3842); + break; + case 45373: // Bloodberry Elixir + data << uint32(4075); + break; + default: // default case (don't must be) + data << uint32(0); + break; + } + break; + case SPELL_FAILED_TOTEMS: + if(m_spellInfo->Totem[0]) + data << uint32(m_spellInfo->Totem[0]); + if(m_spellInfo->Totem[1]) + data << uint32(m_spellInfo->Totem[1]); + break; + case SPELL_FAILED_TOTEM_CATEGORY: + if(m_spellInfo->TotemCategory[0]) + data << uint32(m_spellInfo->TotemCategory[0]); + if(m_spellInfo->TotemCategory[1]) + data << uint32(m_spellInfo->TotemCategory[1]); + break; + case SPELL_FAILED_EQUIPPED_ITEM_CLASS: + data << uint32(m_spellInfo->EquippedItemClass); + data << uint32(m_spellInfo->EquippedItemSubClassMask); + //data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); + break; } + ((Player*)m_caster)->GetSession()->SendPacket(&data); } void Spell::SendSpellStart() @@ -3582,7 +3582,7 @@ void Spell::TriggerSpell() } } -uint8 Spell::CanCast(bool strict) +SpellCastResult Spell::CheckCast(bool strict) { // check cooldowns to prevent cheating if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) @@ -3647,9 +3647,7 @@ uint8 Spell::CanCast(bool strict) return SPELL_FAILED_MOVING; } - Unit *target = m_targets.getUnitTarget(); - - if(target) + if(Unit *target = m_targets.getUnitTarget()) { // target state requirements (not allowed state), apply to self also if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot))) @@ -3813,7 +3811,7 @@ uint8 Spell::CanCast(bool strict) } //ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38 - if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example) + if(m_UniqueTargetInfo.empty()) // skip second CheckCast apply (for delayed spells for example) { for(uint8 j = 0; j < 3; j++) { @@ -3988,7 +3986,7 @@ uint8 Spell::CanCast(bool strict) { // spell different for friends and enemies // hart version required facing - if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, target )) + if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, m_targets.getUnitTarget() )) return SPELL_FAILED_UNIT_NOT_INFRONT; } break; @@ -4393,7 +4391,7 @@ uint8 Spell::CanCast(bool strict) } // all ok - return 0; + return SPELL_CAST_OK; } int16 Spell::PetCanCast(Unit* target) @@ -4460,8 +4458,8 @@ int16 Spell::PetCanCast(Unit* target) return SPELL_FAILED_NOT_READY; } - uint16 result = CanCast(true); - if(result != 0) + SpellCastResult result = CheckCast(true); + if(result != SPELL_CAST_OK) return result; else return -1; //this allows to check spell fail 0, in combat diff --git a/src/game/Spell.h b/src/game/Spell.h index 7a04ac76b..e9139f185 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -337,9 +337,9 @@ class Spell void TakeReagents(); void TakeCastItem(); void TriggerSpell(); - uint8 CanCast(bool strict); + + SpellCastResult CheckCast(bool strict); int16 PetCanCast(Unit* target); - bool CanAutoCast(Unit* target); // handlers void handle_immediate(); @@ -372,8 +372,9 @@ class Spell Unit* SelectMagnetTarget(); bool CheckTarget( Unit* target, uint32 eff ); + bool CanAutoCast(Unit* target); - void SendCastResult(uint8 result); + void SendCastResult(SpellCastResult result); void SendSpellStart(); void SendSpellGo(); void SendSpellCooldown(); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 39cf076c3..52a3a50f7 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -2964,7 +2964,7 @@ void Spell::EffectOpenLock(uint32 effIndex) if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune || goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK ) { - //CanUseBattleGroundObject() already called in CanCast() + //CanUseBattleGroundObject() already called in CheckCast() // in battleground check if(BattleGround *bg = player->GetBattleGround()) { @@ -2976,7 +2976,7 @@ void Spell::EffectOpenLock(uint32 effIndex) } else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND) { - //CanUseBattleGroundObject() already called in CanCast() + //CanUseBattleGroundObject() already called in CheckCast() // in battleground check if(BattleGround *bg = player->GetBattleGround()) { @@ -3012,7 +3012,7 @@ void Spell::EffectOpenLock(uint32 effIndex) SendLoot(guid, LOOT_SKINNING); - // not allow use skill grou at item base open + // not allow use skill grow at item base open if(!m_CastItem && skillId != SKILL_NONE) { // update skill if really known diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 4fb8ff6b0..4ba7ec101 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -2968,7 +2968,7 @@ void Unit::_UpdateAutoRepeatSpell() if (isAttackReady(RANGED_ATTACK)) { // Check if able to cast - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true)) + if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK) { InterruptSpell(CURRENT_AUTOREPEAT_SPELL); return; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 7a28879b5..404e7e2e9 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7466" + #define REVISION_NR "7467" #endif // __REVISION_NR_H__ From 5d6cb5fe801de102c8e2da32909b80c3e7b5e4d9 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 15:39:10 +0300 Subject: [PATCH 30/46] [7468] Convert pet cast check code to use SpellCastResult and finaly fix SPELL_CAST_OK value (255 custom value now) --- src/game/PetHandler.cpp | 10 +++++----- src/game/SharedDefines.h | 7 ++++--- src/game/Spell.cpp | 12 ++++-------- src/game/Spell.h | 2 +- src/game/Unit.cpp | 5 ++++- src/game/Unit.h | 2 +- src/shared/revision_nr.h | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index f8610ccfd..ad0c4f3ec 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -189,7 +189,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) Spell *spell = new Spell(pet, spellInfo, false); - int16 result = spell->PetCanCast(unit_target); + SpellCastResult result = spell->CheckPetCast(unit_target); //auto turn to target unless possessed if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS)) @@ -200,10 +200,10 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) if(Unit* powner = pet->GetCharmerOrOwner()) if(powner->GetTypeId() == TYPEID_PLAYER) pet->SendUpdateToPlayer((Player*)powner); - result = -1; + result = SPELL_CAST_OK; } - if(result == -1) + if(result == SPELL_CAST_OK) { ((Creature*)pet)->AddCreatureSpellCooldown(spellid); if (((Creature*)pet)->isPet()) @@ -610,8 +610,8 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) spell->m_cast_count = cast_count; // probably pending spell cast spell->m_targets = targets; - int16 result = spell->PetCanCast(NULL); - if(result == -1) + SpellCastResult result = spell->CheckPetCast(NULL); + if(result == SPELL_CAST_OK) { pet->AddCreatureSpellCooldown(spellid); if(pet->isPet()) diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 6ef7b646b..314496a9c 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -683,8 +683,7 @@ enum SpellEffects enum SpellCastResult { - SPELL_CAST_OK = 0, //FIXME: used as success result currently - SPELL_FAILED_AFFECTING_COMBAT = 0, //FIXME: used as success result currently + SPELL_FAILED_AFFECTING_COMBAT = 0, SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1, SPELL_FAILED_ALREADY_AT_FULL_MANA = 2, SPELL_FAILED_ALREADY_AT_FULL_POWER = 3, @@ -865,7 +864,9 @@ enum SpellCastResult SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178, SPELL_FAILED_NOT_IN_BARBERSHOP = 179, SPELL_FAILED_FISHING_TOO_LOW = 180, - SPELL_FAILED_UNKNOWN = 181 + SPELL_FAILED_UNKNOWN = 181, + + SPELL_CAST_OK = 255 //custom value, don't must be send to client }; // Spell aura states diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index b09b7200b..712f976fb 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -4394,7 +4394,7 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_CAST_OK; } -int16 Spell::PetCanCast(Unit* target) +SpellCastResult Spell::CheckPetCast(Unit* target) { if(!m_caster->isAlive()) return SPELL_FAILED_CASTER_DEAD; @@ -4458,11 +4458,7 @@ int16 Spell::PetCanCast(Unit* target) return SPELL_FAILED_NOT_READY; } - SpellCastResult result = CheckCast(true); - if(result != SPELL_CAST_OK) - return result; - else - return -1; //this allows to check spell fail 0, in combat + return CheckCast(true); } SpellCastResult Spell::CheckCasterAuras() const @@ -4589,9 +4585,9 @@ bool Spell::CanAutoCast(Unit* target) } } - int16 result = PetCanCast(target); + SpellCastResult result = CheckPetCast(target); - if(result == -1 || result == SPELL_FAILED_UNIT_NOT_INFRONT) + if(result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT) { FillTargetMap(); //check if among target units, our WANTED target is as well (->only self cast spells return false) diff --git a/src/game/Spell.h b/src/game/Spell.h index e9139f185..468ce8884 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -339,7 +339,7 @@ class Spell void TriggerSpell(); SpellCastResult CheckCast(bool strict); - int16 PetCanCast(Unit* target); + SpellCastResult CheckPetCast(Unit* target); // handlers void handle_immediate(); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 4ba7ec101..d0be836af 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -10615,8 +10615,11 @@ Player* Unit::GetSpellModOwner() } ///----------Pet responses methods----------------- -void Unit::SendPetCastFail(uint32 spellid, uint8 msg) +void Unit::SendPetCastFail(uint32 spellid, SpellCastResult msg) { + if(msg == SPELL_CAST_OK) + return; + Unit *owner = GetCharmerOrOwner(); if(!owner || owner->GetTypeId() != TYPEID_PLAYER) return; diff --git a/src/game/Unit.h b/src/game/Unit.h index 2cdd76892..0e739ad12 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1403,7 +1403,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void ClearComboPointHolders(); ///----------Pet responses methods----------------- - void SendPetCastFail(uint32 spellid, uint8 msg); + void SendPetCastFail(uint32 spellid, SpellCastResult msg); void SendPetActionFeedback (uint8 msg); void SendPetTalk (uint32 pettalk); void SendPetSpellCooldown (uint32 spellid, time_t cooltime); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 404e7e2e9..9f9fd308f 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7467" + #define REVISION_NR "7468" #endif // __REVISION_NR_H__ From e904d7c2c0519abe1500fe53ed1c7d7c305577ac Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 18:22:11 +0300 Subject: [PATCH 31/46] [7469] Allow scripting aura spell triggering in case not existed spell. --- src/game/SpellAuras.cpp | 18 ++++++++---------- src/shared/revision_nr.h | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 478c1ae93..d045e1037 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -39,6 +39,7 @@ #include "Formulas.h" #include "BattleGround.h" #include "CreatureAI.h" +#include "ScriptCalls.h" #include "Util.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -1437,7 +1438,7 @@ void Aura::TriggerSpell() caster->ModifyPower( POWER_MANA, mana ); caster->SendEnergizeSpellLog(caster, 23493, mana, POWER_MANA); } - break; + return; } // // Stoneclaw Totem Passive TEST // case 23792: break; @@ -1505,8 +1506,6 @@ void Aura::TriggerSpell() // case 28522: break; // // Silithyst // case 29519: break; -// // Inoculate Nestlewood Owlkin - case 29528: trigger_spell_id = 28713; break; // // Overload // case 29768: break; // // Return Fire @@ -1548,7 +1547,6 @@ void Aura::TriggerSpell() creature->SetHealth(0); // just for nice GM-mode view } return; - break; } // Quake case 30576: trigger_spell_id = 30571; break; @@ -1929,13 +1927,9 @@ void Aura::TriggerSpell() default: break; } + // Reget trigger spell proto triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id); - if(triggeredSpellInfo == NULL) - { - sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex()); - return; - } } else { @@ -1987,8 +1981,12 @@ void Aura::TriggerSpell() } } } + // All ok cast by default case - caster->CastSpell(target, triggeredSpellInfo, true, 0, this); + if(triggeredSpellInfo) + caster->CastSpell(target, triggeredSpellInfo, true, 0, this); + else if(target->GetTypeId()!=TYPEID_UNIT || !Script->EffectDummyCreature(caster, GetId(), GetEffIndex(), (Creature*)target)) + sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex()); } void Aura::TriggerSpellWithValue() diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 9f9fd308f..e9e5b0f86 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7468" + #define REVISION_NR "7469" #endif // __REVISION_NR_H__ From 4033f789a9b7deb25b710449bae311a345ded7a8 Mon Sep 17 00:00:00 2001 From: arrai Date: Mon, 16 Mar 2009 16:50:46 +0100 Subject: [PATCH 32/46] [7470] Fixed possible loot exploit, thanks to leak` for reporting --- src/game/Player.cpp | 3 +++ src/shared/revision_nr.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index f8ececd49..70a0804cb 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -7468,6 +7468,9 @@ void Player::SendLootRelease( uint64 guid ) void Player::SendLoot(uint64 guid, LootType loot_type) { + if (uint64 lguid = GetLootGUID()) + m_session->DoLootRelease(lguid); + Loot *loot = 0; PermissionTypes permission = ALL_PERMISSION; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index e9e5b0f86..0bb9aa25b 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7469" + #define REVISION_NR "7470" #endif // __REVISION_NR_H__ From f4e37fa5667dadb04e73a2f3e1483de2562f3e49 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 20:02:34 +0300 Subject: [PATCH 33/46] [7471] Ignore player target case for spell 29528 instead error reports in log. --- src/game/SpellAuras.cpp | 5 +++++ src/shared/revision_nr.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index d045e1037..d5ca2097d 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -1506,6 +1506,11 @@ void Aura::TriggerSpell() // case 28522: break; // // Silithyst // case 29519: break; + // Inoculate Nestlewood Owlkin + case 29528: + if(target->GetTypeId()!=TYPEID_UNIT)// prevent error reports in case ignored player target + return; + break; // // Overload // case 29768: break; // // Return Fire diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 0bb9aa25b..e9f19d035 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7470" + #define REVISION_NR "7471" #endif // __REVISION_NR_H__ From 846831e3575489707fa09389f9038c338ef2a88d Mon Sep 17 00:00:00 2001 From: Triply Date: Mon, 16 Mar 2009 18:53:33 +0100 Subject: [PATCH 34/46] [7472] Fixed messages in Eye of Storm Battleground. Signed-off-by: Triply --- sql/mangos.sql | 39 +++++++++++++++++++++++++++++-------- sql/updates/Makefile.am | 2 ++ src/game/BattleGroundEY.cpp | 8 ++++---- src/game/Language.h | 6 +++--- src/game/Player.cpp | 1 + src/shared/revision_nr.h | 2 +- 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/sql/mangos.sql b/sql/mangos.sql index 3dc799bad..82ab1d7ab 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -22,7 +22,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, - `required_7439_01_mangos_mangos_string` bit(1) default NULL + `required_7472_01_mangos_mangos_string` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -2771,9 +2771,11 @@ INSERT INTO `mangos_string` VALUES (611,'The Horde flag was picked up by $n!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (612,'The Alliance Flag was picked up by $n!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (613,'The flags are now placed at their bases.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(636,'The Battle for Eye of the Storm begins in 1 minute.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(637,'The Battle for Eye of the Storm begins in 30 seconds.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(638,'The Battle for Eye of the Storm has begun!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(614,'The Alliance flag is now placed at its base.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(615,'The Horde flag is now placed at its base.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(636,'The battle begins in 1 minute.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(637,'The battle begins in 30 seconds.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(638,'The battle has begun!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (650,'Alliance',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (651,'Horde',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (652,'stables',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), @@ -2785,12 +2787,33 @@ INSERT INTO `mangos_string` VALUES (658,'$n has defended the %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (659,'$n has assaulted the %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (660,'$n claims the %s! If left unchallenged, the %s will control it in 1 minute!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(661,'The Battle for Arathi Basin begins in 1 minute.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(662,'The Battle for Arathi Basin begins in 30 seconds. Prepare yourselves!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(663,'The Battle for Arathi Basin has begun!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(661,'The battle for Arathi Basin begins in 1 minute.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(662,'The battle for Arathi Basin begins in 30 seconds. Prepare yourselves!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(663,'The battle for Arathi Basin has begun!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (664,'The Alliance has gathered $1776W resources, and is near victory!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (665,'The Horde has gathered $1777W resources, and is near victory!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (666,'After your recent battle in %s our best attempts to award you a Mark of Honor failed. Enclosed you will find the Mark of Honor we were not able to deliver to you at the time. Thanks for fighting in %s!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(667,'The Alliance has taken control of the Mage Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(668,'The Horde has taken control of the Mage Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(669,'The Alliance has taken control of the Draenei Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(670,'The Horde has taken control of the Draenei Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(671,'The Alliance has taken control of the Blood Elf Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(672,'The Horde has taken control of the Blood Elf Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(673,'The Alliance has taken control of the Fel Reaver Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(674,'The Horde has taken control of the Fel Reaver Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(675,'The Alliance has lost control of the Mage Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(676,'The Horde has lost control of the Mage Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(677,'The Alliance has lost control of the Draenei Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(678,'The Horde has lost control of the Draenei Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(679,'The Alliance has lost control of the Blood Elf Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(680,'The Horde has lost control of the Blood Elf Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(681,'The Alliance has lost control of the Fel Reaver Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(682,'The Horde has lost control of the Fel Reaver Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(683,'%s has taken the flag!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(684,'The Alliance have captured the flag!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(685,'The Horde have captured the flag!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(686,'The flag has been dropped.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(687,'The flag has been reset.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (700,'You must be level %u to form an arena team',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (701,'One minute until the Arena battle begins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (702,'Thirty seconds until the Arena battle begins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), @@ -2841,7 +2864,7 @@ INSERT INTO `mangos_string` VALUES (751,'Not enough players. This game will close in %u seconds.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (753,'The battle for Warsong Gulch begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (754,'The battle for Arathi Basin begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(755,'The battle for Eye of the Storm begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(755,'The battle begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (801,'You do not have enough gold',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (802,'You do not have enough free slots',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (803,'Your partner does not have enough free bag slots',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 7f44538c8..f816f85d9 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -197,6 +197,7 @@ pkgdata_DATA = \ 7399_01_mangos_mangos_string.sql \ 7422_01_mangos_mangos_string.sql \ 7439_01_mangos_mangos_string.sql \ + 7472_01_mangos_mangos_string.sql \ README ## Additional files to include when running 'make dist' @@ -374,4 +375,5 @@ EXTRA_DIST = \ 7399_01_mangos_mangos_string.sql \ 7422_01_mangos_mangos_string.sql \ 7439_01_mangos_mangos_string.sql \ + 7472_01_mangos_mangos_string.sql \ README diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp index aefaf57c8..acd105fe5 100644 --- a/src/game/BattleGroundEY.cpp +++ b/src/game/BattleGroundEY.cpp @@ -605,9 +605,9 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player *Source) UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN); if(Source->GetTeam() == ALLIANCE) - SendMessageToAll(LANG_BG_EY_DROPPED_FLAG,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL); else - SendMessageToAll(LANG_BG_EY_DROPPED_FLAG,CHAT_MSG_BG_SYSTEM_HORDE, Source); + SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL); } void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) @@ -637,9 +637,9 @@ void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); if(Source->GetTeam() == ALLIANCE) - SendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, Source->GetName()); else - SendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG,CHAT_MSG_BG_SYSTEM_HORDE, Source); + PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL, Source->GetName()); } void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) diff --git a/src/game/Language.h b/src/game/Language.h index c25d1e6f4..3d8727d14 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -692,9 +692,9 @@ enum MangosStrings LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins." LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds." // = 752, not used -// LANG_BG_WS_START_TWO_MINUTES = 753, -// LANG_BG_AB_START_TWO_MINUTES = 754, -// LANG_BG_EY_START_TWO_MINUTES = 755, +// LANG_BG_WS_START_TWO_MINUTES = 753, - defined above +// LANG_BG_AB_START_TWO_MINUTES = 754, - defined above +// LANG_BG_EY_START_TWO_MINUTES = 755, - defined above // Room for batleground/arena strings 756-799 not used // in game strings diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 70a0804cb..2b59499c3 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -19503,6 +19503,7 @@ bool Player::CanUseBattleGroundObject() { return ( //InBattleGround() && // in battleground - not need, check in other cases //!IsMounted() && - not correct, player is dismounted when he clicks on flag + //i'm not sure if these two are correct, because invisible players should get visible when they click on flag !HasStealthAura() && // not stealthed !HasInvisibilityAura() && // not invisible !HasAura(SPELL_RECENTLY_DROPPED_FLAG, 0) && // can't pickup diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index e9f19d035..4cdf7b680 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7471" + #define REVISION_NR "7472" #endif // __REVISION_NR_H__ From efd62ea6eaae354eabff90afa704851a8448dddc Mon Sep 17 00:00:00 2001 From: Triply Date: Mon, 16 Mar 2009 18:57:52 +0100 Subject: [PATCH 35/46] Added last file from previous commit Signed-off-by: Triply --- sql/updates/7472_01_mangos_mangos_string.sql | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 sql/updates/7472_01_mangos_mangos_string.sql diff --git a/sql/updates/7472_01_mangos_mangos_string.sql b/sql/updates/7472_01_mangos_mangos_string.sql new file mode 100644 index 000000000..e25ca96d1 --- /dev/null +++ b/sql/updates/7472_01_mangos_mangos_string.sql @@ -0,0 +1,27 @@ +ALTER TABLE db_version CHANGE COLUMN required_7439_01_mangos_mangos_string required_7472_01_mangos_mangos_string bit; + +DELETE FROM mangos_string WHERE entry >= 667 and entry <= 687 or entry = 614 or entry = 615; +INSERT INTO mangos_string VALUES +(614,'The Alliance flag is now placed at its base.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(615,'The Horde flag is now placed at its base.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(667,'The Alliance has taken control of the Mage Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(668,'The Horde has taken control of the Mage Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(669,'The Alliance has taken control of the Draenei Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(670,'The Horde has taken control of the Draenei Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(671,'The Alliance has taken control of the Blood Elf Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(672,'The Horde has taken control of the Blood Elf Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(673,'The Alliance has taken control of the Fel Reaver Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(674,'The Horde has taken control of the Fel Reaver Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(675,'The Alliance has lost control of the Mage Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(676,'The Horde has lost control of the Mage Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(677,'The Alliance has lost control of the Draenei Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(678,'The Horde has lost control of the Draenei Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(679,'The Alliance has lost control of the Blood Elf Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(680,'The Horde has lost control of the Blood Elf Tower!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(681,'The Alliance has lost control of the Fel Reaver Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(682,'The Horde has lost control of the Fel Reaver Ruins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(683,'%s has taken the flag!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(684,'The Alliance have captured the flag!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(685,'The Horde have captured the flag!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(686,'The flag has been dropped.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(687,'The flag has been reset.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); \ No newline at end of file From 773f58a3d013ba8d044bd1d5b84a813ef85d12fc Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 21:57:19 +0300 Subject: [PATCH 36/46] [7473] Better support new DK class profession. --- src/game/Player.cpp | 8 ++++---- src/shared/revision_nr.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 2b59499c3..854571236 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2895,8 +2895,8 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen continue; if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL || - // lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL - pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 ) + // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL + (pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0 ) { switch(GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0)) { @@ -3105,8 +3105,8 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_ continue; if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL || - // lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL - pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 ) + // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL + (pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0 ) { // not reset skills for professions and racial abilities if( (pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) && diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 4cdf7b680..80cd1e4cf 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7472" + #define REVISION_NR "7473" #endif // __REVISION_NR_H__ From 816862db656b92bcaf82d01eeab0f58611b5b372 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 22:36:34 +0300 Subject: [PATCH 37/46] [7474] Set correct value/maxvalue for skill with fixed skill value at skill loading. --- src/game/Player.cpp | 14 +++++++++++++- src/shared/revision_nr.h | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 854571236..ff17bca37 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -19821,8 +19821,20 @@ void Player::_LoadSkills() else SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); - uint32 vskill = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); + // set fixed skill ranges + switch(GetSkillRangeType(pSkill,false)) + { + case SKILL_RANGE_LANGUAGE: // 300..300 + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(300,300)); + break; + case SKILL_RANGE_MONO: // 1..1, grey monolite bar + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(1,1)); + break; + default: + break; + } + uint32 vskill = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); learnSkillRewardedSpells(id, vskill); } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 80cd1e4cf..da0b5b83f 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7473" + #define REVISION_NR "7474" #endif // __REVISION_NR_H__ From c99a849eb9597e0bf94a0dc3fd0225970f44f979 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 16 Mar 2009 23:22:07 +0300 Subject: [PATCH 38/46] [7475] Move Player::IsInFeralForm to Unit::IsInFeralForm --- src/game/Player.h | 1 - src/game/SpellAuras.cpp | 2 +- src/game/Unit.cpp | 4 ++-- src/game/Unit.h | 3 +++ src/shared/revision_nr.h | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/game/Player.h b/src/game/Player.h index 5a0b1560f..52cbae9cf 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1161,7 +1161,6 @@ class MANGOS_DLL_SPEC Player : public Unit void AddArmorProficiency(uint32 newflag) { m_ArmorProficiency |= newflag; } uint32 GetWeaponProficiency() const { return m_WeaponProficiency; } uint32 GetArmorProficiency() const { return m_ArmorProficiency; } - bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; } bool IsUseEquipedWeapon( bool mainhand ) const { // disarm applied only to mainhand weapon diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index d5ca2097d..1c57cae2d 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -3327,7 +3327,7 @@ void Aura::HandleAuraModDisarm(bool apply, bool Real) return; // main-hand attack speed already set to special value for feral form already and don't must change and reset at remove. - if (((Player *)m_target)->IsInFeralForm()) + if (m_target->IsInFeralForm()) return; if (apply) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index d0be836af..839ebe230 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -2842,7 +2842,7 @@ uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) if(attType != BASE_ATTACK && !item ) return 0; - if(((Player*)this)->IsInFeralForm()) + if(IsInFeralForm()) return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact // weapon skill or (unarmed for base attack) @@ -9645,7 +9645,7 @@ uint32 Unit::GetCreatureType() const { if(GetTypeId() == TYPEID_PLAYER) { - SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(((Player*)this)->m_form); + SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(m_form); if(ssEntry && ssEntry->creatureType > 0) return ssEntry->creatureType; else diff --git a/src/game/Unit.h b/src/game/Unit.h index 0e739ad12..92116fb69 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1197,8 +1197,11 @@ class MANGOS_DLL_SPEC Unit : public WorldObject uint64 m_ObjectSlot[4]; uint32 m_detectInvisibilityMask; uint32 m_invisibilityMask; + uint32 m_ShapeShiftFormSpellId; ShapeshiftForm m_form; + bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; } + float m_modMeleeHitChance; float m_modRangedHitChance; float m_modSpellHitChance; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index da0b5b83f..1280fd31e 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7474" + #define REVISION_NR "7475" #endif // __REVISION_NR_H__ From bde638ace77303f1d7241af1bb74de67fb518d12 Mon Sep 17 00:00:00 2001 From: Lightguard Date: Tue, 17 Mar 2009 01:25:11 +0300 Subject: [PATCH 39/46] [7476] Implement druid's talent 61336. Signed-off-by: VladimirMangos Some improvements added to patch. Related cleanups. --- src/game/Spell.cpp | 14 ++++++++++ src/game/SpellAuras.cpp | 59 +++++++++++++++++++++++++++------------- src/game/SpellMgr.cpp | 4 +++ src/shared/revision_nr.h | 2 +- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 712f976fb..823c0b41c 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -4305,6 +4305,20 @@ SpellCastResult Spell::CheckCast(bool strict) { switch(m_spellInfo->EffectApplyAuraName[i]) { + case SPELL_AURA_DUMMY: + { + //custom check + switch(m_spellInfo->Id) + { + case 61336: + if(m_caster->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_caster)->IsInFeralForm()) + return SPELL_FAILED_ONLY_SHAPESHIFT; + break; + default: + break; + } + break; + } case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_MOD_CHARM: { diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 1c57cae2d..e27374f83 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -2259,6 +2259,45 @@ void Aura::HandleAuraDummy(bool apply, bool Real) } case SPELLFAMILY_DRUID: { + switch(GetId()) + { + case 34246: // Idol of the Emerald Queen + { + if (m_target->GetTypeId() != TYPEID_PLAYER) + return; + + if(apply) + { + SpellModifier *mod = new SpellModifier; + mod->op = SPELLMOD_DOT; + mod->value = m_modifier.m_amount/7; + mod->type = SPELLMOD_FLAT; + mod->spellId = GetId(); + mod->mask = 0x001000000000LL; + mod->mask2= 0LL; + + m_spellmod = mod; + } + + ((Player*)m_target)->AddSpellMod(m_spellmod, apply); + return; + } + case 61336: // Survival Instincts + { + if(apply) + { + if (!m_target->IsInFeralForm()) + return; + + int32 bp0 = int32(m_target->GetMaxHealth() * m_modifier.m_amount / 100); + m_target->CastCustomSpell(m_target, 50322, &bp0, NULL, NULL, true); + } + else + m_target-> RemoveAurasDueToSpell(50322); + return; + } + } + // Lifebloom if ( GetSpellProto()->SpellFamilyFlags & 0x1000000000LL ) { @@ -2298,25 +2337,6 @@ void Aura::HandleAuraDummy(bool apply, bool Real) ((Player*)m_target)->UpdateAttackPowerAndDamage(); return; } - // Idol of the Emerald Queen - if ( GetId() == 34246 && m_target->GetTypeId()==TYPEID_PLAYER ) - { - if(apply) - { - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_DOT; - mod->value = m_modifier.m_amount/7; - mod->type = SPELLMOD_FLAT; - mod->spellId = GetId(); - mod->mask = 0x001000000000LL; - mod->mask2= 0LL; - - m_spellmod = mod; - } - - ((Player*)m_target)->AddSpellMod(m_spellmod, apply); - return; - } break; } case SPELLFAMILY_HUNTER: @@ -4691,6 +4711,7 @@ void Aura::HandleAuraModIncreaseHealth(bool apply, bool Real) case 28726: // Nightmare Seed ( Nightmare Seed ) case 34511: // Valor (Bulwark of Kings, Bulwark of the Ancient Kings) case 44055: // Tremendous Fortitude (Battlemaster's Alacrity) + case 50322: // Survival Instincts { if(Real) { diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 1cf471095..c64df4849 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -1336,6 +1336,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons // Cat Energy (Feral T4 (2)) and Omen of Clarity if( spellInfo_1->Id == 16864 && spellInfo_2->Id == 37311 || spellInfo_2->Id == 16864 && spellInfo_1->Id == 37311 ) return false; + + // Survival Instincts and Survival Instincts + if( spellInfo_1->Id == 61336 && spellInfo_2->Id == 50322 || spellInfo_2->Id == 61336 && spellInfo_1->Id == 50322 ) + return false; } // Leader of the Pack and Scroll of Stamina (multi-family check) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 1280fd31e..87da620f6 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7475" + #define REVISION_NR "7476" #endif // __REVISION_NR_H__ From 4215b65b8c23dc790b71f713babf82c44e1a5e44 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Tue, 17 Mar 2009 10:10:14 +0300 Subject: [PATCH 40/46] [7477] Implement work ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM --- src/game/AchievementMgr.cpp | 38 +++++++++++++++++++----------- src/game/Player.cpp | 2 ++ src/shared/Database/DBCStructure.h | 1 + src/shared/revision_nr.h | 2 +- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 3acf2caa5..dcadaacdc 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -806,24 +806,33 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); break; } + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: + // miscvalue1 = item_id + if(!miscvalue1) + continue; + if(miscvalue1 != achievementCriteria->equip_item.itemID) + continue; + + SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: + { + uint32 spellCount = 0; + for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin(); + spellIter != GetPlayer()->GetSpellMap().end(); + ++spellIter) { - uint32 spellCount = 0; - for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin(); - spellIter != GetPlayer()->GetSpellMap().end(); - ++spellIter) + for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first); + skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first); + ++skillIter) { - for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first); - skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first); - ++skillIter) - { - if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine) - spellCount++; - } + if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine) + spellCount++; } - SetCriteriaProgress(achievementCriteria, spellCount); - break; } + SetCriteriaProgress(achievementCriteria, spellCount); + break; + } case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: { if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID) @@ -876,7 +885,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS: case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: @@ -1004,6 +1012,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve return progress->counter >= achievementCriteria->roll_greed_on_loot.count; case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: return progress->counter >= achievementCriteria->do_emote.count; + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: + return progress->counter >= achievementCriteria->equip_item.count; case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: return progress->counter >= achievementCriteria->quest_reward_money.goldInCopper; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: diff --git a/src/game/Player.cpp b/src/game/Player.cpp index ff17bca37..4a1874e5a 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -10688,6 +10688,8 @@ Item* Player::EquipItem( uint16 pos, Item *pItem, bool update ) } } + // only for full equip instead adding to stack + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry()); return pItem; } diff --git a/src/shared/Database/DBCStructure.h b/src/shared/Database/DBCStructure.h index 9519c9e63..d20d3d66d 100644 --- a/src/shared/Database/DBCStructure.h +++ b/src/shared/Database/DBCStructure.h @@ -374,6 +374,7 @@ struct AchievementCriteriaEntry struct { uint32 itemID; // 3 + uint32 count; // 4 } equip_item; // ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD= 62 diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 87da620f6..e4695cd10 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7476" + #define REVISION_NR "7477" #endif // __REVISION_NR_H__ From 2215f77ec37c265e493ddc8bfc4fad484551889e Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Tue, 17 Mar 2009 17:31:44 +0300 Subject: [PATCH 41/46] [7478] Avoid rescan data at some achievments triggering for speed. Only if chnage can affect result * ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL * ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS * ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION * ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION if --- src/game/AchievementMgr.cpp | 25 +++++++++++++++++++++++-- src/game/Player.cpp | 12 ++++++------ src/shared/revision_nr.h | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index dcadaacdc..59e2c5334 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -689,12 +689,15 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: - if(GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID)) + // spell always provide and at login spell learning. + if(miscvalue1 && miscvalue1!=achievementCriteria->learn_spell.spellID) + continue; + if(GetPlayer()->HasSpell(miscvalue1)) SetCriteriaProgress(achievementCriteria, 1); break; case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: // speedup for non-login case - if(miscvalue1 && achievementCriteria->own_item.itemID!=miscvalue1) + if(miscvalue1 && achievementCriteria->own_item.itemID != miscvalue1) continue; SetCriteriaProgress(achievementCriteria, GetPlayer()->GetItemCount(achievementCriteria->own_item.itemID, true)); break; @@ -736,6 +739,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui break; case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: { + // skip faction check only at loading + if (miscvalue1 && miscvalue1 != achievementCriteria->gain_reputation.factionID) + continue; + int32 reputation = GetPlayer()->GetReputation(achievementCriteria->gain_reputation.factionID); if (reputation > 0) SetCriteriaProgress(achievementCriteria, reputation); @@ -743,6 +750,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui } case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: { + // skip faction check only at loading + if (miscvalue1 && GetPlayer()->GetReputationRank(miscvalue1) < REP_EXALTED) + continue; + uint32 counter = 0; const FactionStateList factionStateList = GetPlayer()->GetFactionStateList(); for (FactionStateList::const_iterator iter = factionStateList.begin(); iter!= factionStateList.end(); ++iter) @@ -817,6 +828,16 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: { + // spell always provide and at login spell learning. + if(!miscvalue1) + continue; + // rescan only when change possible + SkillLineAbilityMap::const_iterator skillIter0 = spellmgr.GetBeginSkillLineAbilityMap(miscvalue1); + if(skillIter0 == spellmgr.GetEndSkillLineAbilityMap(miscvalue1)) + continue; + if(skillIter0->second->skillId != achievementCriteria->learn_skilline_spell.skillLine) + continue; + uint32 spellCount = 0; for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin(); spellIter != GetPlayer()->GetSpellMap().end(); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 4a1874e5a..2a46a5e2b 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2933,8 +2933,8 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if(IsInWorld()) { - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL,spell_id); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS,spell_id); } // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell @@ -5949,8 +5949,8 @@ bool Player::ModifyOneFactionReputation(FactionEntry const* factionEntry, int32 } } } - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION,factionEntry->ID); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION,factionEntry->ID); SendFactionState(&(itr->second)); return true; @@ -6016,8 +6016,8 @@ bool Player::SetOneFactionReputation(FactionEntry const* factionEntry, int32 sta SetFactionAtWar(&itr->second,true); SendFactionState(&(itr->second)); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION,factionEntry->ID); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION,factionEntry->ID); return true; } return false; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index e4695cd10..19244cf1b 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7477" + #define REVISION_NR "7478" #endif // __REVISION_NR_H__ From 6f51fbece99e0321018191cfcbf0cff3898bf041 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Tue, 17 Mar 2009 19:05:56 +0300 Subject: [PATCH 42/46] [7479] Implement per client localization for text emote target name. --- src/game/ChatHandler.cpp | 78 ++++++++++++++++++++++++++-------------- src/shared/revision_nr.h | 2 +- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index 76069aee6..9855f18a5 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -34,6 +34,8 @@ #include "SpellAuras.h" #include "Language.h" #include "Util.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) { @@ -496,6 +498,38 @@ void WorldSession::HandleEmoteOpcode( WorldPacket & recv_data ) GetPlayer()->HandleEmoteCommand(emote); } +namespace MaNGOS +{ + class EmoteChatBuilder + { + public: + EmoteChatBuilder(Player const& pl, uint32 text_emote, uint32 emote_num, Unit const* target) + : i_player(pl), i_text_emote(text_emote), i_emote_num(emote_num), i_target(target) {} + + void operator()(WorldPacket& data, int32 loc_idx) + { + char const* nam = i_target ? i_target->GetNameForLocaleIdx(loc_idx) : NULL; + uint32 namlen = (nam ? strlen(nam) : 0) + 1; + + data.Initialize(SMSG_TEXT_EMOTE, (20+namlen)); + data << i_player.GetGUID(); + data << (uint32)i_text_emote; + data << i_emote_num; + data << (uint32)namlen; + if( namlen > 1 ) + data.append(nam, namlen); + else + data << (uint8)0x00; + } + + private: + Player const& i_player; + uint32 i_text_emote; + uint32 i_emote_num; + Unit const* i_target; + }; +} // namespace MaNGOS + void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data ) { if(!GetPlayer()->isAlive()) @@ -517,27 +551,12 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data ) recv_data >> emoteNum; recv_data >> guid; - const char *nam = 0; - uint32 namlen = 1; - - Unit* unit = ObjectAccessor::GetUnit(*_player, guid); - Creature *pCreature = dynamic_cast(unit); - if(unit) - { - nam = unit->GetName(); - namlen = (nam ? strlen(nam) : 0) + 1; - } - EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote); if (!em) return; - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); - uint32 emote_anim = em->textid; - WorldPacket data; - switch(emote_anim) { case EMOTE_STATE_SLEEP: @@ -550,21 +569,26 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data ) break; } - data.Initialize(SMSG_TEXT_EMOTE, (20+namlen)); - data << GetPlayer()->GetGUID(); - data << (uint32)text_emote; - data << emoteNum; - data << (uint32)namlen; - if( namlen > 1 ) - data.append(nam, namlen); - else - data << (uint8)0x00; + Unit* unit = ObjectAccessor::GetUnit(*_player, guid); - GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true); + CellPair p = MaNGOS::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); + + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); + MaNGOS::LocalizedPacketDo emote_do(emote_builder); + MaNGOS::PlayerDistWorker > emote_worker(GetPlayer(),sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),emote_do); + TypeContainerVisitor >, WorldTypeMapContainer > message(emote_worker); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, message, *GetPlayer()->GetMap()); + + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); //Send scripted event call - if (pCreature && Script) - Script->ReceiveEmote(GetPlayer(),pCreature,text_emote); + if (unit->GetTypeId()==TYPEID_UNIT && Script) + Script->ReceiveEmote(GetPlayer(),(Creature*)unit,text_emote); } void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data ) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 19244cf1b..db27503aa 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7478" + #define REVISION_NR "7479" #endif // __REVISION_NR_H__ From b1e712f32f883f2e06c0d7fc271f77dc3ad073c3 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Tue, 17 Mar 2009 21:34:58 +0300 Subject: [PATCH 43/46] [7480] Clear flight flag early for safe. --- src/game/TargetedMovementGenerator.cpp | 2 -- src/game/WaypointMovementGenerator.cpp | 4 +++- src/shared/revision_nr.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp index 6f4aa4c73..b2f5ad827 100644 --- a/src/game/TargetedMovementGenerator.cpp +++ b/src/game/TargetedMovementGenerator.cpp @@ -92,8 +92,6 @@ template void TargetedMovementGenerator::Initialize(T &owner) { - if(!&owner) - return; owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly()) diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp index 7679ef2d3..d3df843ac 100644 --- a/src/game/WaypointMovementGenerator.cpp +++ b/src/game/WaypointMovementGenerator.cpp @@ -245,11 +245,13 @@ void FlightPathMovementGenerator::Initialize(Player &player) void FlightPathMovementGenerator::Finalize(Player & player) { + // remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack) + player.clearUnitState(UNIT_STAT_IN_FLIGHT); + float x, y, z; i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z); player.SetPosition(x, y, z, player.GetOrientation()); - player.clearUnitState(UNIT_STAT_IN_FLIGHT); player.Unmount(); player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index db27503aa..9c93506d9 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7479" + #define REVISION_NR "7480" #endif // __REVISION_NR_H__ From 7f125ce0c3806e4190ea064ca7c03c8d97e360c0 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Tue, 17 Mar 2009 23:25:29 +0300 Subject: [PATCH 44/46] [7481] Implement special target selection for spell 57669. Patch writed by kozelo, rechapa79 with active support from Lightguard. Signed-off-by: VladimirMangos --- src/game/Spell.cpp | 106 +++++++++++++++++++++++++++++++++++++-- src/shared/revision_nr.h | 2 +- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 823c0b41c..4eb296c58 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -49,6 +49,31 @@ extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; +class PrioritizeManaPlayerWraper +{ + friend struct PrioritizeMana; + + public: + explicit PrioritizeManaPlayerWraper(Player* player) : player(player) + { + uint32 maxmana = player->GetMaxPower(POWER_MANA); + percentMana = maxmana ? player->GetPower(POWER_MANA) * 100 / maxmana : 101; + } + Player* getPlayer() const { return player; } + private: + Player* player; + uint32 percentMana; +}; + +struct PrioritizeMana +{ + int operator()( PrioritizeManaPlayerWraper const& x, PrioritizeManaPlayerWraper const& y ) const + { + return x.percentMana < y.percentMana; + } +}; + + bool IsQuestTameSpell(uint32 spellId) { SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId); @@ -1600,7 +1625,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) case TARGET_ALL_PARTY_AROUND_CASTER: case TARGET_ALL_PARTY_AROUND_CASTER_2: case TARGET_ALL_PARTY: - case TARGET_ALL_RAID_AROUND_CASTER: { Player *pTarget = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself(); Group *pGroup = pTarget ? pTarget->GetGroup() : NULL; @@ -1614,9 +1638,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) Player* Target = itr->getSource(); // IsHostileTo check duel and controlled by enemy - if( Target && - (cur==TARGET_ALL_RAID_AROUND_CASTER || Target->GetSubGroup()==subgroup) && - !m_caster->IsHostileTo(Target) ) + if( Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target) ) { if( m_caster->IsWithinDistInMap(Target, radius) ) TagUnitMap.push_back(Target); @@ -1636,7 +1658,81 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) if( m_caster->IsWithinDistInMap(pet, radius) ) TagUnitMap.push_back(pet); } - }break; + break; + } + case TARGET_ALL_RAID_AROUND_CASTER: + { + Player *pTarget = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself(); + Group *pGroup = pTarget ? pTarget->GetGroup() : NULL; + + if(m_spellInfo->Id==57669) //Replenishment (special target selection) + { + if(pGroup) + { + typedef std::priority_queue, PrioritizeMana> Top10; + Top10 manaUsers; + + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL && manaUsers.size() < 10; itr = itr->next()) + { + Player* Target = itr->getSource(); + if (m_caster->GetGUID() != Target->GetGUID() && Target->getPowerType() == POWER_MANA && + !Target->isDead() && m_caster->IsWithinDistInMap(Target, radius)) + { + PrioritizeManaPlayerWraper WTarget(Target); + manaUsers.push(WTarget); + } + } + + while(!manaUsers.empty()) + { + TagUnitMap.push_back(manaUsers.top().getPlayer()); + manaUsers.pop(); + } + } + else + { + Unit* ownerOrSelf = pTarget ? pTarget : m_caster->GetCharmerOrOwnerOrSelf(); + if ((ownerOrSelf==m_caster || m_caster->IsWithinDistInMap(ownerOrSelf, radius)) && + ownerOrSelf->getPowerType() == POWER_MANA) + TagUnitMap.push_back(ownerOrSelf); + + if(Pet* pet = ownerOrSelf->GetPet()) + if( m_caster->IsWithinDistInMap(pet, radius) && pet->getPowerType() == POWER_MANA ) + TagUnitMap.push_back(pet); + } + } + else + { + if(pGroup) + { + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* Target = itr->getSource(); + + // IsHostileTo check duel and controlled by enemy + if( Target && !m_caster->IsHostileTo(Target) ) + { + if( m_caster->IsWithinDistInMap(Target, radius) ) + TagUnitMap.push_back(Target); + + if(Pet* pet = Target->GetPet()) + if( m_caster->IsWithinDistInMap(pet, radius) ) + TagUnitMap.push_back(pet); + } + } + } + else + { + Unit* ownerOrSelf = pTarget ? pTarget : m_caster->GetCharmerOrOwnerOrSelf(); + if(ownerOrSelf==m_caster || m_caster->IsWithinDistInMap(ownerOrSelf, radius)) + TagUnitMap.push_back(ownerOrSelf); + if(Pet* pet = ownerOrSelf->GetPet()) + if( m_caster->IsWithinDistInMap(pet, radius) ) + TagUnitMap.push_back(pet); + } + } + break; + } case TARGET_SINGLE_FRIEND: case TARGET_SINGLE_FRIEND_2: { diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 9c93506d9..613dbfd14 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7480" + #define REVISION_NR "7481" #endif // __REVISION_NR_H__ From 1dcbbd7f48cc5981bb7e2e05bc756f137f2bbb48 Mon Sep 17 00:00:00 2001 From: Trogvar Date: Wed, 18 Mar 2009 00:10:44 +0300 Subject: [PATCH 45/46] [7482] Fixed recently added crash code in text emote handler. Signed-off-by: VladimirMangos --- src/game/ChatHandler.cpp | 2 +- src/shared/revision_nr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index 9855f18a5..f6774dc01 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -587,7 +587,7 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data ) GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); //Send scripted event call - if (unit->GetTypeId()==TYPEID_UNIT && Script) + if (unit && unit->GetTypeId()==TYPEID_UNIT && Script) Script->ReceiveEmote(GetPlayer(),(Creature*)unit,text_emote); } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 613dbfd14..94f4934ed 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7481" + #define REVISION_NR "7482" #endif // __REVISION_NR_H__ From 406a9a7fce1d102db891c1f604f0cde7f5162f37 Mon Sep 17 00:00:00 2001 From: DasBlub Date: Sun, 8 Mar 2009 14:51:14 +0100 Subject: [PATCH 46/46] [7483] the spell 'Protectorate Demolitionist' is a debuff. (cherry picked from commit cdb050aed9d2ea43923123e54e15299f363befe9) Signed-off-by: VladimirMangos --- src/game/SpellMgr.cpp | 1 + src/shared/revision_nr.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index c64df4849..124448f50 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -317,6 +317,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex) { case 13139: // net-o-matic special effect case 23445: // evil twin + case 35679: // Protectorate Demolitionist case 38637: // Nether Exhaustion (red) case 38638: // Nether Exhaustion (green) case 38639: // Nether Exhaustion (blue) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 94f4934ed..b84930cc1 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7482" + #define REVISION_NR "7483" #endif // __REVISION_NR_H__