diff options
Diffstat (limited to 'src')
96 files changed, 2416 insertions, 2079 deletions
diff --git a/src/common/Debugging/WheatyExceptionReport.cpp b/src/common/Debugging/WheatyExceptionReport.cpp index 6e98bf23c5f..836ae7b0837 100644 --- a/src/common/Debugging/WheatyExceptionReport.cpp +++ b/src/common/Debugging/WheatyExceptionReport.cpp @@ -420,18 +420,18 @@ void WheatyExceptionReport::PrintSystemInfo() MemoryStatus.dwLength = sizeof (MEMORYSTATUS); ::GlobalMemoryStatus(&MemoryStatus); TCHAR sString[1024]; - _tprintf(_T("//=====================================================\r\n")); + Log(_T("//=====================================================\r\n")); if (_GetProcessorName(sString, countof(sString))) - _tprintf(_T("*** Hardware ***\r\nProcessor: %s\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"), + Log(_T("*** Hardware ***\r\nProcessor: %s\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"), sString, SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400); else - _tprintf(_T("*** Hardware ***\r\nProcessor: <unknown>\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"), + Log(_T("*** Hardware ***\r\nProcessor: <unknown>\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"), SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400); if (_GetWindowsVersion(sString, countof(sString))) - _tprintf(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString); + Log(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString); else - _tprintf(_T("\r\n*** Operation System:\r\n<unknown>\r\n")); + Log(_T("\r\n*** Operation System:\r\n<unknown>\r\n")); } //=========================================================================== @@ -494,14 +494,14 @@ PEXCEPTION_POINTERS pExceptionInfo) GetLocalTime(&systime); // Start out with a banner - _tprintf(_T("Revision: %s\r\n"), GitRevision::GetFullVersion()); - _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); + Log(_T("Revision: %s\r\n"), GitRevision::GetFullVersion()); + Log(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; PrintSystemInfo(); // First print information about the type of fault - _tprintf(_T("\r\n//=====================================================\r\n")); - _tprintf(_T("Exception code: %08X %s\r\n"), + Log(_T("\r\n//=====================================================\r\n")); + Log(_T("Exception code: %08X %s\r\n"), pExceptionRecord->ExceptionCode, GetExceptionString(pExceptionRecord->ExceptionCode)); @@ -515,12 +515,12 @@ PEXCEPTION_POINTERS pExceptionInfo) section, offset); #ifdef _M_IX86 - _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), + Log(_T("Fault address: %08X %02X:%08X %s\r\n"), pExceptionRecord->ExceptionAddress, section, offset, szFaultingModule); #endif #ifdef _M_X64 - _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), + Log(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), pExceptionRecord->ExceptionAddress, section, offset, szFaultingModule); #endif @@ -529,32 +529,32 @@ PEXCEPTION_POINTERS pExceptionInfo) // Show the registers #ifdef _M_IX86 // X86 Only! - _tprintf(_T("\r\nRegisters:\r\n")); + Log(_T("\r\nRegisters:\r\n")); - _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") + Log(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, pCtx->Esi, pCtx->Edi); - _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); - _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), + Log(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); + Log(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), pCtx->SegSs, pCtx->Esp, pCtx->Ebp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + Log(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); - _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); + Log(_T("Flags:%08X\r\n"), pCtx->EFlags); #endif #ifdef _M_X64 - _tprintf(_T("\r\nRegisters:\r\n")); - _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") + Log(_T("\r\nRegisters:\r\n")); + Log(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n") , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15); - _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); - _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), + Log(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); + Log(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + Log(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); - _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); + Log(_T("Flags:%08X\r\n"), pCtx->EFlags); #endif SymSetOptions(SYMOPT_DEFERRED_LOADS); @@ -562,7 +562,7 @@ PEXCEPTION_POINTERS pExceptionInfo) // Initialize DbgHelp if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) { - _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), + Log(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), ErrorMessage(GetLastError())); } @@ -573,28 +573,20 @@ PEXCEPTION_POINTERS pExceptionInfo) // #ifdef _M_IX86 // X86 Only! - _tprintf(_T("========================\r\n")); - _tprintf(_T("Local Variables And Parameters\r\n")); + Log(_T("========================\r\n")); + Log(_T("Local Variables And Parameters\r\n")); trashableContext = *pCtx; WriteStackDetails(&trashableContext, true, NULL); printTracesForAllThreads(true); - /*_tprintf(_T("========================\r\n")); - _tprintf(_T("Global Variables\r\n")); - - SymEnumSymbols(GetCurrentProcess(), - (UINT_PTR)GetModuleHandle(szFaultingModule), - 0, EnumerateSymbolsCallback, 0);*/ - // #endif // X86 Only! - SymCleanup(GetCurrentProcess()); - _tprintf(_T("\r\n")); + Log(_T("\r\n")); } __except (EXCEPTION_EXECUTE_HANDLER) { - _tprintf(_T("Error writing the crash log\r\n")); + Log(_T("Error writing the crash log\r\n")); } } @@ -720,9 +712,9 @@ void WheatyExceptionReport::WriteStackDetails( PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle) // true if local/params should be output { - _tprintf(_T("\r\nCall stack:\r\n")); + Log(_T("\r\nCall stack:\r\n")); - _tprintf(_T("Address Frame Function SourceFile\r\n")); + Log(_T("Address Frame Function SourceFile\r\n")); DWORD dwMachineType = 0; // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag @@ -769,10 +761,10 @@ bool bWriteVariables, HANDLE pThreadHandle) if (0 == sf.AddrFrame.Offset) // Basic sanity check to make sure break; // the frame is OK. Bail if not. #ifdef _M_IX86 - _tprintf(_T("%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset); + Log(_T("%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset); #endif #ifdef _M_X64 - _tprintf(_T("%016I64X %016I64X "), sf.AddrPC.Offset, sf.AddrFrame.Offset); + Log(_T("%016I64X %016I64X "), sf.AddrPC.Offset, sf.AddrFrame.Offset); #endif DWORD64 symDisplacement = 0; // Displacement of the input address, @@ -786,7 +778,7 @@ bool bWriteVariables, HANDLE pThreadHandle) &symDisplacement, // Address of the variable that will receive the displacement &sip.si)) // Address of the SYMBOL_INFO structure (inside "sip" object) { - _tprintf(_T("%hs+%I64X"), sip.si.Name, symDisplacement); + Log(_T("%hs+%I64X"), sip.si.Name, symDisplacement); } else // No symbol found. Print out the logical address instead. @@ -798,10 +790,10 @@ bool bWriteVariables, HANDLE pThreadHandle) GetLogicalAddress((PVOID)sf.AddrPC.Offset, szModule, sizeof(szModule), section, offset); #ifdef _M_IX86 - _tprintf(_T("%04X:%08X %s"), section, offset, szModule); + Log(_T("%04X:%08X %s"), section, offset, szModule); #endif #ifdef _M_X64 - _tprintf(_T("%04X:%016I64X %s"), section, offset, szModule); + Log(_T("%04X:%016I64X %s"), section, offset, szModule); #endif } @@ -811,10 +803,10 @@ bool bWriteVariables, HANDLE pThreadHandle) if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo)) { - _tprintf(_T(" %s line %u"), lineInfo.FileName, lineInfo.LineNumber); + Log(_T(" %s line %u"), lineInfo.FileName, lineInfo.LineNumber); } - _tprintf(_T("\r\n")); + Log(_T("\r\n")); // Write out the variables, if desired if (bWriteVariables) @@ -827,7 +819,7 @@ bool bWriteVariables, HANDLE pThreadHandle) // Enumerate the locals/parameters SymEnumSymbols(m_hProcess, 0, 0, EnumerateSymbolsCallback, &sf); - _tprintf(_T("\r\n")); + Log(_T("\r\n")); } } @@ -843,22 +835,15 @@ PSYMBOL_INFO pSymInfo, ULONG /*SymbolSize*/, PVOID UserContext) { - - char szBuffer[WER_LARGE_BUFFER_SIZE]; - memset(szBuffer, 0, sizeof(szBuffer)); - __try { ClearSymbols(); - if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext, - szBuffer, sizeof(szBuffer))) - _tprintf(_T("%s"), szBuffer); + FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext); + } __except (EXCEPTION_EXECUTE_HANDLER) { - _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name); - if (szBuffer[0] != '\0') - _tprintf(_T("%s"), szBuffer); + Log(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name); } return TRUE; @@ -871,12 +856,8 @@ PVOID UserContext) ////////////////////////////////////////////////////////////////////////////// bool WheatyExceptionReport::FormatSymbolValue( PSYMBOL_INFO pSym, -STACKFRAME64 * sf, -char * pszBuffer, -unsigned /*cbBuffer*/) +STACKFRAME64 * sf) { - char * pszCurrBuffer = pszBuffer; - // If it's a function, don't do anything. if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK return false; @@ -904,7 +885,7 @@ unsigned /*cbBuffer*/) pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable } - pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + PushSymbolDetail(); // Indicate if the variable is a local or parameter if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) @@ -915,8 +896,7 @@ unsigned /*cbBuffer*/) // Determine if the variable is a user defined type (UDT). IF so, bHandled // will return true. bool bHandled; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex, - pVariable, bHandled, pSym->Name, "", false, true); + DumpTypeIndex(pSym->ModBase, pSym->TypeIndex, pVariable, bHandled, pSym->Name, "", false, true); if (!bHandled) { @@ -936,7 +916,7 @@ unsigned /*cbBuffer*/) symbolDetails.top().Value = buffer; } - pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); + PopSymbolDetail(); return true; } @@ -945,8 +925,7 @@ unsigned /*cbBuffer*/) // at fundamental types. When he hit fundamental types, return // bHandled = false, so that FormatSymbolValue() will format them. ////////////////////////////////////////////////////////////////////////////// -char * WheatyExceptionReport::DumpTypeIndex( -char * pszCurrBuffer, +void WheatyExceptionReport::DumpTypeIndex( DWORD64 modBase, DWORD dwTypeIndex, DWORD_PTR offset, @@ -959,11 +938,11 @@ bool logChildren) bHandled = false; if (newSymbol) - pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + PushSymbolDetail(); DWORD typeTag; if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag)) - return pszCurrBuffer; + return; // Get the name of the symbol. This will either be a Type name (if a UDT), // or the structure member name. @@ -982,12 +961,12 @@ bool logChildren) if (Name != NULL && Name[0] != '\0') symbolDetails.top().Name = Name; bHandled = true; - return pszCurrBuffer; + return; } - char buffer[200]; + char buffer[WER_SMALL_BUFFER_SIZE]; wcstombs(buffer, pwszTypeName, sizeof(buffer)); - buffer[199] = '\0'; + buffer[WER_SMALL_BUFFER_SIZE - 1] = '\0'; if (Name != NULL && Name[0] != '\0') { symbolDetails.top().Type = buffer; @@ -1006,7 +985,7 @@ bool logChildren) // Skip printing address and base class if it has been printed already if (typeTag == SymTagBaseClass) bHandled = true; - return pszCurrBuffer; + return; } DWORD innerTypeID; @@ -1032,7 +1011,7 @@ bool logChildren) // Try to dereference the pointer in a try/except block since it might be invalid DWORD_PTR address = DereferenceUnsafePointer(offset); - char buffer[50]; + char buffer[WER_SMALL_BUFFER_SIZE]; FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer)); symbolDetails.top().Value = buffer; @@ -1043,8 +1022,7 @@ bool logChildren) if (address == NULL || address == DWORD_PTR(-1)) logChildren = false; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, - address, bHandled, Name, addressStr, false, logChildren); + DumpTypeIndex(modBase, innerTypeID, address, bHandled, Name, addressStr, false, logChildren); if (!bHandled) { @@ -1066,7 +1044,7 @@ bool logChildren) symbolDetails.top().Value = buffer2; } bHandled = true; - return pszCurrBuffer; + return; } else if (address == NULL) symbolDetails.top().Value = "NULL"; @@ -1074,7 +1052,7 @@ bool logChildren) { symbolDetails.top().Value = "<Unable to read memory>"; bHandled = true; - return pszCurrBuffer; + return; } } break; @@ -1090,17 +1068,17 @@ bool logChildren) case SymTagUDT: if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL) logChildren = false; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, + DumpTypeIndex(modBase, innerTypeID, offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); break; case SymTagPointerType: if (Name != NULL && Name[0] != '\0') symbolDetails.top().Name = Name; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, + DumpTypeIndex(modBase, innerTypeID, offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); break; case SymTagArrayType: - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, + DumpTypeIndex(modBase, innerTypeID, offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); break; default: @@ -1114,7 +1092,7 @@ bool logChildren) symbolDetails.top().HasChildren = true; BasicType basicType = btNoType; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, + DumpTypeIndex(modBase, innerTypeID, offset, bHandled, Name, "", false, false); // Set Value back to an empty string since the Array object itself has no value, only its elements have @@ -1149,22 +1127,22 @@ bool logChildren) default: for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++) { - pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + PushSymbolDetail(); symbolDetails.top().Suffix += "[" + std::to_string(index) + "]"; FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer)); symbolDetails.top().Value = buffer; - pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); + PopSymbolDetail(); } break; } - return pszCurrBuffer; + return; } break; case SymTagBaseType: break; case SymTagEnum: - return pszCurrBuffer; + return; default: break; } @@ -1174,7 +1152,7 @@ bool logChildren) SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount); if (!dwChildrenCount) // If no children, we're done - return pszCurrBuffer; + return; // Prepare to get an array of "TypeIds", representing each of the children. // SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a @@ -1192,7 +1170,7 @@ bool logChildren) if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN, &children)) { - return pszCurrBuffer; + return; } // Iterate through each of the children @@ -1220,7 +1198,7 @@ bool logChildren) if (!logChildren) { bHandled = false; - return pszCurrBuffer; + return; } // Recurse for each of the child types @@ -1235,7 +1213,7 @@ bool logChildren) // Calculate the address of the member DWORD_PTR dwFinalOffset = offset + dwMemberOffset; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, + DumpTypeIndex(modBase, children.ChildId[i], dwFinalOffset, bHandled2, ""/*Name */, "", true, true); @@ -1260,11 +1238,11 @@ bool logChildren) symbolDetails.top().Value = buffer; } - pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); + PopSymbolDetail(); } bHandled = true; - return pszCurrBuffer; + return; } void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, @@ -1386,26 +1364,26 @@ DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address) // Helper function that writes to the report file, and allows the user to use // printf style formating //============================================================================ -int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) +int __cdecl WheatyExceptionReport::Log(const TCHAR * format, ...) { int retValue; va_list argptr; va_start(argptr, format); if (stackOverflowException) { - retValue = heapprintf(format, argptr); + retValue = HeapLog(format, argptr); va_end(argptr); } else { - retValue = stackprintf(format, argptr); + retValue = StackLog(format, argptr); va_end(argptr); } return retValue; } -int __cdecl WheatyExceptionReport::stackprintf(const TCHAR * format, va_list argptr) +int __cdecl WheatyExceptionReport::StackLog(const TCHAR * format, va_list argptr) { int retValue; DWORD cbWritten; @@ -1417,7 +1395,7 @@ int __cdecl WheatyExceptionReport::stackprintf(const TCHAR * format, va_list arg return retValue; } -int __cdecl WheatyExceptionReport::heapprintf(const TCHAR * format, va_list argptr) +int __cdecl WheatyExceptionReport::HeapLog(const TCHAR * format, va_list argptr) { int retValue = 0; DWORD cbWritten; @@ -1444,37 +1422,35 @@ void WheatyExceptionReport::ClearSymbols() symbolDetails.pop(); } -char* WheatyExceptionReport::PushSymbolDetail(char* pszCurrBuffer) +void WheatyExceptionReport::PushSymbolDetail() { // Log current symbol and then add another to the stack to keep the hierarchy format - pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); + PrintSymbolDetail(); symbolDetails.emplace(); - return pszCurrBuffer; } -char* WheatyExceptionReport::PopSymbolDetail(char* pszCurrBuffer) +void WheatyExceptionReport::PopSymbolDetail() { - pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); + PrintSymbolDetail(); symbolDetails.pop(); - return pszCurrBuffer; } -char* WheatyExceptionReport::PrintSymbolDetail(char* pszCurrBuffer) +void WheatyExceptionReport::PrintSymbolDetail() { if (symbolDetails.empty()) - return pszCurrBuffer; + return; // Don't log anything if has been logged already or if it's empty if (symbolDetails.top().Logged || symbolDetails.top().empty()) - return pszCurrBuffer; + return; // Add appropriate indentation level (since this routine is recursive) for (size_t i = 0; i < symbolDetails.size(); i++) - pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + Log(_T("\t")); - pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str()); + Log(_T("%s\r\n"), symbolDetails.top().ToString().c_str()); - return pszCurrBuffer; + return; } #endif // _WIN32 diff --git a/src/common/Debugging/WheatyExceptionReport.h b/src/common/Debugging/WheatyExceptionReport.h index 7d7ae3feb4e..42d4d3e0a2a 100644 --- a/src/common/Debugging/WheatyExceptionReport.h +++ b/src/common/Debugging/WheatyExceptionReport.h @@ -14,7 +14,8 @@ #define WER_MAX_ARRAY_ELEMENTS_COUNT 10 #define WER_MAX_NESTING_LEVEL 4 -#define WER_LARGE_BUFFER_SIZE 1024 * 128 +#define WER_SMALL_BUFFER_SIZE 1024 +#define WER_LARGE_BUFFER_SIZE WER_SMALL_BUFFER_SIZE * 16 enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK { @@ -173,18 +174,18 @@ class WheatyExceptionReport static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID); - static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer); + static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *); - static char * DumpTypeIndex(char *, DWORD64, DWORD, DWORD_PTR, bool &, const char*, char*, bool, bool); + static void DumpTypeIndex(DWORD64, DWORD, DWORD_PTR, bool &, const char*, char*, bool, bool); static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride = 0); static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase); static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); - static int __cdecl _tprintf(const TCHAR * format, ...); - static int __cdecl stackprintf(const TCHAR * format, va_list argptr); - static int __cdecl heapprintf(const TCHAR * format, va_list argptr); + static int __cdecl Log(const TCHAR * format, ...); + static int __cdecl StackLog(const TCHAR * format, va_list argptr); + static int __cdecl HeapLog(const TCHAR * format, va_list argptr); static bool StoreSymbol(DWORD type , DWORD_PTR offset); static void ClearSymbols(); @@ -205,9 +206,9 @@ class WheatyExceptionReport typedef NTSTATUS(NTAPI* pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation); static pRtlGetVersion RtlGetVersion; - static char* PushSymbolDetail(char* pszCurrBuffer); - static char* PopSymbolDetail(char* pszCurrBuffer); - static char* PrintSymbolDetail(char* pszCurrBuffer); + static void PushSymbolDetail(); + static void PopSymbolDetail(); + static void PrintSymbolDetail(); }; diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 20520cb2068..a18fd16ad15 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -63,13 +63,6 @@ TC_COMMON_API std::string secsToTimeString(uint64 timeInSecs, bool shortText = f TC_COMMON_API uint32 TimeStringToSecs(const std::string& timestring); TC_COMMON_API std::string TimeToTimestampStr(time_t t); -inline void ApplyPercentModFloatVar(float& var, float val, bool apply) -{ - if (val == -100.0f) // prevent set var to zero - val = -99.99f; - var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val)); -} - // Percentage calculation template <class T, class U> inline T CalculatePct(T base, U pct) diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 7fbc8ed2ed5..b9d052cb528 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -368,13 +368,25 @@ bool CreatureAI::CheckBoundary(Position const* who) const who = me; if (_boundary) - for (AreaBoundary const* boundary : *_boundary) - if (!boundary->IsWithinBoundary(who)) + for (AreaBoundary const* areaBoundary : *_boundary) + if (!areaBoundary->IsWithinBoundary(who)) return false; return true; } +bool CreatureAI::IsInBounds(CreatureBoundary const* boundary, Position const* pos) +{ + if (!boundary) + return true; + + for (AreaBoundary const* areaBoundary : *boundary) + if (!areaBoundary->IsWithinBoundary(pos)) + return false; + + return true; +} + void CreatureAI::SetBoundary(CreatureBoundary const* boundary) { _boundary = boundary; diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index e36a41795a0..5fe93e7675a 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -31,7 +31,7 @@ class PlayerAI; class WorldObject; struct Position; -typedef std::set<AreaBoundary const*> CreatureBoundary; +typedef std::vector<AreaBoundary const*> CreatureBoundary; #define TIME_INTERVAL_LOOK 5000 #define VISIBILITY_RANGE 10000 @@ -82,6 +82,7 @@ class TC_GAME_API CreatureAI : public UnitAI Creature* DoSummonFlyer(uint32 entry, WorldObject* obj, float flightZ, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN); bool CheckBoundary(Position const* who = nullptr) const; + void SetBoundary(CreatureBoundary const* boundary); public: enum EvadeReason @@ -214,6 +215,8 @@ class TC_GAME_API CreatureAI : public UnitAI virtual bool CheckInRoom(); CreatureBoundary const* GetBoundary() const { return _boundary; } + static bool IsInBounds(CreatureBoundary const* boundary, Position const* who); + protected: virtual void MoveInLineOfSight(Unit* /*who*/); diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 8bee4794975..6224533846e 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -2341,12 +2341,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { if (Creature* creature = (*itr)->ToCreature()) - { - creature->GetMotionMaster()->Clear(); creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, 0.0f, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); // @todo add optional jump orientation support? - } } - /// @todo Resume path when reached jump location delete targets; break; diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 77ed2075a33..12e33cf9ee3 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -1016,6 +1016,9 @@ bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) if (itr->second == std::chrono::system_clock::time_point::min()) return false; + if (itr->second == std::chrono::system_clock::time_point::max()) + return true; + // Allow completing the realm first kill for entire minute after first person did it // it may allow more than one group to achieve it (highly unlikely) // but apparently this is how blizz handles it as well diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 748e1ac26ee..4bbb29d43c1 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -536,12 +536,12 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, UpdateLevelDependantStats(); // We still re-initialize level dependant stats on entry update SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool)); - SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY])); - SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE])); - SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE])); - SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FROST])); - SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_SHADOW])); - SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FROST])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_SHADOW])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE])); SetCanModifyStats(true); UpdateAllStats(); @@ -1043,8 +1043,7 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 entry, float LastUsedScriptID = GetScriptId(); - /// @todo Replace with spell, handle from DB - if (IsSpiritHealer() || IsSpiritGuide()) + if (IsSpiritHealer() || IsSpiritGuide() || (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_GHOST_VISIBILITY)) { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); @@ -1409,7 +1408,7 @@ void Creature::UpdateLevelDependantStats() break; } - SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health); + SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health); // damage float basedamage = stats->GenerateBaseDamage(cInfo); @@ -1426,11 +1425,11 @@ void Creature::UpdateLevelDependantStats() SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, weaponBaseMinDamage); SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, weaponBaseMaxDamage); - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower); - SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower); + SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower); + SetStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower); float armor = (float)stats->GenerateArmor(cInfo); /// @todo Why is this treated as uint32 when it's a float? - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor); + SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, armor); } float Creature::_GetHealthMod(int32 Rank) @@ -1906,7 +1905,7 @@ void Creature::setDeathState(DeathState s) SetCannotReachTarget(false); UpdateMovementFlags(); - ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_IGNORE_PATHFINDING)); + ClearUnitState(UNIT_STATE_ALL_ERASABLE); if (!IsPet()) { @@ -2437,7 +2436,7 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool /*force*/) const else { // include sizes for huge npcs - dist += GetObjectSize() + victim->GetObjectSize(); + dist += GetCombatReach() + victim->GetCombatReach(); // to prevent creatures in air ignore attacks because distance is already too high... if (GetCreatureTemplate()->InhabitType & INHABIT_AIR) @@ -2755,7 +2754,8 @@ std::string Creature::GetScriptName() const uint32 Creature::GetScriptId() const { if (CreatureData const* creatureData = GetCreatureData()) - return creatureData->ScriptId; + if (uint32 scriptId = creatureData->ScriptId) + return scriptId; return sObjectMgr->GetCreatureTemplate(GetEntry())->ScriptID; } @@ -2995,7 +2995,7 @@ void Creature::SetObjectScale(float scale) if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(GetDisplayId())) { SetBoundingRadius((IsPet() ? 1.0f : minfo->bounding_radius) * scale); - SetCombatReach((IsPet() ? DEFAULT_COMBAT_REACH : minfo->combat_reach) * scale); + SetCombatReach((IsPet() ? DEFAULT_PLAYER_COMBAT_REACH : minfo->combat_reach) * scale); } } @@ -3006,7 +3006,7 @@ void Creature::SetDisplayId(uint32 modelId, float displayScale /*= 1.f*/) if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(modelId)) { SetBoundingRadius((IsPet() ? 1.0f : minfo->bounding_radius) * GetObjectScale()); - SetCombatReach((IsPet() ? DEFAULT_COMBAT_REACH : minfo->combat_reach) * GetObjectScale()); + SetCombatReach((IsPet() ? DEFAULT_PLAYER_COMBAT_REACH : minfo->combat_reach) * GetObjectScale()); } } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index afd07d44053..1be3e00e39a 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -155,7 +155,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma void UpdateMaxPower(Powers power) override; uint32 GetPowerIndex(Powers power) const override; void UpdateAttackPowerAndDamage(bool ranged = false) override; - void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override; + void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const override; void SetCanDualWield(bool value) override; int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; } diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index f94e8dbe22a..d5657ced163 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -255,7 +255,7 @@ enum CreatureDifficultyFlags7 CREATURE_DIFFICULTYFLAGS_7_UNK1 = 0x00000008 }; -enum CreatureFlagsExtra +enum CreatureFlagsExtra : uint32 { CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) @@ -267,24 +267,37 @@ enum CreatureFlagsExtra CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE = 0x00000200, // creature won't update movement flags + CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will be only visible for dead players + CREATURE_FLAG_EXTRA_UNUSED_11 = 0x00000800, + CREATURE_FLAG_EXTRA_UNUSED_12 = 0x00001000, + CREATURE_FLAG_EXTRA_UNUSED_13 = 0x00002000, CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging) CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard + CREATURE_FLAG_EXTRA_UNUSED_16 = 0x00010000, CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // creature is subject to all diminishing returns as player are CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ = 0x00200000, // creature does not need to take player damage for kill credit + CREATURE_FLAG_EXTRA_UNUSED_22 = 0x00400000, + CREATURE_FLAG_EXTRA_UNUSED_23 = 0x00800000, + CREATURE_FLAG_EXTRA_UNUSED_24 = 0x01000000, + CREATURE_FLAG_EXTRA_UNUSED_25 = 0x02000000, + CREATURE_FLAG_EXTRA_UNUSED_26 = 0x04000000, + CREATURE_FLAG_EXTRA_UNUSED_27 = 0x08000000, CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB) CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000, // creature ignore pathfinding - CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK = 0x40000000 // creature is immune to knockback effects -}; + CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK = 0x40000000, // creature is immune to knockback effects + CREATURE_FLAG_EXTRA_UNUSED_31 = 0x80000000, + + // Masks + CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_11 | CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_13 | + CREATURE_FLAG_EXTRA_UNUSED_16 | CREATURE_FLAG_EXTRA_UNUSED_22 | CREATURE_FLAG_EXTRA_UNUSED_23 | + CREATURE_FLAG_EXTRA_UNUSED_24 | CREATURE_FLAG_EXTRA_UNUSED_25 | CREATURE_FLAG_EXTRA_UNUSED_26 | + CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_31), -#define CREATURE_FLAG_EXTRA_DB_ALLOWED (CREATURE_FLAG_EXTRA_INSTANCE_BIND | CREATURE_FLAG_EXTRA_CIVILIAN | \ - CREATURE_FLAG_EXTRA_NO_PARRY | CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN | CREATURE_FLAG_EXTRA_NO_BLOCK | \ - CREATURE_FLAG_EXTRA_NO_CRUSH | CREATURE_FLAG_EXTRA_NO_XP_AT_KILL | CREATURE_FLAG_EXTRA_TRIGGER | \ - CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \ - CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \ - CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING | CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ | CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK) + CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) +}; const uint32 CREATURE_REGEN_INTERVAL = 2 * IN_MILLISECONDS; const uint32 PET_FOCUS_REGEN_INTERVAL = 4 * IN_MILLISECONDS; diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 05aadcc1709..76be982fdb2 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -598,13 +598,13 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU if (canComplete) { - packet.CompEmoteDelay = quest->EmoteOnCompleteDelay; - packet.CompEmoteType = quest->EmoteOnComplete; + packet.CompEmoteDelay = quest->GetCompleteEmoteDelay(); + packet.CompEmoteType = quest->GetCompleteEmote(); } else { - packet.CompEmoteDelay = quest->EmoteOnIncompleteDelay; - packet.CompEmoteType = quest->EmoteOnIncomplete; + packet.CompEmoteDelay = quest->GetIncompleteEmoteDelay(); + packet.CompEmoteType = quest->GetIncompleteEmote(); } packet.QuestFlags[0] = quest->GetFlags(); diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index 056fe78c99d..c91af442cef 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -120,6 +120,7 @@ class TC_GAME_API Guardian : public Minion void UpdateDamagePhysical(WeaponAttackType attType) override; int32 GetBonusDamage() const { return m_bonusSpellDamage; } + float GetBonusStatFromOwner(Stats stat) const { return m_statFromOwner[stat]; } void SetBonusDamage(int32 damage); protected: int32 m_bonusSpellDamage; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index b9e17565702..4e34c8b4785 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2183,7 +2183,8 @@ void GameObject::EventInform(uint32 eventId, WorldObject* invoker /*= nullptr*/) uint32 GameObject::GetScriptId() const { if (GameObjectData const* gameObjectData = GetGOData()) - return gameObjectData->ScriptId; + if (uint32 scriptId = gameObjectData->ScriptId) + return scriptId; return GetGOInfo()->ScriptId; } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index b34f5e7951d..da06d1842f8 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -280,7 +280,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> void EventInform(uint32 eventId, WorldObject* invoker = NULL); - virtual uint32 GetScriptId() const; + uint32 GetScriptId() const; GameObjectAI* AI() const { return m_AI; } std::string GetAIName() const; @@ -363,7 +363,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> void UpdatePackedRotation(); //! Object distance/size - overridden from Object::_IsWithinDist. Needs to take in account proper GO size. - bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool /*is3D*/) const override + bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool /*is3D*/, bool /*incOwnRadius*/, bool /*incTargetRadius*/) const override { //! Following check does check 3d distance return IsInRange(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), dist2compare); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 57be82a51ef..8b7eea39e98 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -844,7 +844,9 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie SetDurability(durability); // update max durability (and durability) if need SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::MaxDurability), proto->MaxDurability); - if (durability > proto->MaxDurability) + + // do not overwrite durability for wrapped items + if (durability > proto->MaxDurability && !HasItemFlag(ITEM_FIELD_FLAG_WRAPPED)) { SetDurability(proto->MaxDurability); need_save = true; diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 13f0cb7de66..c4c5ee62d5a 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -258,6 +258,7 @@ class TC_GAME_API Item : public Object bool IsNotEmptyBag() const; bool IsBroken() const { return *m_itemData->MaxDurability > 0 && *m_itemData->Durability == 0; } void SetDurability(uint32 durability) { SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::Durability), durability); } + void SetMaxDurability(uint32 maxDurability) { SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::MaxDurability), maxDurability); } bool CanBeTraded(bool mail = false, bool trade = false) const; void SetInTrade(bool b = true) { mb_in_trade = b; } bool IsInTrade() const { return mb_in_trade; } diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index b34b3523fc4..94fd3e932c8 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -969,39 +969,31 @@ InstanceScript* WorldObject::GetInstanceScript() float WorldObject::GetDistanceZ(const WorldObject* obj) const { float dz = std::fabs(GetPositionZ() - obj->GetPositionZ()); - float sizefactor = GetObjectSize() + obj->GetObjectSize(); + float sizefactor = GetCombatReach() + obj->GetCombatReach(); float dist = dz - sizefactor; return (dist > 0 ? dist : 0); } -bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const +bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D, bool incOwnRadius, bool incTargetRadius) const { - float sizefactor = GetObjectSize() + obj->GetObjectSize(); + float sizefactor = 0; + sizefactor += incOwnRadius ? GetCombatReach() : 0.0f; + sizefactor += incTargetRadius ? obj->GetCombatReach() : 0.0f; float maxdist = dist2compare + sizefactor; + Position const* thisOrTransport = this; + Position const* objOrObjTransport = obj; + if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetGUID() == GetTransport()->GetGUID()) { - float dtx = m_movementInfo.transport.pos.m_positionX - obj->m_movementInfo.transport.pos.m_positionX; - float dty = m_movementInfo.transport.pos.m_positionY - obj->m_movementInfo.transport.pos.m_positionY; - float disttsq = dtx * dtx + dty * dty; - if (is3D) - { - float dtz = m_movementInfo.transport.pos.m_positionZ - obj->m_movementInfo.transport.pos.m_positionZ; - disttsq += dtz * dtz; - } - return disttsq < (maxdist * maxdist); + thisOrTransport = &m_movementInfo.transport.pos; + objOrObjTransport = &obj->m_movementInfo.transport.pos; } - float dx = GetPositionX() - obj->GetPositionX(); - float dy = GetPositionY() - obj->GetPositionY(); - float distsq = dx*dx + dy*dy; if (is3D) - { - float dz = GetPositionZ() - obj->GetPositionZ(); - distsq += dz*dz; - } - - return distsq < maxdist * maxdist; + return thisOrTransport->IsInDist(objOrObjTransport, maxdist); + else + return thisOrTransport->IsInDist2d(objOrObjTransport, maxdist); } bool WorldObject::IsWithinLOSInMap(const WorldObject* obj, VMAP::ModelIgnoreFlags ignoreFlags) const @@ -1020,31 +1012,31 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj, VMAP::ModelIgnoreFlag float WorldObject::GetDistance(const WorldObject* obj) const { - float d = GetExactDist(obj) - GetObjectSize() - obj->GetObjectSize(); + float d = GetExactDist(obj) - GetCombatReach() - obj->GetCombatReach(); return d > 0.0f ? d : 0.0f; } float WorldObject::GetDistance(const Position &pos) const { - float d = GetExactDist(&pos) - GetObjectSize(); + float d = GetExactDist(&pos) - GetCombatReach(); return d > 0.0f ? d : 0.0f; } float WorldObject::GetDistance(float x, float y, float z) const { - float d = GetExactDist(x, y, z) - GetObjectSize(); + float d = GetExactDist(x, y, z) - GetCombatReach(); return d > 0.0f ? d : 0.0f; } float WorldObject::GetDistance2d(const WorldObject* obj) const { - float d = GetExactDist2d(obj) - GetObjectSize() - obj->GetObjectSize(); + float d = GetExactDist2d(obj) - GetCombatReach() - obj->GetCombatReach(); return d > 0.0f ? d : 0.0f; } float WorldObject::GetDistance2d(float x, float y) const { - float d = GetExactDist2d(x, y) - GetObjectSize(); + float d = GetExactDist2d(x, y) - GetCombatReach(); return d > 0.0f ? d : 0.0f; } @@ -1064,22 +1056,22 @@ bool WorldObject::IsInMap(const WorldObject* obj) const bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist) const { - return IsInDist(x, y, z, dist + GetObjectSize()); + return IsInDist(x, y, z, dist + GetCombatReach()); } bool WorldObject::IsWithinDist3d(const Position* pos, float dist) const { - return IsInDist(pos, dist + GetObjectSize()); + return IsInDist(pos, dist + GetCombatReach()); } bool WorldObject::IsWithinDist2d(float x, float y, float dist) const { - return IsInDist2d(x, y, dist + GetObjectSize()); + return IsInDist2d(x, y, dist + GetCombatReach()); } bool WorldObject::IsWithinDist2d(const Position* pos, float dist) const { - return IsInDist2d(pos, dist + GetObjectSize()); + return IsInDist2d(pos, dist + GetCombatReach()); } bool WorldObject::IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D /*= true*/) const @@ -1087,9 +1079,9 @@ bool WorldObject::IsWithinDist(WorldObject const* obj, float dist2compare, bool return obj && _IsWithinDist(obj, dist2compare, is3D); } -bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D /*= true*/) const +bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D /*= true*/, bool incOwnRadius /*= true*/, bool incTargetRadius /*= true*/) const { - return obj && IsInMap(obj) && IsInPhase(obj) && _IsWithinDist(obj, dist2compare, is3D); + return obj && IsInMap(obj) && IsInPhase(obj) && _IsWithinDist(obj, dist2compare, is3D, incOwnRadius, incTargetRadius); } bool WorldObject::IsWithinLOS(float ox, float oy, float oz, VMAP::ModelIgnoreFlags ignoreFlags) const @@ -1116,7 +1108,7 @@ Position WorldObject::GetHitSpherePointFor(Position const& dest) const { G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ()); G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ()); - G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * GetObjectSize(); + G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(GetPosition()), GetCombatReach()); return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y)); } @@ -1163,7 +1155,7 @@ bool WorldObject::IsInRange(WorldObject const* obj, float minRange, float maxRan distsq += dz*dz; } - float sizefactor = GetObjectSize() + obj->GetObjectSize(); + float sizefactor = GetCombatReach() + obj->GetCombatReach(); // check only for real range if (minRange > 0.0f) @@ -1183,7 +1175,7 @@ bool WorldObject::IsInRange2d(float x, float y, float minRange, float maxRange) float dy = GetPositionY() - y; float distsq = dx*dx + dy*dy; - float sizefactor = GetObjectSize(); + float sizefactor = GetCombatReach(); // check only for real range if (minRange > 0.0f) @@ -1204,7 +1196,7 @@ bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float m float dz = GetPositionZ() - z; float distsq = dx*dx + dy*dy + dz*dz; - float sizefactor = GetObjectSize(); + float sizefactor = GetCombatReach(); // check only for real range if (minRange > 0.0f) @@ -1227,7 +1219,7 @@ bool WorldObject::IsInBetween(Position const& pos1, Position const& pos2, float return false; if (!size) - size = GetObjectSize() / 2; + size = GetCombatReach() / 2; float angle = pos1.GetAngle(pos2); @@ -1837,7 +1829,7 @@ TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, fl { if (!x && !y && !z) { - GetClosePoint(x, y, z, GetObjectSize()); + GetClosePoint(x, y, z, GetCombatReach()); ang = GetOrientation(); } @@ -1879,7 +1871,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float { if (!x && !y && !z) { - GetClosePoint(x, y, z, GetObjectSize()); + GetClosePoint(x, y, z, GetCombatReach()); ang = GetOrientation(); } @@ -1993,8 +1985,8 @@ void WorldObject::GetPlayerListInGrid(Container& playerContainer, float maxSearc void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle) const { - x = GetPositionX() + (GetObjectSize() + distance2d) * std::cos(absAngle); - y = GetPositionY() + (GetObjectSize() + distance2d) * std::sin(absAngle); + x = GetPositionX() + (GetCombatReach() + distance2d) * std::cos(absAngle); + y = GetPositionY() + (GetCombatReach() + distance2d) * std::sin(absAngle); Trinity::NormalizeMapCoord(x); Trinity::NormalizeMapCoord(y); @@ -2066,15 +2058,7 @@ Position WorldObject::GetRandomNearPosition(float radius) void WorldObject::GetContactPoint(const WorldObject* obj, float &x, float &y, float &z, float distance2d /*= CONTACT_DISTANCE*/) const { // angle to face `obj` to `this` using distance includes size of `obj` - GetNearPoint(obj, x, y, z, obj->GetObjectSize(), distance2d, GetAngle(obj)); -} - -float WorldObject::GetObjectSize() const -{ - if (Unit const* thisUnit = ToUnit()) - return thisUnit->m_unitData->CombatReach; - - return DEFAULT_WORLD_OBJECT_SIZE; + GetNearPoint(obj, x, y, z, obj->GetCombatReach(), distance2d, GetAngle(obj)); } void WorldObject::MovePosition(Position &pos, float dist, float angle) diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index c5e22c86c3a..1d48e1f2384 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -395,7 +395,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation Position GetRandomNearPosition(float radius); void GetContactPoint(WorldObject const* obj, float &x, float &y, float &z, float distance2d = CONTACT_DISTANCE) const; - float GetObjectSize() const; + virtual float GetCombatReach() const { return 0.0f; } // overridden (only) in Unit void UpdateGroundPositionZ(float x, float y, float &z) const; void UpdateAllowedPositionZ(float x, float y, float &z) const; @@ -445,7 +445,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation bool IsWithinDist2d(Position const* pos, float dist) const; // use only if you will sure about placing both object at same map bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const; - bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const; + bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true, bool incOwnRadius = true, bool incTargetRadius = true) const; bool IsWithinLOS(float x, float y, float z, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing) const; bool IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing) const; Position GetHitSpherePointFor(Position const& dest) const; @@ -605,7 +605,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation uint16 m_notifyflags; uint16 m_executed_notifies; - virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const; + virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D, bool incOwnRadius = true, bool incTargetRadius = true) const; bool CanNeverSee(WorldObject const* obj) const; virtual bool CanAlwaysSee(WorldObject const* /*obj*/) const { return false; } diff --git a/src/server/game/Entities/Object/ObjectDefines.h b/src/server/game/Entities/Object/ObjectDefines.h index b0db49bcf9f..43f2ea15a4d 100644 --- a/src/server/game/Entities/Object/ObjectDefines.h +++ b/src/server/game/Entities/Object/ObjectDefines.h @@ -36,11 +36,11 @@ #define DEFAULT_VISIBILITY_INSTANCE 170.0f // default visible distance in instances, 170 yards #define DEFAULT_VISIBILITY_BGARENAS 533.0f // default visible distance in BG/Arenas, roughly 533 yards -#define DEFAULT_WORLD_OBJECT_SIZE 0.388999998569489f // player size, also currently used (correctly?) for any non Unit world objects -#define DEFAULT_COMBAT_REACH 1.5f -#define MIN_MELEE_REACH 2.0f -#define NOMINAL_MELEE_RANGE 5.0f -#define MELEE_RANGE (NOMINAL_MELEE_RANGE - MIN_MELEE_REACH * 2) //center to center for players +#define DEFAULT_PLAYER_BOUNDING_RADIUS 0.388999998569489f // player size, also currently used (correctly?) for any non Unit world objects +#define DEFAULT_PLAYER_COMBAT_REACH 1.5f +#define MIN_MELEE_REACH 2.0f +#define NOMINAL_MELEE_RANGE 5.0f +#define MELEE_RANGE (NOMINAL_MELEE_RANGE - MIN_MELEE_REACH * 2) //center to center for players enum class VisibilityDistanceType : uint8 { diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp index ae0fc14e173..a63a3da76d6 100644 --- a/src/server/game/Entities/Object/Position.cpp +++ b/src/server/game/Entities/Object/Position.cpp @@ -148,6 +148,12 @@ bool Position::IsWithinBox(const Position& center, float xradius, float yradius, return true; } +bool Position::IsWithinDoubleVerticalCylinder(Position const* center, float radius, float height) const +{ + float verticalDelta = GetPositionZ() - center->GetPositionZ(); + return IsInDist2d(center, radius) && std::abs(verticalDelta) <= height; +} + bool Position::HasInArc(float arc, const Position* obj, float border) const { // always have self in arc diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h index 37f1231e709..f247c7fb860 100644 --- a/src/server/game/Entities/Object/Position.h +++ b/src/server/game/Entities/Object/Position.h @@ -218,6 +218,11 @@ public: } bool IsWithinBox(const Position& center, float xradius, float yradius, float zradius) const; + + /* + search using this relation: dist2d < radius && abs(dz) < height + */ + bool IsWithinDoubleVerticalCylinder(Position const* center, float radius, float height) const; bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const; bool HasInLine(Position const* pos, float objSize, float width) const; std::string ToString() const; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 7563289b480..9c16502dd25 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -192,7 +192,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c if (IsCritter()) { float px, py, pz; - owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, GetFollowAngle()); + owner->GetClosePoint(px, py, pz, GetCombatReach(), PET_FOLLOW_DIST, GetFollowAngle()); Relocate(px, py, pz, owner->GetOrientation()); if (!IsPositionValid()) @@ -245,7 +245,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c // Set pet's position after setting level, its size depends on it float px, py, pz; - owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, GetFollowAngle()); + owner->GetClosePoint(px, py, pz, GetCombatReach(), PET_FOLLOW_DIST, GetFollowAngle()); Relocate(px, py, pz, owner->GetOrientation()); if (!IsPositionValid()) { @@ -375,6 +375,8 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c if (owner->GetTypeId() == TYPEID_PLAYER && isControlled() && !isTemporarySummoned() && (getPetType() == SUMMON_PET || getPetType() == HUNTER_PET)) owner->ToPlayer()->SetLastPetNumber(petId); + // must be after SetMinion (owner guid check) + LoadMechanicTemplateImmunity(); m_loading = false; return true; @@ -794,7 +796,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel*50)); + SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50)); SetBaseAttackTime(BASE_ATTACK, BASE_ATTACK_TIME); SetBaseAttackTime(OFF_ATTACK, BASE_ATTACK_TIME); @@ -819,7 +821,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) // Hunters pet should not inherit resistances from creature_template, they have separate auras for that if (!IsHunterPet()) for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i])); + SetStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i])); // Health, Mana or Power, Armor PetLevelInfo const* pInfo = sObjectMgr->GetPetLevelInfo(creature_ID, petlevel); @@ -829,7 +831,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetCreateMana(pInfo->mana); if (pInfo->armor > 0) - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor)); + SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor)); for (uint8 stat = 0; stat < MAX_STATS; ++stat) SetCreateStat(Stats(stat), float(pInfo->stats[stat])); @@ -875,7 +877,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4))); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4))); - //SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower)); + //SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower)); break; } case HUNTER_PET: @@ -963,8 +965,8 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float((petlevel * 4 - petlevel))); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((petlevel * 4 + petlevel))); - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetOwner()->GetArmor()) * 0.35f); // Bonus Armor (35% of player armor) - SetModifierValue(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(GetOwner()->GetStat(STAT_STAMINA)) * 0.3f); // Bonus Stamina (30% of player stamina) + SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(GetOwner()->GetArmor()) * 0.35f); // Bonus Armor (35% of player armor) + SetStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(GetOwner()->GetStat(STAT_STAMINA)) * 0.3f); // Bonus Stamina (30% of player stamina) if (!HasAura(58877))//prevent apply twice for the 2 wolves AddAura(58877, this);//Spirit Hunt, passive, Spirit Wolves' attacks heal them and their master for 150% of damage done. break; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index daeaf3d8877..5f2199d9f52 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -269,8 +269,8 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this) for (uint8 i = 0; i < BASEMOD_END; ++i) { - m_auraBaseMod[i][FLAT_MOD] = 0.0f; - m_auraBaseMod[i][PCT_MOD] = 1.0f; + m_auraBaseFlatMod[i] = 0.0f; + m_auraBasePctMod[i] = 1.0f; } for (uint8 i = 0; i < MAX_COMBAT_RATING; i++) @@ -1767,8 +1767,8 @@ void Player::RemoveFromWorld() void Player::SetObjectScale(float scale) { Unit::SetObjectScale(scale); - SetBoundingRadius(scale * DEFAULT_WORLD_OBJECT_SIZE); - SetCombatReach(scale * DEFAULT_COMBAT_REACH); + SetBoundingRadius(scale * DEFAULT_PLAYER_BOUNDING_RADIUS); + SetCombatReach(scale * DEFAULT_PLAYER_COMBAT_REACH); if (IsInWorld()) SendMovementSetCollisionHeight(scale * GetCollisionHeight(IsMounted())); } @@ -4952,20 +4952,104 @@ void Player::LeaveLFGChannel() } } -void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply) +void Player::HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply) { - if (modGroup >= BASEMOD_END || modType >= MOD_END) + if (modGroup >= BASEMOD_END) { TC_LOG_ERROR("spells", "Player::HandleBaseModValue: Invalid BaseModGroup/BaseModType (%u/%u) for player '%s' (%s)", - modGroup, modType, GetName().c_str(), GetGUID().ToString().c_str()); + modGroup, FLAT_MOD, GetName().c_str(), GetGUID().ToString().c_str()); + return; + } + + m_auraBaseFlatMod[modGroup] += apply ? amount : -amount; + UpdateBaseModGroup(modGroup); +} + +void Player::ApplyBaseModPctValue(BaseModGroup modGroup, float pct) +{ + if (modGroup >= BASEMOD_END) + { + TC_LOG_ERROR("spells", "Player::HandleBaseModValue: Invalid BaseModGroup/BaseModType (%u/%u) for player '%s' (%s)", + modGroup, FLAT_MOD, GetName().c_str(), GetGUID().ToString().c_str()); + return; + } + + AddPct(m_auraBasePctMod[modGroup], pct); + UpdateBaseModGroup(modGroup); +} + +void Player::SetBaseModFlatValue(BaseModGroup modGroup, float val) +{ + if (m_auraBaseFlatMod[modGroup] == val) + return; + + m_auraBaseFlatMod[modGroup] = val; + UpdateBaseModGroup(modGroup); +} + +void Player::SetBaseModPctValue(BaseModGroup modGroup, float val) +{ + if (m_auraBasePctMod[modGroup] == val) return; + + m_auraBasePctMod[modGroup] = val; + UpdateBaseModGroup(modGroup); +} + +void Player::UpdateDamageDoneMods(WeaponAttackType attackType) +{ + Unit::UpdateDamageDoneMods(attackType); + + UnitMods unitMod; + switch (attackType) + { + case BASE_ATTACK: + unitMod = UNIT_MOD_DAMAGE_MAINHAND; + break; + case OFF_ATTACK: + unitMod = UNIT_MOD_DAMAGE_OFFHAND; + break; + case RANGED_ATTACK: + unitMod = UNIT_MOD_DAMAGE_RANGED; + break; + default: + ABORT(); + break; } - if (modType == FLAT_MOD) - m_auraBaseMod[modGroup][modType] += apply ? amount : -amount; - else // PCT_MOD - ApplyPercentModFloatVar(m_auraBaseMod[modGroup][modType], amount, apply); + float amount = 0.0f; + Item* item = GetWeaponForAttack(attackType, true); + if (!item) + return; + for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) + { + SpellItemEnchantmentEntry const* enchantmentEntry = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot))); + if (!enchantmentEntry) + continue; + + for (uint8 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i) + { + switch (enchantmentEntry->Effect[i]) + { + case ITEM_ENCHANTMENT_TYPE_DAMAGE: + amount += enchantmentEntry->EffectScalingPoints[i]; + break; + case ITEM_ENCHANTMENT_TYPE_TOTEM: + if (getClass() == CLASS_SHAMAN) + amount += enchantmentEntry->EffectScalingPoints[i] * item->GetTemplate()->GetDelay() / 1000.0f; + break; + default: + break; + } + } + } + + HandleStatFlatModifier(unitMod, TOTAL_VALUE, amount, true); +} + +void Player::UpdateBaseModGroup(BaseModGroup modGroup) +{ if (!CanModifyStats()) return; @@ -4987,10 +5071,7 @@ float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const return 0.0f; } - if (modType == PCT_MOD && m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f) - return 0.0f; - - return m_auraBaseMod[modGroup][modType]; + return (modType == FLAT_MOD ? m_auraBaseFlatMod[modGroup] : m_auraBasePctMod[modGroup]); } float Player::GetTotalBaseModValue(BaseModGroup modGroup) const @@ -5002,10 +5083,7 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const return 0.0f; } - if (m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f) - return 0.0f; - - return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD]; + return m_auraBaseFlatMod[modGroup] * m_auraBasePctMod[modGroup]; } void Player::GetDodgeFromAgility(float &/*diminishing*/, float &/*nondiminishing*/) const @@ -5053,7 +5131,7 @@ void Player::GetDodgeFromAgility(float &/*diminishing*/, float &/*nondiminishing // return; ///// @todo research if talents/effects that increase total agility by x% should increase non-diminishing part - //float base_agility = GetCreateStat(STAT_AGILITY) * m_auraModifiersGroup[UNIT_MOD_STAT_START + STAT_AGILITY][BASE_PCT]; + //float base_agility = GetCreateStat(STAT_AGILITY) * GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + STAT_AGILITY), BASE_PCT); //float bonus_agility = GetStat(STAT_AGILITY) - base_agility; //// calculate diminishing (green in char screen) and non-diminishing (white) contribution @@ -5312,7 +5390,7 @@ void Player::UpdateRating(CombatRating cr) void Player::UpdateAllRatings() { - for (int cr = 0; cr < MAX_COMBAT_RATING; ++cr) + for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr) UpdateRating(CombatRating(cr)); } @@ -7419,7 +7497,13 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemA _ApplyItemBonuses(item, slot, apply); ApplyItemEquipSpell(item, apply); if (updateItemAuras) + { ApplyItemDependentAuras(item, apply); + + WeaponAttackType const attackType = Player::GetAttackBySlot(slot, item->GetTemplate()->GetInventoryType()); + if (attackType != MAX_ATTACK) + UpdateWeaponDependentAuras(attackType); + } ApplyArtifactPowers(item, apply); ApplyAzeritePowers(item, apply); ApplyEnchantment(item, apply); @@ -7452,22 +7536,22 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) switch (statType) { case ITEM_MOD_MANA: - HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply); break; case ITEM_MOD_HEALTH: // modify HP - HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply); break; case ITEM_MOD_AGILITY: // modify agility - HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_AGILITY); break; case ITEM_MOD_STRENGTH: //modify strength - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_STRENGTH); break; case ITEM_MOD_INTELLECT: //modify intellect - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_INTELLECT); break; // case ITEM_MOD_SPIRIT: //modify spirit // HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply); @@ -7477,8 +7561,8 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) { if (GtStaminaMultByILvl const* staminaMult = sStaminaMultByILvlGameTable.GetRow(itemLevel)) val = int32(val * GetIlvlStatMultiplier(staminaMult, proto->GetInventoryType())); - HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STAMINA, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STAMINA, BASE_PCT_EXCLUDE_CREATE)), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_STAMINA); break; } case ITEM_MOD_DEFENSE_SKILL_RATING: @@ -7570,11 +7654,11 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) ApplyRatingMod(CR_EXPERTISE, int32(val * combatRatingMultiplier), apply); break; case ITEM_MOD_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply); - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); break; case ITEM_MOD_RANGED_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); break; case ITEM_MOD_VERSATILITY: ApplyRatingMod(CR_VERSATILITY_DAMAGE_DONE, int32(val * combatRatingMultiplier), apply); @@ -7600,25 +7684,25 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) ApplyRatingMod(CR_MASTERY, int32(val * combatRatingMultiplier), apply); break; case ITEM_MOD_EXTRA_ARMOR: - HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(val), apply); break; case ITEM_MOD_FIRE_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(val), apply); break; case ITEM_MOD_FROST_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(val), apply); break; case ITEM_MOD_HOLY_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(val), apply); break; case ITEM_MOD_SHADOW_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(val), apply); break; case ITEM_MOD_NATURE_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(val), apply); break; case ITEM_MOD_ARCANE_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(val), apply); break; case ITEM_MOD_PVP_POWER: ApplyRatingMod(CR_PVP_POWER, int32(val), apply); @@ -7654,36 +7738,36 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) ApplyRatingMod(CR_UNUSED_12, int32(val), apply); break; case ITEM_MOD_AGI_STR_INT: - HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); - ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); - ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_AGILITY); + UpdateStatBuffMod(STAT_STRENGTH); + UpdateStatBuffMod(STAT_INTELLECT); break; case ITEM_MOD_AGI_STR: - HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); - ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_AGILITY); + UpdateStatBuffMod(STAT_STRENGTH); break; case ITEM_MOD_AGI_INT: - HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); - ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_AGILITY); + UpdateStatBuffMod(STAT_INTELLECT); break; case ITEM_MOD_STR_INT: - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); - ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_STRENGTH); + UpdateStatBuffMod(STAT_INTELLECT); break; } } if (uint32 armor = item->GetArmor(this)) - HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(armor), apply); + HandleStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(armor), apply); WeaponAttackType attType = BASE_ATTACK; @@ -7775,6 +7859,49 @@ void Player::ApplyItemObtainSpells(Item* item, bool apply) } } +// this one rechecks weapon auras and stores them in BaseModGroup container +// needed for things like axe specialization applying only to axe weapons in case of dual-wield +void Player::UpdateWeaponDependentCritAuras(WeaponAttackType attackType) +{ + BaseModGroup modGroup; + switch (attackType) + { + case BASE_ATTACK: + modGroup = CRIT_PERCENTAGE; + break; + case OFF_ATTACK: + modGroup = OFFHAND_CRIT_PERCENTAGE; + break; + case RANGED_ATTACK: + modGroup = RANGED_CRIT_PERCENTAGE; + break; + default: + ABORT(); + break; + } + + float amount = 0.0f; + amount += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1)); + + // these auras don't have item requirement (only Combat Expertise in 3.3.5a) + amount += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT); + + SetBaseModFlatValue(modGroup, amount); +} + +void Player::UpdateAllWeaponDependentCritAuras() +{ + for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i) + UpdateWeaponDependentCritAuras(WeaponAttackType(i)); +} + +void Player::UpdateWeaponDependentAuras(WeaponAttackType attackType) +{ + UpdateWeaponDependentCritAuras(attackType); + UpdateDamageDoneMods(attackType); + UpdateDamagePctDoneMods(attackType); +} + void Player::ApplyItemDependentAuras(Item* item, bool apply) { if (apply) @@ -7797,6 +7924,19 @@ void Player::ApplyItemDependentAuras(Item* item, bool apply) RemoveItemDependentAurasAndCasts(item); } +bool Player::CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const +{ + SpellInfo const* spellInfo = aurEff->GetSpellInfo(); + if (spellInfo->EquippedItemClass == -1) + return true; + + Item* item = GetWeaponForAttack(attackType, true); + if (!item || !item->IsFitToSpellRequirements(spellInfo)) + return false; + + return true; +} + void Player::ApplyItemEquipSpell(Item* item, bool apply, bool formChange /*= false*/) { if (!item) @@ -8427,6 +8567,10 @@ void Player::_ApplyAllItemMods() ApplyItemDependentAuras(m_items[i], true); _ApplyItemBonuses(m_items[i], i, true); + + WeaponAttackType const attackType = Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType()); + if (attackType != MAX_ATTACK) + UpdateWeaponDependentAuras(attackType); } } @@ -10094,7 +10238,7 @@ Item* Player::GetChildItemByGuid(ObjectGuid guid) const return nullptr; } -uint8 Player::GetAttackBySlot(uint8 slot, InventoryType inventoryType) +WeaponAttackType Player::GetAttackBySlot(uint8 slot, InventoryType inventoryType) { switch (slot) { @@ -14124,16 +14268,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool // processed in Player::CastItemCombatSpell break; case ITEM_ENCHANTMENT_TYPE_DAMAGE: - if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) - { - if (item->GetTemplate()->GetInventoryType() != INVTYPE_RANGED && item->GetTemplate()->GetInventoryType() != INVTYPE_RANGEDRIGHT) - HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(enchant_amount), apply); - else - HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(enchant_amount), apply); - } - else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND) - HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(enchant_amount), apply); + { + WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot(), item->GetTemplate()->GetInventoryType()); + if (attackType != MAX_ATTACK) + UpdateDamageDoneMods(attackType); break; + } case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL: if (enchant_spell_id) { @@ -14163,7 +14303,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool enchant_amount = uint32(pEnchant->EffectScalingPoints[s] * GetSpellScalingColumnForClass(spellScaling, scalingClass)); } enchant_amount = std::max(enchant_amount, 1u); - HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply); break; case ITEM_ENCHANTMENT_TYPE_STAT: { @@ -14193,26 +14333,26 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool { case ITEM_MOD_MANA: TC_LOG_DEBUG("entities.player.items", "+ %u MANA", enchant_amount); - HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply); break; case ITEM_MOD_HEALTH: TC_LOG_DEBUG("entities.player.items", "+ %u HEALTH", enchant_amount); - HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply); break; case ITEM_MOD_AGILITY: TC_LOG_DEBUG("entities.player.items", "+ %u AGILITY", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_AGILITY, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_AGILITY); break; case ITEM_MOD_STRENGTH: TC_LOG_DEBUG("entities.player.items", "+ %u STRENGTH", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_STRENGTH, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_STRENGTH); break; case ITEM_MOD_INTELLECT: TC_LOG_DEBUG("entities.player.items", "+ %u INTELLECT", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_INTELLECT, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_INTELLECT); break; // case ITEM_MOD_SPIRIT: // TC_LOG_DEBUG("entities.player.items", "+ %u SPIRIT", enchant_amount); @@ -14221,8 +14361,8 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool // break; case ITEM_MOD_STAMINA: TC_LOG_DEBUG("entities.player.items", "+ %u STAMINA", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_STAMINA, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_STAMINA); break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply); @@ -14330,12 +14470,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool TC_LOG_DEBUG("entities.player.items", "+ %u EXPERTISE", enchant_amount); break; case ITEM_MOD_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply); - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); TC_LOG_DEBUG("entities.player.items", "+ %u ATTACK_POWER", enchant_amount); break; case ITEM_MOD_RANGED_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); TC_LOG_DEBUG("entities.player.items", "+ %u RANGED_ATTACK_POWER", enchant_amount); break; case ITEM_MOD_MANA_REGENERATION: @@ -14359,7 +14499,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool TC_LOG_DEBUG("entities.player.items", "+ %u SPELL_PENETRATION", enchant_amount); break; case ITEM_MOD_BLOCK_VALUE: - HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(enchant_amount), apply); + HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(enchant_amount), apply); TC_LOG_DEBUG("entities.player.items", "+ %u BLOCK_VALUE", enchant_amount); break; case ITEM_MOD_MASTERY_RATING: @@ -14379,20 +14519,9 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool } case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon { - if (getClass() == CLASS_SHAMAN) - { - float addValue; - if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) - { - addValue = float(enchant_amount * item->GetTemplate()->GetDelay() / 1000.0f); - HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply); - } - else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND) - { - addValue = float(enchant_amount * item->GetTemplate()->GetDelay() / 1000.0f); - HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, addValue, apply); - } - } + WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot(), item->GetTemplate()->GetInventoryType()); + if (attackType != MAX_ATTACK) + UpdateDamageDoneMods(attackType); break; } case ITEM_ENCHANTMENT_TYPE_USE_SPELL: @@ -15075,7 +15204,7 @@ bool Player::CanSeeStartQuest(Quest const* quest) { if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) && SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) && - SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) && + SatisfyQuestDependentQuests(quest, false) && SatisfyQuestNextChain(quest, false) && SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) && SatisfyQuestMonth(quest, false) && SatisfyQuestSeasonal(quest, false)) { @@ -15091,7 +15220,7 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg) && SatisfyQuestStatus(quest, msg) && SatisfyQuestExclusiveGroup(quest, msg) && SatisfyQuestClass(quest, msg) && SatisfyQuestRace(quest, msg) && SatisfyQuestLevel(quest, msg) && SatisfyQuestSkill(quest, msg) && SatisfyQuestReputation(quest, msg) - && SatisfyQuestPreviousQuest(quest, msg) && SatisfyQuestTimed(quest, msg) + && SatisfyQuestDependentQuests(quest, msg) && SatisfyQuestTimed(quest, msg) && SatisfyQuestNextChain(quest, msg) && SatisfyQuestPrevChain(quest, msg) && SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg) && SatisfyQuestMonth(quest, msg) && SatisfyQuestSeasonal(quest, msg) @@ -15956,97 +16085,90 @@ bool Player::SatisfyQuestLog(bool msg) const return false; } -bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestDependentQuests(Quest const* qInfo, bool msg) const +{ + return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg); +} + +bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const { // No previous quest (might be first quest in a series) - if (qInfo->prevQuests.empty()) + if (!qInfo->GetPrevQuestId()) return true; - for (Quest::PrevQuests::const_iterator iter = qInfo->prevQuests.begin(); iter != qInfo->prevQuests.end(); ++iter) - { - uint32 prevId = abs(*iter); + uint32 prevId = std::abs(qInfo->GetPrevQuestId()); + // If positive previous quest rewarded, return true + if (qInfo->GetPrevQuestId() > 0 && m_RewardedQuests.count(prevId) > 0) + return true; - Quest const* qPrevInfo = sObjectMgr->GetQuestTemplate(prevId); + // If negative previous quest active, return true + if (qInfo->GetPrevQuestId() < 0 && GetQuestStatus(prevId) == QUEST_STATUS_INCOMPLETE) + return true; - if (qPrevInfo) - { - // If any of the positive previous quests completed, return true - if (*iter > 0 && m_RewardedQuests.find(prevId) != m_RewardedQuests.end()) - { - // skip one-from-all exclusive group - if (qPrevInfo->GetExclusiveGroup() >= 0) - return true; + // Has positive prev. quest in non-rewarded state + // and negative prev. quest in non-active state + if (msg) + { + SendCanTakeQuestResponse(QUEST_ERR_NONE); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent QUEST_ERR_NONE (QuestID: %u) because player '%s' (%s) doesn't have required quest %u.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str(), prevId); + } - // each-from-all exclusive group (< 0) - // can be start if only all quests in prev quest exclusive group completed and rewarded - ObjectMgr::ExclusiveQuestGroupsBounds range(sObjectMgr->mExclusiveQuestGroups.equal_range(qPrevInfo->GetExclusiveGroup())); + return false; +} - for (; range.first != range.second; ++range.first) - { - uint32 exclude_Id = range.first->second; +bool Player::SatisfyQuestDependentPreviousQuests(Quest const* qInfo, bool msg) const +{ + // No previous quest (might be first quest in a series) + if (qInfo->DependentPreviousQuests.empty()) + return true; - // skip checked quest id, only state of other quests in group is interesting - if (exclude_Id == prevId) - continue; + for (uint32 prevId : qInfo->DependentPreviousQuests) + { + // checked in startup + Quest const* questInfo = sObjectMgr->GetQuestTemplate(prevId); + ASSERT(questInfo); - // alternative quest from group also must be completed and rewarded (reported) - if (m_RewardedQuests.find(exclude_Id) == m_RewardedQuests.end()) - { - if (msg) - { - SendCanTakeQuestResponse(QUEST_ERR_NONE); - TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent QUEST_ERR_NONE (QuestID: %u) because player '%s' (%s) doesn't have the required quest (1).", - qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); - } - return false; - } - } + // If any of the previous quests completed, return true + if (IsQuestRewarded(prevId)) + { + // skip one-from-all exclusive group + if (questInfo->GetExclusiveGroup() >= 0) return true; - } - // If any of the negative previous quests active, return true - if (*iter < 0 && GetQuestStatus(prevId) != QUEST_STATUS_NONE) + // each-from-all exclusive group (< 0) + // can be start if only all quests in prev quest exclusive group completed and rewarded + auto bounds = sObjectMgr->GetExclusiveQuestGroupBounds(questInfo->GetExclusiveGroup()); + for (auto itr = bounds.first; itr != bounds.second; ++itr) { - // skip one-from-all exclusive group - if (qPrevInfo->GetExclusiveGroup() >= 0) - return true; - - // each-from-all exclusive group (< 0) - // can be start if only all quests in prev quest exclusive group active - ObjectMgr::ExclusiveQuestGroupsBounds range(sObjectMgr->mExclusiveQuestGroups.equal_range(qPrevInfo->GetExclusiveGroup())); + // skip checked quest id, only state of other quests in group is interesting + uint32 exclusiveQuestId = itr->second; + if (exclusiveQuestId == prevId) + continue; - for (; range.first != range.second; ++range.first) + // alternative quest from group also must be completed and rewarded (reported) + if (!IsQuestRewarded(exclusiveQuestId)) { - uint32 exclude_Id = range.first->second; - - // skip checked quest id, only state of other quests in group is interesting - if (exclude_Id == prevId) - continue; - - // alternative quest from group also must be active - if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE) + if (msg) { - if (msg) - { - SendCanTakeQuestResponse(QUEST_ERR_NONE); - TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent QUEST_ERR_NONE (QuestID: %u) because player '%s' (%s) doesn't have the required quest (2).", - qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); - - } - return false; + SendCanTakeQuestResponse(QUEST_ERR_NONE); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentPreviousQuests: Sent QUEST_ERR_NONE (QuestID: %u) because player '%s' (%s) doesn't have the required quest (1).", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } + + return false; } - return true; } + + return true; } } - // Has only positive prev. quests in non-rewarded state - // and negative prev. quests in non-active state + // Has only prev. quests in non-rewarded state if (msg) { SendCanTakeQuestResponse(QUEST_ERR_NONE); - TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent QUEST_ERR_NONE (QuestID: %u) because player '%s' (%s) doesn't have required quest (3).", + TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentPreviousQuests: Sent QUEST_ERR_NONE (QuestID: %u) because player '%s' (%s) doesn't have required quest (2).", qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } @@ -16191,17 +16313,16 @@ bool Player::SatisfyQuestTimed(Quest const* qInfo, bool msg) const return true; } -bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const { // non positive exclusive group, if > 0 then can be start if any other quest in exclusive group already started/completed if (qInfo->GetExclusiveGroup() <= 0) return true; - ObjectMgr::ExclusiveQuestGroupsBounds range(sObjectMgr->mExclusiveQuestGroups.equal_range(qInfo->GetExclusiveGroup())); - - for (; range.first != range.second; ++range.first) + auto bounds = sObjectMgr->GetExclusiveQuestGroupBounds(qInfo->GetExclusiveGroup()); + for (auto itr = bounds.first; itr != bounds.second; ++itr) { - uint32 exclude_Id = range.first->second; + uint32 exclude_Id = itr->second; // skip checked quest id, only state of other quests in group is interesting if (exclude_Id == qInfo->GetQuestId()) @@ -16264,12 +16385,12 @@ bool Player::SatisfyQuestNextChain(Quest const* qInfo, bool msg) const bool Player::SatisfyQuestPrevChain(Quest const* qInfo, bool msg) { // No previous quest in chain - if (qInfo->prevChainQuests.empty()) + if (qInfo->PrevChainQuests.empty()) return true; - for (Quest::PrevChainQuests::const_iterator iter = qInfo->prevChainQuests.begin(); iter != qInfo->prevChainQuests.end(); ++iter) + for (uint32 prevQuestId : qInfo->PrevChainQuests) { - QuestStatusMap::const_iterator itr = m_QuestStatus.find(*iter); + auto itr = m_QuestStatus.find(prevQuestId); // If any of the previous quests in chain active, return false if (itr != m_QuestStatus.end() && itr->second.Status != QUEST_STATUS_NONE) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 476aa0d7492..acbc5dd6086 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1128,8 +1128,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const; Item* GetShield(bool useable = false) const; Item* GetChildItemByGuid(ObjectGuid guid) const; - static uint8 GetAttackBySlot(uint8 slot, InventoryType inventoryType); // MAX_ATTACK if not weapon slot - std::vector<Item*> &GetItemUpdateQueue() { return m_itemUpdateQueue; } + static WeaponAttackType GetAttackBySlot(uint8 slot, InventoryType inventoryType); // MAX_ATTACK if not weapon slot + std::vector<Item*>& GetItemUpdateQueue() { return m_itemUpdateQueue; } static bool IsInventoryPos(uint16 pos) { return IsInventoryPos(pos >> 8, pos & 255); } static bool IsInventoryPos(uint8 bag, uint8 slot); static bool IsEquipmentPos(uint16 pos) { return IsEquipmentPos(pos >> 8, pos & 255); } @@ -1342,14 +1342,16 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const; bool SatisfyQuestLevel(Quest const* qInfo, bool msg) const; bool SatisfyQuestLog(bool msg) const; - bool SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg); + bool SatisfyQuestDependentQuests(Quest const* qInfo, bool msg) const; + bool SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const; + bool SatisfyQuestDependentPreviousQuests(Quest const* qInfo, bool msg) const; bool SatisfyQuestClass(Quest const* qInfo, bool msg) const; bool SatisfyQuestRace(Quest const* qInfo, bool msg) const; bool SatisfyQuestReputation(Quest const* qInfo, bool msg); bool SatisfyQuestStatus(Quest const* qInfo, bool msg) const; bool SatisfyQuestConditions(Quest const* qInfo, bool msg); bool SatisfyQuestTimed(Quest const* qInfo, bool msg) const; - bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg); + bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const; bool SatisfyQuestNextChain(Quest const* qInfo, bool msg) const; bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg); bool SatisfyQuestDay(Quest const* qInfo, bool msg) const; @@ -1771,6 +1773,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void ApplyModDamageDonePos(SpellSchools school, int32 mod, bool apply) { ApplyModUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ModDamageDonePos, school), mod, apply); } void ApplyModDamageDoneNeg(SpellSchools school, int32 mod, bool apply) { ApplyModUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ModDamageDoneNeg, school), mod, apply); } void ApplyModDamageDonePercent(SpellSchools school, float pct, bool apply) { ApplyPercentModUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ModDamageDonePercent, school), pct, apply); } + void SetModDamageDonePercent(uint8 school, float pct) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ModDamageDonePercent, school), pct); } void ApplyRatingMod(CombatRating cr, int32 value, bool apply); void UpdateRating(CombatRating cr); void UpdateAllRatings(); @@ -1779,7 +1782,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void UpdateHealingDonePercentMod(); bool CanUseMastery() const; - void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override; + void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const override; void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);} void GetDodgeFromAgility(float &diminishing, float &nondiminishing) const; @@ -2003,11 +2006,19 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool CanTameExoticPets() const { return IsGameMaster() || HasAuraType(SPELL_AURA_ALLOW_TAME_PET_TYPE); } void SetRegularAttackTime(); - void SetBaseModValue(BaseModGroup modGroup, BaseModType modType, float value) { m_auraBaseMod[modGroup][modType] = value; } - void HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply); + + void HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply); + void ApplyBaseModPctValue(BaseModGroup modGroup, float pct); + + void SetBaseModFlatValue(BaseModGroup modGroup, float val); + void SetBaseModPctValue(BaseModGroup modGroup, float val); + + void UpdateDamageDoneMods(WeaponAttackType attackType) override; + void UpdateBaseModGroup(BaseModGroup modGroup); + float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const; float GetTotalBaseModValue(BaseModGroup modGroup) const; - float GetTotalPercentageModValue(BaseModGroup modGroup) const { return m_auraBaseMod[modGroup][FLAT_MOD] + m_auraBaseMod[modGroup][PCT_MOD]; } + void _ApplyAllStatBonuses(); void _RemoveAllStatBonuses(); @@ -2015,8 +2026,15 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void CastAllObtainSpells(); void ApplyItemObtainSpells(Item* item, bool apply); + + void UpdateWeaponDependentCritAuras(WeaponAttackType attackType); + void UpdateAllWeaponDependentCritAuras(); + + void UpdateWeaponDependentAuras(WeaponAttackType attackType); void ApplyItemDependentAuras(Item* item, bool apply); + bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const override; + void _ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemAuras = true); void _RemoveAllItemMods(); void _ApplyAllItemMods(); @@ -2651,7 +2669,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> ActionButtonList m_actionButtons; - float m_auraBaseMod[BASEMOD_END][MOD_END]; + float m_auraBaseFlatMod[BASEMOD_END]; + float m_auraBasePctMod[BASEMOD_END]; int16 m_baseRatingValue[MAX_COMBAT_RATING]; uint32 m_baseSpellPower; uint32 m_baseManaRegen; diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index 96b400892de..201e3ef4db6 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -203,8 +203,13 @@ void SocialMgr::GetFriendInfo(Player* player, ObjectGuid const& friendGUID, Frie else if (target->isAFK()) friendInfo.Status = FRIEND_STATUS_AFK; else + { friendInfo.Status = FRIEND_STATUS_ONLINE; + if (target->GetSession()->GetRecruiterId() == player->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == player->GetSession()->GetRecruiterId()) + friendInfo.Status = FriendStatus(uint32(friendInfo.Status) | FRIEND_STATUS_RAF); + } + friendInfo.Area = target->GetZoneId(); friendInfo.Level = target->getLevel(); friendInfo.Class = target->getClass(); diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index e9f1fc359d9..2170ba4d7c7 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -200,7 +200,7 @@ void Player::UpdateSpellDamageAndHealingBonus() bool Player::UpdateAllStats() { - for (int8 i = STAT_STRENGTH; i < MAX_STATS; ++i) + for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) { float value = GetTotalStatValue(Stats(i)); SetStat(Stats(i), int32(value)); @@ -254,10 +254,10 @@ void Player::UpdateArmor() { UnitMods unitMod = UNIT_MOD_ARMOR; - float value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items) + float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items) float baseValue = value; - value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items - value += GetModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); //add dynamic flat mods AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT); @@ -267,7 +267,7 @@ void Player::UpdateArmor() value += CalculatePct(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount()); } - value *= GetModifierValue(unitMod, TOTAL_PCT); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetArmor(int32(baseValue), int32(value - baseValue)); @@ -294,10 +294,10 @@ void Player::UpdateMaxHealth() { UnitMods unitMod = UNIT_MOD_HEALTH; - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina(); - value *= GetModifierValue(unitMod, TOTAL_PCT); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina(); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxHealth((uint32)value); } @@ -315,10 +315,10 @@ void Player::UpdateMaxPower(Powers power) UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE); - value *= GetModifierValue(unitMod, TOTAL_PCT); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, (int32)std::lroundf(value)); } @@ -357,11 +357,11 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) val2 = CalculatePct(float(minSpellPower), *m_activePlayerData->OverrideAPBySpellPowerPercent); } - SetModifierValue(unitMod, BASE_VALUE, val2); + SetStatFlatModifier(unitMod, BASE_VALUE, val2); - float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); - float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; + float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT); + float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f; if (ranged) { @@ -405,7 +405,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) } } -void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) +void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const { UnitMods unitMod; @@ -425,10 +425,10 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo float attackPowerMod = std::max(GetAPMultiplier(attType, normalized), 0.25f); - float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 3.5f * attackPowerMod; - float basePct = GetModifierValue(unitMod, BASE_PCT); - float totalValue = GetModifierValue(unitMod, TOTAL_VALUE); - float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f; + float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 3.5f * attackPowerMod; + float basePct = GetPctModifierValue(unitMod, BASE_PCT); + float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f; float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE); float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE); @@ -492,16 +492,16 @@ void Player::UpdateCritPercentage(WeaponAttackType attType) { case OFF_ATTACK: SetUpdateFieldStatValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::OffhandCritPercentage), - applyCritLimit(GetTotalPercentageModValue(OFFHAND_CRIT_PERCENTAGE) + GetRatingBonusValue(CR_CRIT_MELEE))); + applyCritLimit(GetBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD) + GetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD) + GetRatingBonusValue(CR_CRIT_MELEE))); break; case RANGED_ATTACK: SetUpdateFieldStatValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::RangedCritPercentage), - applyCritLimit(GetTotalPercentageModValue(RANGED_CRIT_PERCENTAGE) + GetRatingBonusValue(CR_CRIT_RANGED))); + applyCritLimit(GetBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD) + GetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD) + GetRatingBonusValue(CR_CRIT_RANGED))); break; case BASE_ATTACK: default: SetUpdateFieldStatValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::CritPercentage), - applyCritLimit(GetTotalPercentageModValue(CRIT_PERCENTAGE) + GetRatingBonusValue(CR_CRIT_MELEE))); + applyCritLimit(GetBaseModValue(CRIT_PERCENTAGE, FLAT_MOD) + GetBaseModValue(CRIT_PERCENTAGE, PCT_MOD) + GetRatingBonusValue(CR_CRIT_MELEE))); break; } } @@ -510,9 +510,9 @@ void Player::UpdateAllCritPercentages() { float value = 5.0f; - SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value); - SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value); - SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value); + SetBaseModPctValue(CRIT_PERCENTAGE, value); + SetBaseModPctValue(OFFHAND_CRIT_PERCENTAGE, value); + SetBaseModPctValue(RANGED_CRIT_PERCENTAGE, value); UpdateCritPercentage(BASE_ATTACK); UpdateCritPercentage(OFF_ATTACK); @@ -835,7 +835,7 @@ bool Creature::UpdateAllStats() void Creature::UpdateArmor() { - float baseValue = GetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE); + float baseValue = GetFlatModifierValue(UNIT_MOD_ARMOR, BASE_VALUE); float value = GetTotalAuraModValue(UNIT_MOD_ARMOR); SetArmor(int32(baseValue), int32(value - baseValue)); } @@ -864,10 +864,10 @@ void Creature::UpdateMaxPower(Powers power) UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE); - value *= GetModifierValue(unitMod, TOTAL_PCT); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, (int32)std::lroundf(value)); } @@ -876,8 +876,8 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) { UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; - float baseAttackPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attackPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; + float baseAttackPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT); + float attackPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f; if (ranged) { @@ -900,7 +900,7 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) } } -void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) +void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const { float variance = 1.0f; UnitMods unitMod; @@ -939,10 +939,10 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float attackPower = GetTotalAttackPowerValue(attType); float attackSpeedMulti = GetAPMultiplier(attType, normalized); - float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 3.5f) * variance; - float basePct = GetModifierValue(unitMod, BASE_PCT) * attackSpeedMulti; - float totalValue = GetModifierValue(unitMod, TOTAL_VALUE); - float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f; + float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + (attackPower / 3.5f) * variance; + float basePct = GetPctModifierValue(unitMod, BASE_PCT) * attackSpeedMulti; + float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f; float dmgMultiplier = GetCreatureTemplate()->ModDamage; // = ModDamage * _GetDamageMod(rank); minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct; @@ -970,7 +970,7 @@ bool Guardian::UpdateStats(Stats stat) { // value = ((base_value * base_pct) + total_value) * total_pct float value = GetTotalStatValue(stat); - ApplyStatBuffMod(stat, m_statFromOwner[stat], false); + UpdateStatBuffMod(stat); float ownersBonus = 0.0f; Unit* owner = GetOwner(); @@ -1010,7 +1010,7 @@ bool Guardian::UpdateStats(Stats stat) SetStat(stat, int32(value)); m_statFromOwner[stat] = ownersBonus; - ApplyStatBuffMod(stat, m_statFromOwner[stat], true); + UpdateStatBuffMod(stat); switch (stat) { @@ -1044,7 +1044,7 @@ void Guardian::UpdateResistances(uint32 school) { if (school > SPELL_SCHOOL_NORMAL) { - float baseValue = GetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + school), BASE_VALUE); + float baseValue = GetFlatModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + school), BASE_VALUE); float bonusValue = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)) - baseValue; // hunter and warlock pets gain 40% of owner's resistance @@ -1074,11 +1074,11 @@ void Guardian::UpdateArmor() else if (IsPet()) bonus_armor = m_owner->GetArmor(); - value = GetModifierValue(unitMod, BASE_VALUE); + value = GetFlatModifierValue(unitMod, BASE_VALUE); baseValue = value; - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor; - value *= GetModifierValue(unitMod, TOTAL_PCT); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + bonus_armor; + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetArmor(int32(baseValue), int32(value - baseValue)); } @@ -1100,10 +1100,10 @@ void Guardian::UpdateMaxHealth() default: multiplicator = 10.0f; break; } - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator; - value *= GetModifierValue(unitMod, TOTAL_PCT); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator; + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxHealth((uint32)value); } @@ -1115,10 +1115,10 @@ void Guardian::UpdateMaxPower(Powers power) UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE); - value *= GetModifierValue(unitMod, TOTAL_PCT); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, int32(value)); } @@ -1178,11 +1178,11 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) } } - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP); + SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP); //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB - float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; + float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT); + float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f; SetAttackPower(int32(base_attPower)); SetAttackPowerMultiplier(attPowerMultiplier); @@ -1219,10 +1219,10 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType) float att_speed = float(GetBaseAttackTime(BASE_ATTACK))/1000.0f; - float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 3.5f * att_speed + bonusDamage; - float base_pct = GetModifierValue(unitMod, BASE_PCT); - float total_value = GetModifierValue(unitMod, TOTAL_VALUE); - float total_pct = GetModifierValue(unitMod, TOTAL_PCT); + float base_value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 3.5f * att_speed + bonusDamage; + float base_pct = GetPctModifierValue(unitMod, BASE_PCT); + float total_value = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float total_pct = GetPctModifierValue(unitMod, TOTAL_PCT); float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 62790919a9c..a0ddb919106 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -331,14 +331,14 @@ Unit::Unit(bool isWorldObject) : for (uint8 i = 0; i < UNIT_MOD_END; ++i) { - m_auraModifiersGroup[i][BASE_VALUE] = 0.0f; - m_auraModifiersGroup[i][BASE_PCT_EXCLUDE_CREATE] = 100.0f; - m_auraModifiersGroup[i][BASE_PCT] = 1.0f; - m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; - m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; + m_auraFlatModifiersGroup[i][BASE_VALUE] = 0.0f; + m_auraFlatModifiersGroup[i][BASE_PCT_EXCLUDE_CREATE] = 100.0f; + m_auraFlatModifiersGroup[i][TOTAL_VALUE] = 0.0f; + m_auraPctModifiersGroup[i][BASE_PCT] = 1.0f; + m_auraPctModifiersGroup[i][TOTAL_PCT] = 1.0f; } // implement 50% base damage from offhand - m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; + m_auraPctModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; for (uint8 i = 0; i < MAX_ATTACK; ++i) { @@ -627,7 +627,7 @@ void Unit::GetRandomContactPoint(const Unit* obj, float &x, float &y, float &z, { float combat_reach = GetCombatReach(); if (combat_reach < 0.1f) // sometimes bugged for players - combat_reach = DEFAULT_COMBAT_REACH; + combat_reach = DEFAULT_PLAYER_COMBAT_REACH; uint32 attacker_number = uint32(getAttackers().size()); if (attacker_number > 0) @@ -2258,7 +2258,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackTy return MELEE_HIT_NORMAL; } -uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) +uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const { float minDamage = 0.0f; float maxDamage = 0.0f; @@ -4892,16 +4892,69 @@ void Unit::InitStatBuffMods() } } -void Unit::ApplyStatBuffMod(Stats stat, float val, bool apply) +void Unit::UpdateStatBuffMod(Stats stat) { - ApplyPercentModFloatVar((val > 0 ? m_floatStatPosBuff[stat] : m_floatStatNegBuff[stat]), val, apply); - UpdateStatBuffModForClient(stat); -} + float modPos = 0.0f; + float modNeg = 0.0f; + float factor = 0.0f; -void Unit::ApplyStatPercentBuffMod(Stats stat, float val, bool apply) -{ - ApplyPercentModFloatVar(m_floatStatPosBuff[stat], val, apply); - ApplyPercentModFloatVar(m_floatStatNegBuff[stat], val, apply); + UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + stat); + + // includes value from items and enchantments + float modValue = GetFlatModifierValue(unitMod, BASE_VALUE); + if (modValue > 0.f) + modPos += modValue; + else + modNeg += modValue; + + if (IsGuardian()) + { + modValue = static_cast<Guardian*>(this)->GetBonusStatFromOwner(stat); + if (modValue > 0.f) + modPos += modValue; + else + modNeg += modValue; + } + + // SPELL_AURA_MOD_STAT_BONUS_PCT only affects BASE_VALUE + modPos = CalculatePct(modPos, std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f)); + modNeg = CalculatePct(modNeg, std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f)); + + modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool + { + if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0) + return true; + return false; + }); + + modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool + { + if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0) + return true; + return false; + }); + + factor = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat) + return true; + return false; + }); + + factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat) + return true; + return false; + }); + + modPos *= factor; + modNeg *= factor; + + m_floatStatPosBuff[stat] = modPos; + m_floatStatNegBuff[stat] = modNeg; + + UpdateStatBuffModForClient(stat); } void Unit::UpdateStatBuffModForClient(Stats stat) @@ -9371,31 +9424,99 @@ bool Unit::IsDisallowedMountForm(uint32 spellId, ShapeshiftForm form, uint32 dis ######## ######## #######################################*/ -bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply) +void Unit::HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply) { - if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END) { - TC_LOG_ERROR("entities.unit", "ERROR in HandleStatModifier(): non-existing UnitMods or wrong UnitModifierType!"); - return false; + TC_LOG_ERROR("entities.unit", "ERROR in HandleStatFlatModifier(): non-existing UnitMods or wrong UnitModifierType!"); + return; } + if (!amount) + return; + switch (modifierType) { case BASE_VALUE: case BASE_PCT_EXCLUDE_CREATE: case TOTAL_VALUE: - m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; + m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; break; + default: + break; + } + + UpdateUnitMod(unitMod); +} + +void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct) +{ + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END) + { + TC_LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!"); + return; + } + + if (!pct) + return; + + switch (modifierType) + { case BASE_PCT: case TOTAL_PCT: - ApplyPercentModFloatVar(m_auraModifiersGroup[unitMod][modifierType], amount, apply); + AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct); break; default: break; } + UpdateUnitMod(unitMod); +} + +void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val) +{ + if (m_auraFlatModifiersGroup[unitMod][modifierType] == val) + return; + + m_auraFlatModifiersGroup[unitMod][modifierType] = val; + UpdateUnitMod(unitMod); +} + +void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val) +{ + if (m_auraPctModifiersGroup[unitMod][modifierType] == val) + return; + + m_auraPctModifiersGroup[unitMod][modifierType] = val; + UpdateUnitMod(unitMod); +} + +float Unit::GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const +{ + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END) + { + TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!"); + return 0.0f; + } + + return m_auraFlatModifiersGroup[unitMod][modifierType]; +} + +float Unit::GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const +{ + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END) + { + TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!"); + return 0.0f; + } + + return m_auraPctModifiersGroup[unitMod][modifierType]; +} + +void Unit::UpdateUnitMod(UnitMods unitMod) +{ if (!CanModifyStats()) - return false; + return; switch (unitMod) { @@ -9445,37 +9566,92 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f ASSERT(false, "Not implemented UnitMod %u", unitMod); break; } +} + +void Unit::UpdateDamageDoneMods(WeaponAttackType attackType) +{ + UnitMods unitMod; + switch (attackType) + { + case BASE_ATTACK: + unitMod = UNIT_MOD_DAMAGE_MAINHAND; + break; + case OFF_ATTACK: + unitMod = UNIT_MOD_DAMAGE_OFFHAND; + break; + case RANGED_ATTACK: + unitMod = UNIT_MOD_DAMAGE_RANGED; + break; + default: + ABORT(); + break; + } - return true; + float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1)); + + SetStatFlatModifier(unitMod, TOTAL_VALUE, amount); +} + +void Unit::UpdateAllDamageDoneMods() +{ + for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i) + UpdateDamageDoneMods(WeaponAttackType(i)); } -float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const +void Unit::UpdateDamagePctDoneMods(WeaponAttackType attackType) { - if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) + float factor; + UnitMods unitMod; + switch (attackType) { - TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!"); - return 0.0f; + case BASE_ATTACK: + factor = 1.0f; + unitMod = UNIT_MOD_DAMAGE_MAINHAND; + break; + case OFF_ATTACK: + // off hand has 50% penalty + factor = 0.5f; + unitMod = UNIT_MOD_DAMAGE_OFFHAND; + break; + case RANGED_ATTACK: + factor = 1.0f; + unitMod = UNIT_MOD_DAMAGE_RANGED; + break; + default: + ABORT(); + break; } - if (modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f) - return 0.0f; + factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool + { + if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) + return false; + + return CheckAttackFitToAuraRequirement(attackType, aurEff); + }); + + if (attackType == OFF_ATTACK) + factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1)); - return m_auraModifiersGroup[unitMod][modifierType]; + SetStatPctModifier(unitMod, TOTAL_PCT, factor); +} + +void Unit::UpdateAllDamagePctDoneMods() +{ + for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i) + UpdateDamagePctDoneMods(WeaponAttackType(i)); } float Unit::GetTotalStatValue(Stats stat) const { UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat); - if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) - return 0.0f; - // value = ((base_value * base_pct) + total_value) * total_pct - float value = CalculatePct(m_auraModifiersGroup[unitMod][BASE_VALUE], std::max(m_auraModifiersGroup[unitMod][BASE_PCT_EXCLUDE_CREATE], -100.0f)); + float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f)); value += GetCreateStat(stat); - value *= m_auraModifiersGroup[unitMod][BASE_PCT]; - value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; - value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); return value; } @@ -9488,13 +9664,10 @@ float Unit::GetTotalAuraModValue(UnitMods unitMod) const return 0.0f; } - if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) - return 0.0f; - - float value = CalculatePct(m_auraModifiersGroup[unitMod][BASE_VALUE], std::max(m_auraModifiersGroup[unitMod][BASE_PCT_EXCLUDE_CREATE], -100.0f)); - value *= m_auraModifiersGroup[unitMod][BASE_PCT]; - value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; - value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; + float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f)); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); return value; } @@ -9542,7 +9715,7 @@ void Unit::UpdateResistances(uint32 school) { UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school); - SetResistance(SpellSchools(school), int32(m_auraModifiersGroup[unitMod][BASE_VALUE])); + SetResistance(SpellSchools(school), int32(GetFlatModifierValue(unitMod, BASE_VALUE))); SetBonusResistanceMod(SpellSchools(school), int32(GetTotalAuraModValue(unitMod) - GetResistance(SpellSchools(school)))); } else @@ -9802,7 +9975,6 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup) CombatStop(); DeleteThreatList(); getHostileRefManager().deleteReferences(); - GetMotionMaster()->Clear(false); // remove different non-standard movement generators. } void Unit::CleanupsBeforeDelete(bool finalCleanup) @@ -10609,7 +10781,10 @@ void Unit::RestoreDisplayId(bool ignorePositiveAurasPreventingMounting /*= false // transform aura was found if (handledAura) + { handledAura->HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true); + return; + } // we've found shapeshift else if (!shapeshiftAura.empty()) // we've found shapeshift { @@ -10620,11 +10795,11 @@ void Unit::RestoreDisplayId(bool ignorePositiveAurasPreventingMounting /*= false SetDisplayId(modelId); else SetDisplayId(GetNativeDisplayId()); + return; } } // no auras found - set modelid to default - else - SetDisplayId(GetNativeDisplayId()); + SetDisplayId(GetNativeDisplayId()); } void Unit::ClearAllReactives() @@ -10734,10 +10909,15 @@ void Unit::UpdateAttackTimeField(WeaponAttackType att) } } +void ApplyPercentModFloatVar(float& var, float val, bool apply) +{ + var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val)); +} + void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply) { float remainingTimePct = float(m_attackTimer[att]) / (m_baseAttackSpeed[att] * m_modAttackSpeedPct[att]); - if (val > 0) + if (val > 0.f) { ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply); @@ -10762,7 +10942,7 @@ void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply void Unit::ApplyCastTimePercentMod(float val, bool apply) { - if (val > 0) + if (val > 0.f) { ApplyPercentModUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ModCastingSpeed), val, !apply); ApplyPercentModUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ModSpellHaste), val, !apply); @@ -10920,7 +11100,7 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect return (CastingTime / 3500.0f) * DotFactor; } -float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) +float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const { if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized)) return GetBaseAttackTime(attType) / 1000.0f; @@ -11999,8 +12179,8 @@ bool Unit::IsInPartyWith(Unit const* unit) const if (this == unit) return true; - const Unit* u1 = GetCharmerOrOwnerOrSelf(); - const Unit* u2 = unit->GetCharmerOrOwnerOrSelf(); + Unit const* u1 = GetCharmerOrOwnerOrSelf(); + Unit const* u2 = unit->GetCharmerOrOwnerOrSelf(); if (u1 == u2) return true; @@ -12010,8 +12190,7 @@ bool Unit::IsInPartyWith(Unit const* unit) const (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_UNIT && u2->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)) return true; - // else u1->GetTypeId() == u2->GetTypeId() == TYPEID_UNIT - return u1->getFaction() == u2->getFaction(); + return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->getFaction() == u2->getFaction(); } bool Unit::IsInRaidWith(Unit const* unit) const @@ -12019,8 +12198,8 @@ bool Unit::IsInRaidWith(Unit const* unit) const if (this == unit) return true; - const Unit* u1 = GetCharmerOrOwnerOrSelf(); - const Unit* u2 = unit->GetCharmerOrOwnerOrSelf(); + Unit const* u1 = GetCharmerOrOwnerOrSelf(); + Unit const* u2 = unit->GetCharmerOrOwnerOrSelf(); if (u1 == u2) return true; @@ -12030,8 +12209,7 @@ bool Unit::IsInRaidWith(Unit const* unit) const (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_UNIT && u2->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)) return true; - // else u1->GetTypeId() == u2->GetTypeId() == TYPEID_UNIT - return u1->getFaction() == u2->getFaction(); + return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->getFaction() == u2->getFaction(); } void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap) @@ -12852,6 +13030,8 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) { bool result = false; uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry(); + TriggerCastFlags const flags = GetVehicleKit() ? TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE : TRIGGERED_NONE; + SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry); for (SpellClickInfoContainer::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr) { @@ -12894,7 +13074,7 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) } if (IsInMap(caster)) - caster->CastCustomSpell(itr->second.spellId, SpellValueMod(SPELLVALUE_BASE_POINT0+i), seatId + 1, target, GetVehicleKit() ? TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE : TRIGGERED_NONE, NULL, NULL, origCasterGUID); + caster->CastCustomSpell(itr->second.spellId, SpellValueMod(SPELLVALUE_BASE_POINT0 + i), seatId + 1, target, flags, NULL, NULL, origCasterGUID); else // This can happen during Player::_LoadAuras { int32 bp0[MAX_SPELL_EFFECTS]; @@ -12909,7 +13089,7 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) else { if (IsInMap(caster)) - caster->CastSpell(target, spellEntry, GetVehicleKit() ? TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE : TRIGGERED_NONE, NULL, NULL, origCasterGUID); + caster->CastSpell(target, spellEntry, flags, NULL, NULL, origCasterGUID); else Aura::TryRefreshStackOrCreate(spellEntry, ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), MAX_EFFECT_MASK, this, clicker, NULL, NULL, origCasterGUID); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 1f9de500ad1..7db8583f69f 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -257,14 +257,19 @@ typedef std::vector<DispelableAura> DispelChargesList; typedef std::unordered_multimap<uint32 /*type*/, uint32 /*spellId*/> SpellImmuneContainer; -enum UnitModifierType +enum UnitModifierFlatType { BASE_VALUE = 0, BASE_PCT_EXCLUDE_CREATE = 1, // percent modifier affecting all stat values from auras and gear but not player base for level - BASE_PCT = 2, - TOTAL_VALUE = 3, - TOTAL_PCT = 4, - MODIFIER_TYPE_END = 5 + TOTAL_VALUE = 2, + MODIFIER_TYPE_FLAT_END = 3 +}; + +enum UnitModifierPctType +{ + BASE_PCT = 0, + TOTAL_PCT = 1, + MODIFIER_TYPE_PCT_END = 2 }; enum WeaponDamageRange @@ -378,66 +383,60 @@ enum DeathState JUST_RESPAWNED = 4 }; -enum UnitState +enum UnitState : uint32 { - UNIT_STATE_DIED = 0x00000001, // player has fake death aura - UNIT_STATE_MELEE_ATTACKING = 0x00000002, // player is melee attacking someone - //UNIT_STATE_MELEE_ATTACK_BY = 0x00000004, // player is melee attack by someone - UNIT_STATE_STUNNED = 0x00000008, - UNIT_STATE_ROAMING = 0x00000010, - UNIT_STATE_CHASE = 0x00000020, - //UNIT_STATE_SEARCHING = 0x00000040, - UNIT_STATE_FLEEING = 0x00000080, - UNIT_STATE_IN_FLIGHT = 0x00000100, // player is in flight mode - UNIT_STATE_FOLLOW = 0x00000200, - UNIT_STATE_ROOT = 0x00000400, - UNIT_STATE_CONFUSED = 0x00000800, - UNIT_STATE_DISTRACTED = 0x00001000, - UNIT_STATE_ISOLATED = 0x00002000, // area auras do not affect other players - UNIT_STATE_ATTACK_PLAYER = 0x00004000, - UNIT_STATE_CASTING = 0x00008000, - UNIT_STATE_POSSESSED = 0x00010000, - UNIT_STATE_CHARGING = 0x00020000, - UNIT_STATE_JUMPING = 0x00040000, - UNIT_STATE_MOVE = 0x00100000, - UNIT_STATE_ROTATING = 0x00200000, - UNIT_STATE_EVADE = 0x00400000, - UNIT_STATE_ROAMING_MOVE = 0x00800000, - UNIT_STATE_CONFUSED_MOVE = 0x01000000, - UNIT_STATE_FLEEING_MOVE = 0x02000000, - UNIT_STATE_CHASE_MOVE = 0x04000000, - UNIT_STATE_FOLLOW_MOVE = 0x08000000, - UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator + UNIT_STATE_DIED = 0x00000001, // player has fake death aura + UNIT_STATE_MELEE_ATTACKING = 0x00000002, // player is melee attacking someone + //UNIT_STATE_MELEE_ATTACK_BY = 0x00000004, // player is melee attack by someone + UNIT_STATE_STUNNED = 0x00000008, + UNIT_STATE_ROAMING = 0x00000010, + UNIT_STATE_CHASE = 0x00000020, + //UNIT_STATE_SEARCHING = 0x00000040, + UNIT_STATE_FLEEING = 0x00000080, + UNIT_STATE_IN_FLIGHT = 0x00000100, // player is in flight mode + UNIT_STATE_FOLLOW = 0x00000200, + UNIT_STATE_ROOT = 0x00000400, + UNIT_STATE_CONFUSED = 0x00000800, + UNIT_STATE_DISTRACTED = 0x00001000, + UNIT_STATE_ISOLATED = 0x00002000, // area auras do not affect other players + UNIT_STATE_ATTACK_PLAYER = 0x00004000, + UNIT_STATE_CASTING = 0x00008000, + UNIT_STATE_POSSESSED = 0x00010000, + UNIT_STATE_CHARGING = 0x00020000, + UNIT_STATE_JUMPING = 0x00040000, + UNIT_STATE_MOVE = 0x00100000, + UNIT_STATE_ROTATING = 0x00200000, + UNIT_STATE_EVADE = 0x00400000, + UNIT_STATE_ROAMING_MOVE = 0x00800000, + UNIT_STATE_CONFUSED_MOVE = 0x01000000, + UNIT_STATE_FLEEING_MOVE = 0x02000000, + UNIT_STATE_CHASE_MOVE = 0x04000000, + UNIT_STATE_FOLLOW_MOVE = 0x08000000, + UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator + UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE | UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | UNIT_STATE_FOLLOW | UNIT_STATE_ROOT | UNIT_STATE_CONFUSED | UNIT_STATE_DISTRACTED | UNIT_STATE_ISOLATED | UNIT_STATE_ATTACK_PLAYER | UNIT_STATE_CASTING | UNIT_STATE_POSSESSED | UNIT_STATE_CHARGING | UNIT_STATE_JUMPING | UNIT_STATE_MOVE | UNIT_STATE_ROTATING | UNIT_STATE_EVADE | UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE | UNIT_STATE_IGNORE_PATHFINDING, - UNIT_STATE_UNATTACKABLE = UNIT_STATE_IN_FLIGHT, - // for real move using movegen check and stop (except unstoppable flight) - UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE, - UNIT_STATE_CONTROLLED = (UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING), - UNIT_STATE_LOST_CONTROL = (UNIT_STATE_CONTROLLED | UNIT_STATE_JUMPING | UNIT_STATE_CHARGING), - UNIT_STATE_SIGHTLESS = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_EVADE), - UNIT_STATE_CANNOT_AUTOATTACK = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_CASTING), - UNIT_STATE_CANNOT_TURN = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_ROTATING), - // stay by different reasons - UNIT_STATE_NOT_MOVE = UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DIED | UNIT_STATE_DISTRACTED, - UNIT_STATE_ALL_STATE = 0xffffffff //(UNIT_STATE_STOPPED | UNIT_STATE_MOVING | UNIT_STATE_IN_COMBAT | UNIT_STATE_IN_FLIGHT) + + UNIT_STATE_UNATTACKABLE = UNIT_STATE_IN_FLIGHT, + UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE, + UNIT_STATE_CONTROLLED = UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING, + UNIT_STATE_LOST_CONTROL = UNIT_STATE_CONTROLLED | UNIT_STATE_JUMPING | UNIT_STATE_CHARGING, + UNIT_STATE_SIGHTLESS = UNIT_STATE_LOST_CONTROL | UNIT_STATE_EVADE, + UNIT_STATE_CANNOT_AUTOATTACK = UNIT_STATE_LOST_CONTROL | UNIT_STATE_CASTING, + UNIT_STATE_CANNOT_TURN = UNIT_STATE_LOST_CONTROL | UNIT_STATE_ROTATING, + UNIT_STATE_NOT_MOVE = UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DIED | UNIT_STATE_DISTRACTED, + + UNIT_STATE_ALL_ERASABLE = UNIT_STATE_ALL_STATE_SUPPORTED & ~(UNIT_STATE_IGNORE_PATHFINDING), + UNIT_STATE_ALL_STATE = 0xffffffff }; TC_GAME_API extern float baseMoveSpeed[MAX_MOVE_TYPE]; TC_GAME_API extern float playerBaseMoveSpeed[MAX_MOVE_TYPE]; -enum WeaponAttackType : uint8 -{ - BASE_ATTACK = 0, - OFF_ATTACK = 1, - RANGED_ATTACK = 2, - MAX_ATTACK -}; - enum CombatRating { CR_AMPLIFY = 0, @@ -966,7 +965,7 @@ class TC_GAME_API Unit : public WorldObject bool haveOffhandWeapon() const; bool CanDualWield() const { return m_canDualWield; } virtual void SetCanDualWield(bool value) { m_canDualWield = value; } - float GetCombatReach() const { return m_unitData->CombatReach; } + float GetCombatReach() const override { return m_unitData->CombatReach; } void SetCombatReach(float combatReach) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::CombatReach), combatReach); } float GetBoundingRadius() const { return m_unitData->BoundingRadius; } void SetBoundingRadius(float boundingRadius) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::BoundingRadius), boundingRadius); } @@ -1608,8 +1607,7 @@ class TC_GAME_API Unit : public WorldObject int32 GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellInfo const* affectedSpell) const; void InitStatBuffMods(); - void ApplyStatBuffMod(Stats stat, float val, bool apply); - void ApplyStatPercentBuffMod(Stats stat, float val, bool apply); + void UpdateStatBuffMod(Stats stat); void UpdateStatBuffModForClient(Stats stat); void SetCreateStat(Stats stat, float val) { m_createStats[stat] = val; } void SetCreateHealth(uint32 val) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::BaseHealth), val); } @@ -1693,9 +1691,26 @@ class TC_GAME_API Unit : public WorldObject EventProcessor m_Events; // stat system - bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply); - void SetModifierValue(UnitMods unitMod, UnitModifierType modifierType, float value) { m_auraModifiersGroup[unitMod][modifierType] = value; } - float GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const; + void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply); + void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount); + + void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val); + void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val); + + float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const; + float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const; + + void UpdateUnitMod(UnitMods unitMod); + + // only players have item requirements + virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType /*attackType*/, AuraEffect const* /*aurEff*/) const { return true; } + + virtual void UpdateDamageDoneMods(WeaponAttackType attackType); + void UpdateAllDamageDoneMods(); + + void UpdateDamagePctDoneMods(WeaponAttackType attackType); + void UpdateAllDamagePctDoneMods(); + float GetTotalStatValue(Stats stat) const; float GetTotalAuraModValue(UnitMods unitMod) const; SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const; @@ -1723,9 +1738,9 @@ class TC_GAME_API Unit : public WorldObject float GetTotalAttackPowerValue(WeaponAttackType attType) const; float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const; void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } - virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) = 0; - uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct); - float GetAPMultiplier(WeaponAttackType attType, bool normalized); + virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const = 0; + uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const; + float GetAPMultiplier(WeaponAttackType attType, bool normalized) const; bool isInFrontInMap(Unit const* target, float distance, float arc = float(M_PI)) const; bool isInBackInMap(Unit const* target, float distance, float arc = float(M_PI)) const; @@ -2066,7 +2081,8 @@ class TC_GAME_API Unit : public WorldObject AuraStateAurasMap m_auraStateAuras; // Used for improve performance of aura state checks on aura apply/remove std::array<uint32, 2> m_interruptMask; - float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END]; + float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]; + float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]; float m_weaponDamage[MAX_ATTACK][2]; bool m_canModifyStats; diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index 158943800c8..9bf875ee810 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -21,7 +21,6 @@ #include "Define.h" #include <string> -#define DEFAULT_COMBAT_REACH 1.5f #define MIN_MELEE_REACH 2.0f #define NOMINAL_MELEE_RANGE 5.0f #define MELEE_RANGE (NOMINAL_MELEE_RANGE - MIN_MELEE_REACH * 2) //center to center for players diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index abc2a7b9189..4ab04447914 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1538,7 +1538,7 @@ void ObjectMgr::LoadCreatureModelInfo() } if (modelInfo.combat_reach < 0.1f) - modelInfo.combat_reach = DEFAULT_COMBAT_REACH; + modelInfo.combat_reach = DEFAULT_PLAYER_COMBAT_REACH; if (CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(creatureDisplay->ModelID)) { @@ -1986,8 +1986,6 @@ void ObjectMgr::LoadCreatures() data.phaseGroup = fields[25].GetUInt32(); data.terrainSwapMap = fields[26].GetInt32(); data.ScriptId = GetScriptId(fields[27].GetString()); - if (!data.ScriptId) - data.ScriptId = cInfo->ScriptID; MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); if (!mapEntry) @@ -2459,8 +2457,6 @@ void ObjectMgr::LoadGameobjects() } data.ScriptId = GetScriptId(fields[21].GetString()); - if (!data.ScriptId) - data.ScriptId = gInfo->ScriptId; if (std::abs(data.orientation) > 2 * float(M_PI)) { @@ -3874,12 +3870,12 @@ void ObjectMgr::LoadQuests() uint32 oldMSTime = getMSTime(); // For reload case - for (QuestMap::const_iterator itr=_questTemplates.begin(); itr != _questTemplates.end(); ++itr) + for (auto itr = _questTemplates.begin(); itr != _questTemplates.end(); ++itr) delete itr->second; _questTemplates.clear(); _questObjectives.clear(); - mExclusiveQuestGroups.clear(); + _exclusiveQuestGroups.clear(); QueryResult result = WorldDatabase.Query("SELECT " //0 1 2 3 4 5 6 7 8 9 10 11 12 @@ -3930,123 +3926,63 @@ void ObjectMgr::LoadQuests() _questTemplates[newQuest->GetQuestId()] = newQuest; } while (result->NextRow()); - // Load `quest_details` - // 0 1 2 3 4 5 6 7 8 - result = WorldDatabase.Query("SELECT ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4 FROM quest_details"); - - if (!result) - { - TC_LOG_ERROR("server.loading", ">> Loaded 0 quest details. DB table `quest_details` is empty."); - } - else + struct QuestLoaderHelper { - do - { - Field* fields = result->Fetch(); - uint32 questId = fields[0].GetUInt32(); - - auto itr = _questTemplates.find(questId); - if (itr != _questTemplates.end()) - itr->second->LoadQuestDetails(fields); - else - TC_LOG_ERROR("server.loading", "Table `quest_details` has data for quest %u but such quest does not exist", questId); - } while (result->NextRow()); - } + typedef void(Quest::* QuestLoaderFunction)(Field* fields); - // Load `quest_request_items` - // 0 1 2 3 4 5 - result = WorldDatabase.Query("SELECT ID, EmoteOnComplete, EmoteOnIncomplete, EmoteOnCompleteDelay, EmoteOnIncompleteDelay, CompletionText FROM quest_request_items"); + char const* QueryFields; + char const* TableName; + char const* QueryExtra; + char const* TableDesc; + QuestLoaderFunction LoaderFunction; + }; - if (!result) + static std::vector<QuestLoaderHelper> const QuestLoaderHelpers = { - TC_LOG_ERROR("server.loading", ">> Loaded 0 quest request items. DB table `quest_request_items` is empty."); - } - else - { - do - { - Field* fields = result->Fetch(); - uint32 questId = fields[0].GetUInt32(); + // 0 1 2 3 4 5 6 7 8 + { "ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4", "quest_details", "", "details", &Quest::LoadQuestDetails }, - auto itr = _questTemplates.find(questId); - if (itr != _questTemplates.end()) - itr->second->LoadQuestRequestItems(fields); - else - TC_LOG_ERROR("server.loading", "Table `quest_request_items` has data for quest %u but such quest does not exist", questId); - } while (result->NextRow()); - } + // 0 1 2 3 4 5 + { "ID, EmoteOnComplete, EmoteOnIncomplete, EmoteOnCompleteDelay, EmoteOnIncompleteDelay, CompletionText", "quest_request_items", "", "request items", &Quest::LoadQuestRequestItems }, - // Load `quest_offer_reward` - // 0 1 2 3 4 5 6 7 8 9 - result = WorldDatabase.Query("SELECT ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4, RewardText FROM quest_offer_reward"); + // 0 1 2 3 4 5 6 7 8 9 + { "ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4, RewardText", "quest_offer_reward", "", "reward emotes", &Quest::LoadQuestOfferReward }, - if (!result) - { - TC_LOG_ERROR("server.loading", ">> Loaded 0 quest reward emotes. DB table `quest_offer_reward` is empty."); - } - else - { - do - { - Field* fields = result->Fetch(); - uint32 questId = fields[0].GetUInt32(); + // 0 1 2 3 4 5 6 7 8 + { "ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, RewardMailTemplateID, RewardMailDelay," + // 9 10 11 12 13 14 15 16 + " RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, SpecialFlags," + // 17 + " ScriptName", "quest_template_addon", "", "template addons", &Quest::LoadQuestTemplateAddon }, - auto itr = _questTemplates.find(questId); - if (itr != _questTemplates.end()) - itr->second->LoadQuestOfferReward(fields); - else - TC_LOG_ERROR("server.loading", "Table `quest_offer_reward` has data for quest %u but such quest does not exist", questId); - } while (result->NextRow()); - } + // 0 1 + { "QuestId, RewardMailSenderEntry", "quest_mail_sender", "", "mail sender entries", &Quest::LoadQuestMailSender }, - // Load `quest_template_addon` - // 0 1 2 3 4 5 6 7 8 - result = WorldDatabase.Query("SELECT ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, RewardMailTemplateID, RewardMailDelay, " - //9 10 11 12 13 14 15 16 - "RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, RewardMailSenderEntry, " - //17 18 - "SpecialFlags, ScriptName FROM quest_template_addon LEFT JOIN quest_mail_sender ON Id=QuestId"); + // QuestID needs to be fields[0] + // 0 1 2 3 4 5 6 7 8 9 + { "QuestID, ID, Type, StorageIndex, ObjectID, Amount, Flags, Flags2, ProgressBarWeight, Description", "quest_objectives", "ORDER BY `Order` ASC, StorageIndex ASC", "quest objectives", &Quest::LoadQuestObjective } + }; - if (!result) - { - TC_LOG_ERROR("server.loading", ">> Loaded 0 quest template addons. DB table `quest_template_addon` is empty."); - } - else + for (QuestLoaderHelper const& loader : QuestLoaderHelpers) { - do - { - Field* fields = result->Fetch(); - uint32 questId = fields[0].GetUInt32(); - - auto itr = _questTemplates.find(questId); - if (itr != _questTemplates.end()) - itr->second->LoadQuestTemplateAddon(fields); - else - TC_LOG_ERROR("server.loading", "Table `quest_template_addon` has data for quest %u but such quest does not exist", questId); - } while (result->NextRow()); - } - - // Load `quest_objectives` - // 0 1 2 3 4 5 6 7 8 9 - result = WorldDatabase.Query("SELECT ID, QuestID, Type, StorageIndex, ObjectID, Amount, Flags, Flags2, ProgressBarWeight, Description FROM quest_objectives ORDER BY `Order` ASC, StorageIndex ASC"); + QueryResult result = WorldDatabase.PQuery("SELECT %s FROM %s", loader.QueryFields, loader.TableName, loader.QueryExtra); - if (!result) - { - TC_LOG_ERROR("server.loading", ">> Loaded 0 quest objectives. DB table `quest_objectives` is empty."); - } - else - { - do + if (!result) + TC_LOG_ERROR("server.loading", ">> Loaded 0 quest %s. DB table `%s` is empty.", loader.TableDesc, loader.TableName); + else { - Field* fields = result->Fetch(); - uint32 questId = fields[1].GetUInt32(); + do + { + Field* fields = result->Fetch(); + uint32 questId = fields[0].GetUInt32(); - auto itr = _questTemplates.find(questId); - if (itr != _questTemplates.end()) - itr->second->LoadQuestObjective(fields); - else - TC_LOG_ERROR("server.loading", "Table `quest_objectives` has objective for quest %u but such quest does not exist", questId); - } while (result->NextRow()); + auto itr = _questTemplates.find(questId); + if (itr != _questTemplates.end()) + (itr->second->*loader.LoaderFunction)(fields); + else + TC_LOG_ERROR("server.loading", "Table `%s` has data for quest %u but such quest does not exist", loader.TableName, questId); + } while (result->NextRow()); + } } // Load `quest_visual_effect` join table with quest_objectives because visual effects are based on objective ID (core stores objectives by their index in quest) @@ -4103,223 +4039,223 @@ void ObjectMgr::LoadQuests() if (qinfo->GetQuestType() >= MAX_QUEST_TYPES) TC_LOG_ERROR("sql.sql", "Quest %u has `Method` = %u, expected values are 0, 1 or 2.", qinfo->GetQuestId(), qinfo->GetQuestType()); - if (qinfo->SpecialFlags & ~QUEST_SPECIAL_FLAGS_DB_ALLOWED) + if (qinfo->_specialFlags & ~QUEST_SPECIAL_FLAGS_DB_ALLOWED) { TC_LOG_ERROR("sql.sql", "Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u", - qinfo->GetQuestId(), qinfo->SpecialFlags, QUEST_SPECIAL_FLAGS_DB_ALLOWED); - qinfo->SpecialFlags &= QUEST_SPECIAL_FLAGS_DB_ALLOWED; + qinfo->GetQuestId(), qinfo->_specialFlags, QUEST_SPECIAL_FLAGS_DB_ALLOWED); + qinfo->_specialFlags &= QUEST_SPECIAL_FLAGS_DB_ALLOWED; } - if (qinfo->Flags & QUEST_FLAGS_DAILY && qinfo->Flags & QUEST_FLAGS_WEEKLY) + if (qinfo->_flags & QUEST_FLAGS_DAILY && qinfo->_flags & QUEST_FLAGS_WEEKLY) { TC_LOG_ERROR("sql.sql", "Weekly Quest %u is marked as daily quest in `Flags`, removed daily flag.", qinfo->GetQuestId()); - qinfo->Flags &= ~QUEST_FLAGS_DAILY; + qinfo->_flags &= ~QUEST_FLAGS_DAILY; } - if (qinfo->Flags & QUEST_FLAGS_DAILY) + if (qinfo->_flags & QUEST_FLAGS_DAILY) { - if (!(qinfo->SpecialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE)) + if (!(qinfo->_specialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE)) { TC_LOG_DEBUG("sql.sql", "Daily Quest %u not marked as repeatable in `SpecialFlags`, added.", qinfo->GetQuestId()); - qinfo->SpecialFlags |= QUEST_SPECIAL_FLAGS_REPEATABLE; + qinfo->_specialFlags |= QUEST_SPECIAL_FLAGS_REPEATABLE; } } - if (qinfo->Flags & QUEST_FLAGS_WEEKLY) + if (qinfo->_flags & QUEST_FLAGS_WEEKLY) { - if (!(qinfo->SpecialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE)) + if (!(qinfo->_specialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE)) { TC_LOG_DEBUG("sql.sql", "Weekly Quest %u not marked as repeatable in `SpecialFlags`, added.", qinfo->GetQuestId()); - qinfo->SpecialFlags |= QUEST_SPECIAL_FLAGS_REPEATABLE; + qinfo->_specialFlags |= QUEST_SPECIAL_FLAGS_REPEATABLE; } } - if (qinfo->SpecialFlags & QUEST_SPECIAL_FLAGS_MONTHLY) + if (qinfo->_specialFlags & QUEST_SPECIAL_FLAGS_MONTHLY) { - if (!(qinfo->SpecialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE)) + if (!(qinfo->_specialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE)) { TC_LOG_DEBUG("sql.sql", "Monthly quest %u not marked as repeatable in `SpecialFlags`, added.", qinfo->GetQuestId()); - qinfo->SpecialFlags |= QUEST_SPECIAL_FLAGS_REPEATABLE; + qinfo->_specialFlags |= QUEST_SPECIAL_FLAGS_REPEATABLE; } } - if (qinfo->Flags & QUEST_FLAGS_TRACKING) + if (qinfo->_flags & QUEST_FLAGS_TRACKING) { // at auto-reward can be rewarded only RewardChoiceItemId[0] - for (int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j ) + for (uint32 j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j ) { if (uint32 id = qinfo->RewardChoiceItemId[j]) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardChoiceItemId%d` = %u but item from `RewardChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_TRACKING.", - qinfo->GetQuestId(), j+1, id, j+1); + qinfo->GetQuestId(), j + 1, id, j + 1); // no changes, quest ignore this data } } } - if (qinfo->MinLevel == -1 || qinfo->MinLevel > DEFAULT_MAX_LEVEL) + if (qinfo->_minLevel == -1 || qinfo->_minLevel > DEFAULT_MAX_LEVEL) { - TC_LOG_ERROR("sql.sql", "Quest %u should be disabled because `MinLevel` = %i", qinfo->GetQuestId(), int32(qinfo->MinLevel)); + TC_LOG_ERROR("sql.sql", "Quest %u should be disabled because `MinLevel` = %i", qinfo->GetQuestId(), int32(qinfo->_minLevel)); // no changes needed, sending -1 in SMSG_QUEST_QUERY_RESPONSE is valid } // client quest log visual (area case) - if (qinfo->QuestSortID > 0) + if (qinfo->_questSortID > 0) { - if (!sAreaTableStore.LookupEntry(qinfo->QuestSortID)) + if (!sAreaTableStore.LookupEntry(qinfo->_questSortID)) { TC_LOG_ERROR("sql.sql", "Quest %u has `QuestSortID` = %u (zone case) but zone with this id does not exist.", - qinfo->GetQuestId(), qinfo->QuestSortID); + qinfo->GetQuestId(), qinfo->_questSortID); // no changes, quest not dependent from this value but can have problems at client } } // client quest log visual (sort case) - if (qinfo->QuestSortID < 0) + if (qinfo->_questSortID < 0) { - QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->QuestSortID)); + QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->_questSortID)); if (!qSort) { TC_LOG_ERROR("sql.sql", "Quest %u has `QuestSortID` = %i (sort case) but quest sort with this id does not exist.", - qinfo->GetQuestId(), qinfo->QuestSortID); + qinfo->GetQuestId(), qinfo->_questSortID); // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check) } //check for proper RequiredSkillId value (skill case) - if (uint32 skill_id = SkillByQuestSort(-int32(qinfo->QuestSortID))) + if (uint32 skill_id = SkillByQuestSort(-int32(qinfo->_questSortID))) { - if (qinfo->RequiredSkillId != skill_id) + if (qinfo->_requiredSkillId != skill_id) { TC_LOG_ERROR("sql.sql", "Quest %u has `QuestSortID` = %i but `RequiredSkillId` does not have a corresponding value (%d).", - qinfo->GetQuestId(), qinfo->QuestSortID, skill_id); + qinfo->GetQuestId(), qinfo->_questSortID, skill_id); //override, and force proper value here? } } } // AllowableClasses, can be 0/CLASSMASK_ALL_PLAYABLE to allow any class - if (qinfo->AllowableClasses) + if (qinfo->_allowableClasses) { - if (!(qinfo->AllowableClasses & CLASSMASK_ALL_PLAYABLE)) + if (!(qinfo->_allowableClasses & CLASSMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable classes in `AllowableClasses` (%u), value set to 0 (all classes).", qinfo->GetQuestId(), qinfo->AllowableClasses); - qinfo->AllowableClasses = 0; + TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable classes in `AllowableClasses` (%u), value set to 0 (all classes).", qinfo->GetQuestId(), qinfo->_allowableClasses); + qinfo->_allowableClasses = 0; } } // AllowableRaces, can be -1/RACEMASK_ALL_PLAYABLE to allow any race - if (qinfo->AllowableRaces.RawValue != uint64(-1)) + if (qinfo->_allowableRaces.RawValue != uint64(-1)) { - if (qinfo->AllowableRaces && !(qinfo->AllowableRaces.RawValue & RACEMASK_ALL_PLAYABLE)) + if (qinfo->_allowableRaces && !(qinfo->_allowableRaces.RawValue & RACEMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable races in `AllowableRaces` (" UI64FMTD "), value set to -1 (all races).", qinfo->GetQuestId(), qinfo->AllowableRaces.RawValue); - qinfo->AllowableRaces.RawValue = uint64(-1); + TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable races in `AllowableRaces` (" UI64FMTD "), value set to -1 (all races).", qinfo->GetQuestId(), qinfo->_allowableRaces.RawValue); + qinfo->_allowableRaces.RawValue = uint64(-1); } } // RequiredSkillId, can be 0 - if (qinfo->RequiredSkillId) + if (qinfo->_requiredSkillId) { - if (!sSkillLineStore.LookupEntry(qinfo->RequiredSkillId)) + if (!sSkillLineStore.LookupEntry(qinfo->_requiredSkillId)) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSkillId` = %u but this skill does not exist", - qinfo->GetQuestId(), qinfo->RequiredSkillId); + qinfo->GetQuestId(), qinfo->_requiredSkillId); } } - if (qinfo->RequiredSkillPoints) + if (qinfo->_requiredSkillPoints) { - if (qinfo->RequiredSkillPoints > sWorld->GetConfigMaxSkillValue()) + if (qinfo->_requiredSkillPoints > sWorld->GetConfigMaxSkillValue()) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSkillPoints` = %u but max possible skill is %u, quest can't be done.", - qinfo->GetQuestId(), qinfo->RequiredSkillPoints, sWorld->GetConfigMaxSkillValue()); + qinfo->GetQuestId(), qinfo->_requiredSkillPoints, sWorld->GetConfigMaxSkillValue()); // no changes, quest can't be done for this requirement } } // else Skill quests can have 0 skill level, this is ok - if (qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction)) + if (qinfo->_requiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->_requiredMinRepFaction)) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(), qinfo->RequiredMinRepFaction, qinfo->RequiredMinRepFaction); + qinfo->GetQuestId(), qinfo->_requiredMinRepFaction, qinfo->_requiredMinRepFaction); // no changes, quest can't be done for this requirement } - if (qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction)) + if (qinfo->_requiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->_requiredMaxRepFaction)) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(), qinfo->RequiredMaxRepFaction, qinfo->RequiredMaxRepFaction); + qinfo->GetQuestId(), qinfo->_requiredMaxRepFaction, qinfo->_requiredMaxRepFaction); // no changes, quest can't be done for this requirement } - if (qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > ReputationMgr::Reputation_Cap) + if (qinfo->_requiredMinRepValue && qinfo->_requiredMinRepValue > ReputationMgr::Reputation_Cap) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.", - qinfo->GetQuestId(), qinfo->RequiredMinRepValue, ReputationMgr::Reputation_Cap); + qinfo->GetQuestId(), qinfo->_requiredMinRepValue, ReputationMgr::Reputation_Cap); // no changes, quest can't be done for this requirement } - if (qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue) + if (qinfo->_requiredMinRepValue && qinfo->_requiredMaxRepValue && qinfo->_requiredMaxRepValue <= qinfo->_requiredMinRepValue) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.", - qinfo->GetQuestId(), qinfo->RequiredMaxRepValue, qinfo->RequiredMinRepValue); + qinfo->GetQuestId(), qinfo->_requiredMaxRepValue, qinfo->_requiredMinRepValue); // no changes, quest can't be done for this requirement } - if (!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue != 0) + if (!qinfo->_requiredMinRepFaction && qinfo->_requiredMinRepValue != 0) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect", - qinfo->GetQuestId(), qinfo->RequiredMinRepValue); + qinfo->GetQuestId(), qinfo->_requiredMinRepValue); // warning } - if (!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue != 0) + if (!qinfo->_requiredMaxRepFaction && qinfo->_requiredMaxRepValue != 0) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect", - qinfo->GetQuestId(), qinfo->RequiredMaxRepValue); + qinfo->GetQuestId(), qinfo->_requiredMaxRepValue); // warning } - if (qinfo->RewardTitleId && !sCharTitlesStore.LookupEntry(qinfo->RewardTitleId)) + if (qinfo->_rewardTitleId && !sCharTitlesStore.LookupEntry(qinfo->_rewardTitleId)) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.", - qinfo->GetQuestId(), qinfo->RewardTitleId, qinfo->RewardTitleId); - qinfo->RewardTitleId = 0; + qinfo->GetQuestId(), qinfo->_rewardTitleId, qinfo->_rewardTitleId); + qinfo->_rewardTitleId = 0; // quest can't reward this title } - if (qinfo->SourceItemId) + if (qinfo->_sourceItemId) { - if (!sObjectMgr->GetItemTemplate(qinfo->SourceItemId)) + if (!sObjectMgr->GetItemTemplate(qinfo->_sourceItemId)) { TC_LOG_ERROR("sql.sql", "Quest %u has `SourceItemId` = %u but item with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(), qinfo->SourceItemId, qinfo->SourceItemId); - qinfo->SourceItemId = 0; // quest can't be done for this requirement + qinfo->GetQuestId(), qinfo->_sourceItemId, qinfo->_sourceItemId); + qinfo->_sourceItemId = 0; // quest can't be done for this requirement } - else if (qinfo->SourceItemIdCount == 0) + else if (qinfo->_sourceItemIdCount == 0) { TC_LOG_ERROR("sql.sql", "Quest %u has `StartItem` = %u but `ProvidedItemCount` = 0, set to 1 but need fix in DB.", - qinfo->GetQuestId(), qinfo->SourceItemId); - qinfo->SourceItemIdCount = 1; // update to 1 for allow quest work for backward compatibility with DB + qinfo->GetQuestId(), qinfo->_sourceItemId); + qinfo->_sourceItemIdCount = 1; // update to 1 for allow quest work for backward compatibility with DB } } - else if (qinfo->SourceItemIdCount>0) + else if (qinfo->_sourceItemIdCount > 0) { TC_LOG_ERROR("sql.sql", "Quest %u has `SourceItemId` = 0 but `SourceItemIdCount` = %u, useless value.", - qinfo->GetQuestId(), qinfo->SourceItemIdCount); - qinfo->SourceItemIdCount=0; // no quest work changes in fact + qinfo->GetQuestId(), qinfo->_sourceItemIdCount); + qinfo->_sourceItemIdCount = 0; // no quest work changes in fact } - if (qinfo->SourceSpellID) + if (qinfo->_sourceSpellID) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->SourceSpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->_sourceSpellID); if (!spellInfo) { TC_LOG_ERROR("sql.sql", "Quest %u has `SourceSpellid` = %u but spell %u doesn't exist, quest can't be done.", - qinfo->GetQuestId(), qinfo->SourceSpellID, qinfo->SourceSpellID); - qinfo->SourceSpellID = 0; // quest can't be done for this requirement + qinfo->GetQuestId(), qinfo->_sourceSpellID, qinfo->_sourceSpellID); + qinfo->_sourceSpellID = 0; // quest can't be done for this requirement } else if (!SpellMgr::IsSpellValid(spellInfo)) { TC_LOG_ERROR("sql.sql", "Quest %u has `SourceSpellid` = %u but spell %u is broken, quest can't be done.", - qinfo->GetQuestId(), qinfo->SourceSpellID, qinfo->SourceSpellID); - qinfo->SourceSpellID = 0; // quest can't be done for this requirement + qinfo->GetQuestId(), qinfo->_sourceSpellID, qinfo->_sourceSpellID); + qinfo->_sourceSpellID = 0; // quest can't be done for this requirement } } @@ -4501,7 +4437,7 @@ void ObjectMgr::LoadQuests() { if (qinfo->RewardFactionId[j]) { - if (abs(qinfo->RewardFactionValue[j]) > 9) + if (std::abs(qinfo->RewardFactionValue[j]) > 9) { TC_LOG_ERROR("sql.sql", "Quest %u has RewardFactionValueId%d = %i. That is outside the range of valid values (-9 to 9).", qinfo->GetQuestId(), j+1, qinfo->RewardFactionValue[j]); } @@ -4542,59 +4478,59 @@ void ObjectMgr::LoadQuests() } } - if (qinfo->RewardSpell > 0) + if (qinfo->_rewardSpell > 0) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->_rewardSpell); if (!spellInfo) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.", - qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell); - qinfo->RewardSpell = 0; // no spell will be cast on player + qinfo->GetQuestId(), qinfo->_rewardSpell, qinfo->_rewardSpell); + qinfo->_rewardSpell = 0; // no spell will be cast on player } else if (!SpellMgr::IsSpellValid(spellInfo)) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpellCast` = %u but spell %u is broken, quest will not have a spell reward.", - qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell); - qinfo->RewardSpell = 0; // no spell will be cast on player + qinfo->GetQuestId(), qinfo->_rewardSpell, qinfo->_rewardSpell); + qinfo->_rewardSpell = 0; // no spell will be cast on player } } - if (qinfo->RewardMailTemplateId) + if (qinfo->_rewardMailTemplateId) { - if (!sMailTemplateStore.LookupEntry(qinfo->RewardMailTemplateId)) + if (!sMailTemplateStore.LookupEntry(qinfo->_rewardMailTemplateId)) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardMailTemplateId` = %u but mail template %u does not exist, quest will not have a mail reward.", - qinfo->GetQuestId(), qinfo->RewardMailTemplateId, qinfo->RewardMailTemplateId); - qinfo->RewardMailTemplateId = 0; // no mail will send to player - qinfo->RewardMailDelay = 0; // no mail will send to player - qinfo->RewardMailSenderEntry = 0; + qinfo->GetQuestId(), qinfo->_rewardMailTemplateId, qinfo->_rewardMailTemplateId); + qinfo->_rewardMailTemplateId = 0; // no mail will send to player + qinfo->_rewardMailDelay = 0; // no mail will send to player + qinfo->_rewardMailSenderEntry = 0; } - else if (usedMailTemplates.find(qinfo->RewardMailTemplateId) != usedMailTemplates.end()) + else if (usedMailTemplates.find(qinfo->_rewardMailTemplateId) != usedMailTemplates.end()) { - std::map<uint32, uint32>::const_iterator used_mt_itr = usedMailTemplates.find(qinfo->RewardMailTemplateId); + auto used_mt_itr = usedMailTemplates.find(qinfo->_rewardMailTemplateId); TC_LOG_ERROR("sql.sql", "Quest %u has `RewardMailTemplateId` = %u but mail template %u already used for quest %u, quest will not have a mail reward.", - qinfo->GetQuestId(), qinfo->RewardMailTemplateId, qinfo->RewardMailTemplateId, used_mt_itr->second); - qinfo->RewardMailTemplateId = 0; // no mail will send to player - qinfo->RewardMailDelay = 0; // no mail will send to player - qinfo->RewardMailSenderEntry = 0; + qinfo->GetQuestId(), qinfo->_rewardMailTemplateId, qinfo->_rewardMailTemplateId, used_mt_itr->second); + qinfo->_rewardMailTemplateId = 0; // no mail will send to player + qinfo->_rewardMailDelay = 0; // no mail will send to player + qinfo->_rewardMailSenderEntry = 0; } else - usedMailTemplates[qinfo->RewardMailTemplateId] = qinfo->GetQuestId(); + usedMailTemplates.emplace(qinfo->_rewardMailTemplateId, qinfo->GetQuestId()); } - if (qinfo->NextQuestInChain) + if (qinfo->_nextQuestInChain) { - QuestMap::iterator qNextItr = _questTemplates.find(qinfo->NextQuestInChain); + auto qNextItr = _questTemplates.find(qinfo->_nextQuestInChain); if (qNextItr == _questTemplates.end()) { TC_LOG_ERROR("sql.sql", "Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.", - qinfo->GetQuestId(), qinfo->NextQuestInChain, qinfo->NextQuestInChain); - qinfo->NextQuestInChain = 0; + qinfo->GetQuestId(), qinfo->_nextQuestInChain, qinfo->_nextQuestInChain); + qinfo->_nextQuestInChain = 0; } else - qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId()); + qNextItr->second->PrevChainQuests.push_back(qinfo->GetQuestId()); } for (uint8 j = 0; j < QUEST_REWARD_CURRENCY_COUNT; ++j) @@ -4623,79 +4559,74 @@ void ObjectMgr::LoadQuests() } } - if (qinfo->SoundAccept) + if (qinfo->_soundAccept) { - if (!sSoundKitStore.LookupEntry(qinfo->SoundAccept)) + if (!sSoundKitStore.LookupEntry(qinfo->_soundAccept)) { TC_LOG_ERROR("sql.sql", "Quest %u has `SoundAccept` = %u but sound %u does not exist, set to 0.", - qinfo->GetQuestId(), qinfo->SoundAccept, qinfo->SoundAccept); - qinfo->SoundAccept = 0; // no sound will be played + qinfo->GetQuestId(), qinfo->_soundAccept, qinfo->_soundAccept); + qinfo->_soundAccept = 0; // no sound will be played } } - if (qinfo->SoundTurnIn) + if (qinfo->_soundTurnIn) { - if (!sSoundKitStore.LookupEntry(qinfo->SoundTurnIn)) + if (!sSoundKitStore.LookupEntry(qinfo->_soundTurnIn)) { TC_LOG_ERROR("sql.sql", "Quest %u has `SoundTurnIn` = %u but sound %u does not exist, set to 0.", - qinfo->GetQuestId(), qinfo->SoundTurnIn, qinfo->SoundTurnIn); - qinfo->SoundTurnIn = 0; // no sound will be played + qinfo->GetQuestId(), qinfo->_soundTurnIn, qinfo->_soundTurnIn); + qinfo->_soundTurnIn = 0; // no sound will be played } } - if (qinfo->RewardSkillId) + if (qinfo->_rewardSkillId) { - if (!sSkillLineStore.LookupEntry(qinfo->RewardSkillId)) + if (!sSkillLineStore.LookupEntry(qinfo->_rewardSkillId)) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillId` = %u but this skill does not exist", - qinfo->GetQuestId(), qinfo->RewardSkillId); + qinfo->GetQuestId(), qinfo->_rewardSkillId); } - if (!qinfo->RewardSkillPoints) + if (!qinfo->_rewardSkillPoints) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillId` = %u but `RewardSkillPoints` is 0", - qinfo->GetQuestId(), qinfo->RewardSkillId); + qinfo->GetQuestId(), qinfo->_rewardSkillId); } } - if (qinfo->RewardSkillPoints) + if (qinfo->_rewardSkillPoints) { - if (qinfo->RewardSkillPoints > sWorld->GetConfigMaxSkillValue()) + if (qinfo->_rewardSkillPoints > sWorld->GetConfigMaxSkillValue()) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillPoints` = %u but max possible skill is %u, quest can't be done.", - qinfo->GetQuestId(), qinfo->RewardSkillPoints, sWorld->GetConfigMaxSkillValue()); + qinfo->GetQuestId(), qinfo->_rewardSkillPoints, sWorld->GetConfigMaxSkillValue()); // no changes, quest can't be done for this requirement } - if (!qinfo->RewardSkillId) + if (!qinfo->_rewardSkillId) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillPoints` = %u but `RewardSkillId` is 0", - qinfo->GetQuestId(), qinfo->RewardSkillPoints); + qinfo->GetQuestId(), qinfo->_rewardSkillPoints); } } // fill additional data stores - if (qinfo->PrevQuestID) + if (qinfo->_prevQuestID) { if (_questTemplates.find(abs(qinfo->GetPrevQuestId())) == _questTemplates.end()) TC_LOG_ERROR("sql.sql", "Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId()); - else - qinfo->prevQuests.push_back(qinfo->PrevQuestID); } - if (qinfo->NextQuestID) + if (qinfo->_nextQuestID) { - QuestMap::iterator qNextItr = _questTemplates.find(abs(qinfo->GetNextQuestId())); + auto qNextItr = _questTemplates.find(qinfo->GetNextQuestId()); if (qNextItr == _questTemplates.end()) - TC_LOG_ERROR("sql.sql", "Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId()); + TC_LOG_ERROR("sql.sql", "Quest %d has NextQuestId %u, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId()); else - { - int32 signedQuestId = qinfo->NextQuestID < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId()); - qNextItr->second->prevQuests.push_back(signedQuestId); - } + qNextItr->second->DependentPreviousQuests.push_back(qinfo->GetQuestId()); } - if (qinfo->ExclusiveGroup) - mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId())); - if (qinfo->LimitTime) + if (qinfo->_exclusiveGroup) + _exclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->_exclusiveGroup, qinfo->GetQuestId())); + if (qinfo->_limitTime) qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED); } @@ -9223,6 +9154,8 @@ void ObjectMgr::LoadScriptNames() return; } + _scriptNamesStore.reserve(result->GetRowCount() + 1); + do { _scriptNamesStore.push_back((*result)[0].GetString()); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 7a2105cf346..6506eb3d80d 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -540,6 +540,9 @@ typedef std::multimap<uint32, uint32> QuestRelationsReverse; // quest -> unit/go typedef std::pair<QuestRelations::const_iterator, QuestRelations::const_iterator> QuestRelationBounds; typedef std::pair<QuestRelationsReverse::const_iterator, QuestRelationsReverse::const_iterator> QuestRelationReverseBounds; +typedef std::multimap<int32, uint32> ExclusiveQuestGroups; // exclusiveGroupId -> quest +typedef std::pair<ExclusiveQuestGroups::const_iterator, ExclusiveQuestGroups::const_iterator> ExclusiveQuestGroupsBounds; + struct PlayerCreateInfoItem { PlayerCreateInfoItem(uint32 id, uint32 amount) : item_id(id), item_amount(amount) { } @@ -1206,6 +1209,11 @@ class TC_GAME_API ObjectMgr return _creatureQuestInvolvedRelationsReverse.equal_range(questId); } + ExclusiveQuestGroupsBounds GetExclusiveQuestGroupBounds(int32 exclusiveGroupId) const + { + return _exclusiveQuestGroups.equal_range(exclusiveGroupId); + } + bool LoadTrinityStrings(); void LoadEventScripts(); @@ -1344,11 +1352,6 @@ class TC_GAME_API ObjectMgr uint64 GenerateCreatureSpawnId(); uint64 GenerateGameObjectSpawnId(); - typedef std::multimap<int32, uint32> ExclusiveQuestGroups; - typedef std::pair<ExclusiveQuestGroups::const_iterator, ExclusiveQuestGroups::const_iterator> ExclusiveQuestGroupsBounds; - - ExclusiveQuestGroups mExclusiveQuestGroups; - MailLevelReward const* GetMailLevelReward(uint8 level, uint8 race) { MailLevelRewardContainer::const_iterator map_itr = _mailLevelRewardStore.find(level); @@ -1677,6 +1680,8 @@ class TC_GAME_API ObjectMgr QuestRelations _creatureQuestInvolvedRelations; QuestRelationsReverse _creatureQuestInvolvedRelationsReverse; + ExclusiveQuestGroups _exclusiveQuestGroups; + //character reserved names typedef std::set<std::wstring> ReservedNamesContainer; ReservedNamesContainer _reservedNamesStore; diff --git a/src/server/game/Grids/Cells/CellImpl.h b/src/server/game/Grids/Cells/CellImpl.h index a06a84eaebc..3b343851bb2 100644 --- a/src/server/game/Grids/Cells/CellImpl.h +++ b/src/server/game/Grids/Cells/CellImpl.h @@ -64,7 +64,7 @@ inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, { //we should increase search radius by object's radius, otherwise //we could have problems with huge creatures, which won't attack nearest players etc - Visit(standing_cell, visitor, map, obj.GetPositionX(), obj.GetPositionY(), radius + obj.GetObjectSize()); + Visit(standing_cell, visitor, map, obj.GetPositionX(), obj.GetPositionY(), radius + obj.GetCombatReach()); } template<class T, class CONTAINER> diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index e786935b538..23f3cf2ddc0 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -944,14 +944,27 @@ namespace Trinity class AnyFriendlyUnitInObjectRangeCheck { public: - AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool playerOnly = false) : i_obj(obj), i_funit(funit), i_range(range), i_playerOnly(playerOnly) { } + AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool playerOnly = false, bool incOwnRadius = true, bool incTargetRadius = true) + : i_obj(obj), i_funit(funit), i_range(range), i_playerOnly(playerOnly), i_incOwnRadius(incOwnRadius), i_incTargetRadius(incTargetRadius) { } bool operator()(Unit* u) const { - if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u) && (!i_playerOnly || u->GetTypeId() == TYPEID_PLAYER)) - return true; - else + if (!u->IsAlive()) + return false; + + float searchRadius = i_range; + if (i_incOwnRadius) + searchRadius += i_obj->GetCombatReach(); + if (i_incTargetRadius) + searchRadius += u->GetCombatReach(); + + if (!u->IsInMap(i_obj) || !u->IsInPhase(i_obj) || !u->IsWithinDoubleVerticalCylinder(i_obj, searchRadius, searchRadius)) return false; + + if (!i_funit->IsFriendlyTo(u)) + return false; + + return !i_playerOnly || u->GetTypeId() == TYPEID_PLAYER; } private: @@ -959,12 +972,15 @@ namespace Trinity Unit const* i_funit; float i_range; bool i_playerOnly; + bool i_incOwnRadius; + bool i_incTargetRadius; }; class AnyGroupedUnitInObjectRangeCheck { public: - AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid, bool playerOnly = false) : _source(obj), _refUnit(funit), _range(range), _raid(raid), _playerOnly(playerOnly) { } + AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid, bool playerOnly = false, bool incOwnRadius = true, bool incTargetRadius = true) + : _source(obj), _refUnit(funit), _range(range), _raid(raid), _playerOnly(playerOnly), i_incOwnRadius(incOwnRadius), i_incTargetRadius(incTargetRadius) { } bool operator()(Unit* u) const { @@ -979,7 +995,19 @@ namespace Trinity else if (!_refUnit->IsInPartyWith(u)) return false; - return !_refUnit->IsHostileTo(u) && u->IsAlive() && _source->IsWithinDistInMap(u, _range); + if (_refUnit->IsHostileTo(u)) + return false; + + if (!u->IsAlive()) + return false; + + float searchRadius = _range; + if (i_incOwnRadius) + searchRadius += _source->GetCombatReach(); + if (i_incTargetRadius) + searchRadius += u->GetCombatReach(); + + return u->IsInMap(_source) && u->IsInPhase(_source) && u->IsWithinDoubleVerticalCylinder(_source, searchRadius, searchRadius); } private: @@ -988,6 +1016,8 @@ namespace Trinity float _range; bool _raid; bool _playerOnly; + bool i_incOwnRadius; + bool i_incTargetRadius; }; class AnyUnitInObjectRangeCheck @@ -1039,8 +1069,8 @@ namespace Trinity class AnyAoETargetUnitInObjectRangeCheck { public: - AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, SpellInfo const* spellInfo = nullptr) - : i_obj(obj), i_funit(funit), _spellInfo(spellInfo), i_range(range) + AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, SpellInfo const* spellInfo = nullptr, bool incOwnRadius = true, bool incTargetRadius = true) + : i_obj(obj), i_funit(funit), _spellInfo(spellInfo), i_range(range), i_incOwnRadius(incOwnRadius), i_incTargetRadius(incTargetRadius) { if (!_spellInfo) if (DynamicObject const* dynObj = i_obj->ToDynObject()) @@ -1056,7 +1086,16 @@ namespace Trinity if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS) && u->GetTypeId() != TYPEID_PLAYER) return false; - return i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range); + if (!i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr)) + return false; + + float searchRadius = i_range; + if (i_incOwnRadius) + searchRadius += i_obj->GetCombatReach(); + if (i_incTargetRadius) + searchRadius += u->GetCombatReach(); + + return u->IsInMap(i_obj) && u->IsInPhase(i_obj) && u->IsWithinDoubleVerticalCylinder(i_obj, searchRadius, searchRadius); } private: @@ -1064,6 +1103,8 @@ namespace Trinity Unit const* i_funit; SpellInfo const* _spellInfo; float i_range; + bool i_incOwnRadius; + bool i_incTargetRadius; }; // do attack at call of help to friendly crearture diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index bf2f9dc3cd5..1ae93079145 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -228,6 +228,7 @@ void WorldSession::HandleOpenWrappedItemCallback(uint16 pos, ObjectGuid itemGuid item->SetGiftCreator(ObjectGuid::Empty); item->SetEntry(entry); item->SetItemFlags(ItemFieldFlags(flags)); + item->SetMaxDurability(item->GetTemplate()->MaxDurability); item->SetState(ITEM_CHANGED, GetPlayer()); GetPlayer()->SaveInventoryAndGoldToDB(trans); diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 90582235948..4f124dd9567 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -145,7 +145,7 @@ void InstanceScript::LoadBossBoundaries(const BossBoundaryData& data) { for (BossBoundaryEntry const& entry : data) if (entry.BossId < bosses.size()) - bosses[entry.BossId].boundary.insert(entry.Boundary); + bosses[entry.BossId].boundary.push_back(entry.Boundary); } void InstanceScript::LoadMinionData(const MinionData* data) diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 0fc37d470ec..a87779f7f22 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -119,7 +119,7 @@ struct ObjectData uint32 type; }; -typedef std::set<AreaBoundary const*> CreatureBoundary; +typedef std::vector<AreaBoundary const*> CreatureBoundary; struct BossInfo { diff --git a/src/server/game/Maps/AreaBoundary.cpp b/src/server/game/Maps/AreaBoundary.cpp index f7ae5b4c9b6..407b5c27e53 100644 --- a/src/server/game/Maps/AreaBoundary.cpp +++ b/src/server/game/Maps/AreaBoundary.cpp @@ -21,7 +21,7 @@ // ---== RECTANGLE ==--- RectangleBoundary::RectangleBoundary(float southX, float northX, float eastY, float westY, bool isInverted) : - AreaBoundary(BoundaryType::BOUNDARY_RECTANGLE, isInverted), _minX(southX), _maxX(northX), _minY(eastY), _maxY(westY) { } + AreaBoundary(isInverted), _minX(southX), _maxX(northX), _minY(eastY), _maxY(westY) { } bool RectangleBoundary::IsWithinBoundaryArea(Position const* pos) const { if (!pos) @@ -38,13 +38,9 @@ bool RectangleBoundary::IsWithinBoundaryArea(Position const* pos) const // ---== CIRCLE ==--- CircleBoundary::CircleBoundary(Position const& center, double radius, bool isInverted) : - CircleBoundary(DoublePosition(center), radius, isInverted) { } -CircleBoundary::CircleBoundary(DoublePosition const& center, double radius, bool isInverted) : - AreaBoundary(BoundaryType::BOUNDARY_CIRCLE, isInverted), _center(center), _radiusSq(radius*radius) { } + AreaBoundary(isInverted), _center(center), _radiusSq(radius*radius) { } CircleBoundary::CircleBoundary(Position const& center, Position const& pointOnCircle, bool isInverted) : - CircleBoundary(DoublePosition(center), DoublePosition(pointOnCircle), isInverted) { } -CircleBoundary::CircleBoundary(DoublePosition const& center, DoublePosition const& pointOnCircle, bool isInverted) : - AreaBoundary(BoundaryType::BOUNDARY_CIRCLE, isInverted), _center(center), _radiusSq(center.GetDoubleExactDist2dSq(pointOnCircle)) { } + AreaBoundary(isInverted), _center(center), _radiusSq(_center.GetDoubleExactDist2dSq(pointOnCircle)) { } bool CircleBoundary::IsWithinBoundaryArea(Position const* pos) const { if (!pos) @@ -58,9 +54,7 @@ bool CircleBoundary::IsWithinBoundaryArea(Position const* pos) const // ---== ELLIPSE ==--- EllipseBoundary::EllipseBoundary(Position const& center, double radiusX, double radiusY, bool isInverted) : - EllipseBoundary(DoublePosition(center), radiusX, radiusY, isInverted) { } -EllipseBoundary::EllipseBoundary(DoublePosition const& center, double radiusX, double radiusY, bool isInverted) : - AreaBoundary(BoundaryType::BOUNDARY_ELLIPSE, isInverted), _center(center), _radiusYSq(radiusY*radiusY), _scaleXSq(_radiusYSq / (radiusX*radiusX)) { } + AreaBoundary(isInverted), _center(center), _radiusYSq(radiusY*radiusY), _scaleXSq(_radiusYSq / (radiusX*radiusX)) { } bool EllipseBoundary::IsWithinBoundaryArea(Position const* pos) const { if (!pos) @@ -73,9 +67,7 @@ bool EllipseBoundary::IsWithinBoundaryArea(Position const* pos) const // ---== TRIANGLE ==--- TriangleBoundary::TriangleBoundary(Position const& pointA, Position const& pointB, Position const& pointC, bool isInverted) : - TriangleBoundary(DoublePosition(pointA), DoublePosition(pointB), DoublePosition(pointC), isInverted) { } -TriangleBoundary::TriangleBoundary(DoublePosition const& pointA, DoublePosition const& pointB, DoublePosition const& pointC, bool isInverted) : - AreaBoundary(BoundaryType::BOUNDARY_TRIANGLE, isInverted), _a(pointA), _b(pointB), _c(pointC), _abx(_b.GetDoublePositionX()-_a.GetDoublePositionX()), _bcx(_c.GetDoublePositionX()-_b.GetDoublePositionX()), _cax(_a.GetDoublePositionX() - _c.GetDoublePositionX()), _aby(_b.GetDoublePositionY()-_a.GetDoublePositionY()), _bcy(_c.GetDoublePositionY()-_b.GetDoublePositionY()), _cay(_a.GetDoublePositionY() - _c.GetDoublePositionY()) { } + AreaBoundary(isInverted), _a(pointA), _b(pointB), _c(pointC), _abx(_b.GetDoublePositionX()-_a.GetDoublePositionX()), _bcx(_c.GetDoublePositionX()-_b.GetDoublePositionX()), _cax(_a.GetDoublePositionX() - _c.GetDoublePositionX()), _aby(_b.GetDoublePositionY()-_a.GetDoublePositionY()), _bcy(_c.GetDoublePositionY()-_b.GetDoublePositionY()), _cay(_a.GetDoublePositionY() - _c.GetDoublePositionY()) { } bool TriangleBoundary::IsWithinBoundaryArea(Position const* pos) const { if (!pos) @@ -93,9 +85,7 @@ bool TriangleBoundary::IsWithinBoundaryArea(Position const* pos) const // ---== PARALLELOGRAM ==--- ParallelogramBoundary::ParallelogramBoundary(Position const& cornerA, Position const& cornerB, Position const& cornerD, bool isInverted) : - ParallelogramBoundary(DoublePosition(cornerA), DoublePosition(cornerB), DoublePosition(cornerD), isInverted) { } -ParallelogramBoundary::ParallelogramBoundary(DoublePosition const& cornerA, DoublePosition const& cornerB, DoublePosition const& cornerD, bool isInverted) : - AreaBoundary(BoundaryType::BOUNDARY_PARALLELOGRAM, isInverted), _a(cornerA), _b(cornerB), _d(cornerD), _c(DoublePosition(_d.GetDoublePositionX() + (_b.GetDoublePositionX() - _a.GetDoublePositionX()), _d.GetDoublePositionY() + (_b.GetDoublePositionY() - _a.GetDoublePositionY()))), _abx(_b.GetDoublePositionX() - _a.GetDoublePositionX()), _dax(_a.GetDoublePositionX() - _d.GetDoublePositionX()), _aby(_b.GetDoublePositionY() - _a.GetDoublePositionY()), _day(_a.GetDoublePositionY() - _d.GetDoublePositionY()) { } + AreaBoundary(isInverted), _a(cornerA), _b(cornerB), _d(cornerD), _c(DoublePosition(_d.GetDoublePositionX() + (_b.GetDoublePositionX() - _a.GetDoublePositionX()), _d.GetDoublePositionY() + (_b.GetDoublePositionY() - _a.GetDoublePositionY()))), _abx(_b.GetDoublePositionX() - _a.GetDoublePositionX()), _dax(_a.GetDoublePositionX() - _d.GetDoublePositionX()), _aby(_b.GetDoublePositionY() - _a.GetDoublePositionY()), _day(_a.GetDoublePositionY() - _d.GetDoublePositionY()) { } bool ParallelogramBoundary::IsWithinBoundaryArea(Position const* pos) const { if (!pos) @@ -114,7 +104,7 @@ bool ParallelogramBoundary::IsWithinBoundaryArea(Position const* pos) const // ---== Z RANGE ==--- ZRangeBoundary::ZRangeBoundary(float minZ, float maxZ, bool isInverted) : - AreaBoundary(BoundaryType::BOUNDARY_Z_RANGE, isInverted), _minZ(minZ), _maxZ(maxZ) { } + AreaBoundary(isInverted), _minZ(minZ), _maxZ(maxZ) { } bool ZRangeBoundary::IsWithinBoundaryArea(Position const* pos) const { if (!pos) diff --git a/src/server/game/Maps/AreaBoundary.h b/src/server/game/Maps/AreaBoundary.h index 069701775eb..6aa7e4185cc 100644 --- a/src/server/game/Maps/AreaBoundary.h +++ b/src/server/game/Maps/AreaBoundary.h @@ -23,48 +23,52 @@ class TC_GAME_API AreaBoundary { public: - enum BoundaryType - { - BOUNDARY_RECTANGLE, // Rectangle aligned with the coordinate axis - BOUNDARY_CIRCLE, - BOUNDARY_ELLIPSE, - BOUNDARY_TRIANGLE, - BOUNDARY_PARALLELOGRAM, - BOUNDARY_Z_RANGE, - }; - virtual ~AreaBoundary() { } - BoundaryType GetBoundaryType() const { return m_boundaryType; } - bool IsWithinBoundary(Position const* pos) const { return (IsWithinBoundaryArea(pos) != m_isInvertedBoundary); } + bool IsWithinBoundary(Position const* pos) const { return (IsWithinBoundaryArea(pos) != _isInvertedBoundary); } bool IsWithinBoundary(Position const& pos) const { return IsWithinBoundary(&pos); } + virtual ~AreaBoundary() { } + + protected: + explicit AreaBoundary(bool isInverted) : _isInvertedBoundary(isInverted) { } + struct DoublePosition : Position { - double d_positionX, d_positionY, d_positionZ; DoublePosition(double x = 0.0, double y = 0.0, double z = 0.0, float o = 0.0f) - : Position(float(x), float(y), float(z), o), d_positionX(x), d_positionY(y), d_positionZ(z) { } + : Position(float(x), float(y), float(z), o), DoublePosX(x), DoublePosY(y), DoublePosZ(z) { } + DoublePosition(float x, float y = 0.0f, float z = 0.0f, float o = 0.0f) - : Position(x, y, z, o), d_positionX(x), d_positionY(y), d_positionZ(z) { } + : Position(x, y, z, o), DoublePosX(x), DoublePosY(y), DoublePosZ(z) { } + DoublePosition(Position const & pos) - : DoublePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()) { } + : Position(pos), DoublePosX(pos.m_positionX), DoublePosY(pos.m_positionY), DoublePosZ(pos.m_positionZ) { } - double GetDoublePositionX() const { return d_positionX; } - double GetDoublePositionY() const { return d_positionY; } - double GetDoublePositionZ() const { return d_positionZ; } + double GetDoublePositionX() const { return DoublePosX; } + double GetDoublePositionY() const { return DoublePosY; } + double GetDoublePositionZ() const { return DoublePosZ; } double GetDoubleExactDist2dSq(DoublePosition const& pos) const { - double offX = GetDoublePositionX() - pos.GetDoublePositionX(); - double offY = GetDoublePositionY() - pos.GetDoublePositionY(); - return (offX*offX) + (offY*offY); + double const offX = GetDoublePositionX() - pos.GetDoublePositionX(); + double const offY = GetDoublePositionY() - pos.GetDoublePositionY(); + return (offX * offX) + (offY * offY); + } + + Position* sync() + { + m_positionX = float(DoublePosX); + m_positionY = float(DoublePosY); + m_positionZ = float(DoublePosZ); + return this; } - Position* sync() { m_positionX = (float)d_positionX; m_positionY = (float)d_positionY; m_positionZ = (float)d_positionZ; return this; } + double DoublePosX; + double DoublePosY; + double DoublePosZ; }; - protected: - AreaBoundary(BoundaryType bType, bool isInverted) : m_boundaryType(bType), m_isInvertedBoundary(isInverted) { } virtual bool IsWithinBoundaryArea(Position const* pos) const = 0; - const BoundaryType m_boundaryType; - bool m_isInvertedBoundary; + + private: + bool _isInvertedBoundary; }; class TC_GAME_API RectangleBoundary : public AreaBoundary @@ -77,51 +81,47 @@ class TC_GAME_API RectangleBoundary : public AreaBoundary bool IsWithinBoundaryArea(Position const* pos) const override; private: - const float _minX, _maxX, _minY, _maxY; + float const _minX, _maxX, _minY, _maxY; }; class TC_GAME_API CircleBoundary : public AreaBoundary { public: CircleBoundary(Position const& center, double radius, bool isInverted = false); - CircleBoundary(DoublePosition const& center, double radius, bool isInverted = false); CircleBoundary(Position const& center, Position const& pointOnCircle, bool isInverted = false); - CircleBoundary(DoublePosition const& center, DoublePosition const& pointOnCircle, bool isInverted = false); protected: bool IsWithinBoundaryArea(Position const* pos) const override; private: - const DoublePosition _center; - const double _radiusSq; + DoublePosition const _center; + double const _radiusSq; }; class TC_GAME_API EllipseBoundary : public AreaBoundary { public: EllipseBoundary(Position const& center, double radiusX, double radiusY, bool isInverted = false); - EllipseBoundary(DoublePosition const& center, double radiusX, double radiusY, bool isInverted = false); protected: bool IsWithinBoundaryArea(Position const* pos) const override; private: - const DoublePosition _center; - const double _radiusYSq, _scaleXSq; + DoublePosition const _center; + double const _radiusYSq, _scaleXSq; }; class TC_GAME_API TriangleBoundary : public AreaBoundary { public: TriangleBoundary(Position const& pointA, Position const& pointB, Position const& pointC, bool isInverted = false); - TriangleBoundary(DoublePosition const& pointA, DoublePosition const& pointB, DoublePosition const& pointC, bool isInverted = false); protected: bool IsWithinBoundaryArea(Position const* pos) const override; private: - const DoublePosition _a, _b, _c; - const double _abx, _bcx, _cax, _aby, _bcy, _cay; + DoublePosition const _a, _b, _c; + double const _abx, _bcx, _cax, _aby, _bcy, _cay; }; class TC_GAME_API ParallelogramBoundary : public AreaBoundary @@ -129,14 +129,13 @@ class TC_GAME_API ParallelogramBoundary : public AreaBoundary public: // Note: AB must be orthogonal to AD ParallelogramBoundary(Position const& cornerA, Position const& cornerB, Position const& cornerD, bool isInverted = false); - ParallelogramBoundary(DoublePosition const& cornerA, DoublePosition const& cornerB, DoublePosition const& cornerD, bool isInverted = false); protected: bool IsWithinBoundaryArea(Position const* pos) const override; private: - const DoublePosition _a, _b, _d, _c; - const double _abx, _dax, _aby, _day; + DoublePosition const _a, _b, _d, _c; + double const _abx, _dax, _aby, _day; }; class TC_GAME_API ZRangeBoundary : public AreaBoundary @@ -148,7 +147,7 @@ class TC_GAME_API ZRangeBoundary : public AreaBoundary bool IsWithinBoundaryArea(Position const* pos) const override; private: - const float _minZ, _maxZ; + float const _minZ, _maxZ; }; #endif //TRINITY_AREA_BOUNDARY_H diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 283b0b42fc7..4355789458a 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -547,7 +547,7 @@ enum TrinityStrings LANG_MOVEGENS_IDLE = 527, LANG_MOVEGENS_RANDOM = 528, LANG_MOVEGENS_WAYPOINT = 529, - LANG_MOVEGENS_ANIMAL_RANDOM = 530, + // = 530, not used LANG_MOVEGENS_CONFUSED = 531, LANG_MOVEGENS_CHASE_PLAYER = 532, LANG_MOVEGENS_CHASE_CREATURE = 533, diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 1edeb4218fe..1002ab50684 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -5392,6 +5392,14 @@ enum DiminishingLevels DIMINISHING_LEVEL_TAUNT_IMMUNE = 4 }; +enum WeaponAttackType : uint8 +{ + BASE_ATTACK = 0, + OFF_ATTACK = 1, + RANGED_ATTACK = 2, + MAX_ATTACK +}; + enum TokenResult { TOKEN_RESULT_SUCCESS = 0, diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index f4190f2520c..3e775d238a4 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -43,10 +43,16 @@ MotionMaster::~MotionMaster() // clear ALL movement generators (including default) while (!empty()) { - MovementGenerator *curr = top(); + MovementGenerator* movement = top(); pop(); - if (curr && !IsStatic(curr)) - delete curr; // Skip finalizing on delete, it might launch new movement + if (movement && !IsStatic(movement)) + delete movement; + } + + while (!_expireList.empty()) + { + delete _expireList.back(); + _expireList.pop_back(); } } @@ -89,13 +95,15 @@ void MotionMaster::UpdateMotion(uint32 diff) ASSERT(!empty()); _cleanFlag |= MMCF_UPDATE; - bool isMoveGenUpdateSuccess = top()->Update(_owner, diff); - _cleanFlag &= ~MMCF_UPDATE; - - if (!isMoveGenUpdateSuccess) + if (!top()->Update(_owner, diff)) + { + _cleanFlag &= ~MMCF_UPDATE; MovementExpired(); + } + else + _cleanFlag &= ~MMCF_UPDATE; - if (_expireList) + if (!_expireList.empty()) ClearExpireList(); } @@ -115,14 +123,10 @@ void MotionMaster::Clear(bool reset /*= true*/) void MotionMaster::ClearExpireList() { - for (size_t i = 0; i < _expireList->size(); ++i) - { - MovementGenerator* mg = (*_expireList)[i]; - DirectDelete(mg); - } + for (auto itr : _expireList) + DirectDelete(itr); - delete _expireList; - _expireList = nullptr; + _expireList.clear(); if (empty()) Initialize(); @@ -159,7 +163,7 @@ MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const MovementGeneratorType MotionMaster::GetMotionSlotType(int slot) const { if (!_slot[slot]) - return NULL_MOTION_TYPE; + return MAX_MOTION_TYPE; else return _slot[slot]->GetMovementGeneratorType(); } @@ -429,7 +433,7 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa float dist = 2 * moveTimeHalf * speedXY; float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ); - _owner->GetNearPoint(_owner, x, y, z, _owner->GetObjectSize(), dist, _owner->GetAngle(srcX, srcY) + float(M_PI)); + _owner->GetNearPoint(_owner, x, y, z, _owner->GetCombatReach(), dist, _owner->GetAngle(srcX, srcY) + float(M_PI)); Movement::MoveSplineInit init(_owner); init.MoveTo(x, y, z); @@ -453,7 +457,7 @@ void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ) float moveTimeHalf = speedZ / Movement::gravity; float dist = 2 * moveTimeHalf * speedXY; - _owner->GetClosePoint(x, y, z, _owner->GetObjectSize(), dist, angle); + _owner->GetClosePoint(x, y, z, _owner->GetCombatReach(), dist, angle); MoveJump(x, y, z, 0.0f, speedXY, speedZ); } @@ -835,7 +839,6 @@ void MotionMaster::DelayedDelete(MovementGenerator* curr) TC_LOG_FATAL("misc", "Unit (Entry %u) is trying to delete its updating Movement Generator (Type %u)!", _owner->GetEntry(), curr->GetMovementGeneratorType()); if (IsStatic(curr)) return; - if (!_expireList) - _expireList = new ExpireList(); - _expireList->push_back(curr); + + _expireList.push_back(curr); } diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index f8dbe43306d..c496a0ec4ec 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -52,7 +52,6 @@ enum MovementGeneratorType : uint8 RANDOM_MOTION_TYPE = 1, // RandomMovementGenerator.h WAYPOINT_MOTION_TYPE = 2, // WaypointMovementGenerator.h MAX_DB_MOTION_TYPE = 3, // Below motion types can't be set in DB. - ANIMAL_RANDOM_MOTION_TYPE = MAX_DB_MOTION_TYPE, // AnimalRandomMovementGenerator.h CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h @@ -60,14 +59,13 @@ enum MovementGeneratorType : uint8 POINT_MOTION_TYPE = 8, // PointMovementGenerator.h FLEEING_MOTION_TYPE = 9, // FleeingMovementGenerator.h DISTRACT_MOTION_TYPE = 10, // IdleMovementGenerator.h - ASSISTANCE_MOTION_TYPE = 11, // PointMovementGenerator.h (first part of flee for assistance) - ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h (second part of flee for assistance) - TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h (alt.second part of flee for assistance) + ASSISTANCE_MOTION_TYPE = 11, // PointMovementGenerator.h + ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h + TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h FOLLOW_MOTION_TYPE = 14, ROTATE_MOTION_TYPE = 15, EFFECT_MOTION_TYPE = 16, - NULL_MOTION_TYPE = 17, - SPLINE_CHAIN_MOTION_TYPE = 18, // SplineChainMovementGenerator.h + SPLINE_CHAIN_MOTION_TYPE = 17, // SplineChainMovementGenerator.h MAX_MOTION_TYPE // limit }; @@ -100,11 +98,8 @@ struct JumpArrivalCastArgs class TC_GAME_API MotionMaster { - private: - typedef std::vector<MovementGenerator*> ExpireList; - public: - explicit MotionMaster(Unit* unit) : _expireList(nullptr), _top(-1), _owner(unit), _cleanFlag(MMCF_NONE) + explicit MotionMaster(Unit* unit) : _owner(unit), _top(-1), _cleanFlag(MMCF_NONE) { for (uint8 i = 0; i < MAX_MOTION_SLOT; ++i) { @@ -182,6 +177,8 @@ class TC_GAME_API MotionMaster void MoveRotate(uint32 time, RotateDirection direction); private: + typedef std::vector<MovementGenerator*> MovementList; + void pop(); bool NeedInitTop() const; @@ -197,11 +194,11 @@ class TC_GAME_API MotionMaster void DelayedDelete(MovementGenerator* curr); void ClearExpireList(); - ExpireList* _expireList; MovementGenerator* _slot[MAX_MOTION_SLOT]; - int _top; - Unit* _owner; bool _initialize[MAX_MOTION_SLOT]; + MovementList _expireList; + Unit* _owner; + int _top; uint8 _cleanFlag; }; diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index 51b9641661e..e8fa2ba6c53 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -63,7 +63,7 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner) skipToHome = false; arrived = false; - owner->ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~(UNIT_STATE_EVADE | UNIT_STATE_IGNORE_PATHFINDING))); + owner->ClearUnitState(UNIT_STATE_ALL_ERASABLE & ~UNIT_STATE_EVADE); } bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, const uint32 /*time_diff*/) diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 6f3b34c0e4f..3cf0711dc41 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -149,8 +149,6 @@ void EffectMovementGenerator::Finalize(Unit* unit) { if (Unit* victim = unit->GetVictim()) unit->GetMotionMaster()->MoveChase(victim); - else - unit->GetMotionMaster()->Initialize(); } if (unit->ToCreature()->AI()) diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index 0a1206a8d48..54cc97ab418 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -65,7 +65,7 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T* owner, bool up float size; // Pets need special handling. - // We need to subtract GetObjectSize() because it gets added back further down the chain + // We need to subtract GetCombatReach() because it gets added back further down the chain // and that makes pets too far away. Subtracting it allows pets to properly // be (GetCombatReach() + i_offset) away. // Only applies when i_target is pet's owner otherwise pets and mobs end up @@ -73,12 +73,12 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T* owner, bool up if (owner->IsPet() && i_target->GetTypeId() == TYPEID_PLAYER) { dist = 1.0f; //i_target->GetCombatReach(); - size = 1.0f; //i_target->GetCombatReach() - i_target->GetObjectSize(); + size = 1.0f; //i_target->GetCombatReach() - i_target->GetCombatReach(); } else { dist = i_offset + 1.0f; - size = owner->GetObjectSize(); + size = owner->GetCombatReach(); } if (i_target->IsWithinDistInMap(owner, dist)) diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 92a039344a5..28685dc58ec 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -27,43 +27,36 @@ Quest::Quest(Field* questRecord) { - EmoteOnIncomplete = 0; - EmoteOnComplete = 0; - _rewItemsCount = 0; - _rewChoiceItemsCount = 0; - _eventIdForQuest = 0; - _rewCurrencyCount = 0; - - ID = questRecord[0].GetUInt32(); - Type = questRecord[1].GetUInt8(); - Level = questRecord[2].GetInt32(); - ScalingFactionGroup = questRecord[3].GetInt32(); - MaxScalingLevel = questRecord[4].GetInt32(); - PackageID = questRecord[5].GetUInt32(); - MinLevel = questRecord[6].GetInt32(); - QuestSortID = questRecord[7].GetInt16(); - QuestInfoID = questRecord[8].GetUInt16(); - SuggestedPlayers = questRecord[9].GetUInt8(); - NextQuestInChain = questRecord[10].GetUInt32(); - RewardXPDifficulty = questRecord[11].GetUInt32(); - RewardXPMultiplier = questRecord[12].GetFloat(); - RewardMoney = questRecord[13].GetUInt32(); - RewardMoneyDifficulty = questRecord[14].GetUInt32(); - RewardMoneyMultiplier = questRecord[15].GetFloat(); - RewardBonusMoney = questRecord[16].GetUInt32(); + _id = questRecord[0].GetUInt32(); + _type = questRecord[1].GetUInt8(); + _level = questRecord[2].GetInt32(); + _scalingFactionGroup = questRecord[3].GetInt32(); + _maxScalingLevel = questRecord[4].GetInt32(); + _packageID = questRecord[5].GetUInt32(); + _minLevel = questRecord[6].GetInt32(); + _questSortID = questRecord[7].GetInt16(); + _questInfoID = questRecord[8].GetUInt16(); + _suggestedPlayers = questRecord[9].GetUInt8(); + _nextQuestInChain = questRecord[10].GetUInt32(); + _rewardXPDifficulty = questRecord[11].GetUInt32(); + _rewardXPMultiplier = questRecord[12].GetFloat(); + _rewardMoney = questRecord[13].GetUInt32(); + _rewardMoneyDifficulty = questRecord[14].GetUInt32(); + _rewardMoneyMultiplier = questRecord[15].GetFloat(); + _rewardBonusMoney = questRecord[16].GetUInt32(); for (uint32 i = 0; i < QUEST_REWARD_DISPLAY_SPELL_COUNT; ++i) RewardDisplaySpell[i] = questRecord[17 + i].GetUInt32(); - RewardSpell = questRecord[20].GetUInt32(); - RewardHonor = questRecord[21].GetUInt32(); - RewardKillHonor = questRecord[22].GetUInt32(); - SourceItemId = questRecord[23].GetUInt32(); - RewardArtifactXPDifficulty = questRecord[24].GetUInt32(); - RewardArtifactXPMultiplier = questRecord[25].GetFloat(); - RewardArtifactCategoryID = questRecord[26].GetUInt32(); - Flags = questRecord[27].GetUInt32(); - FlagsEx = questRecord[28].GetUInt32(); - FlagsEx2 = questRecord[29].GetUInt32(); + _rewardSpell = questRecord[20].GetUInt32(); + _rewardHonor = questRecord[21].GetUInt32(); + _rewardKillHonor = questRecord[22].GetUInt32(); + _sourceItemId = questRecord[23].GetUInt32(); + _rewardArtifactXPDifficulty = questRecord[24].GetUInt32(); + _rewardArtifactXPMultiplier = questRecord[25].GetFloat(); + _rewardArtifactCategoryID = questRecord[26].GetUInt32(); + _flags = questRecord[27].GetUInt32(); + _flagsEx = questRecord[28].GetUInt32(); + _flagsEx2 = questRecord[29].GetUInt32(); for (uint32 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i) { @@ -86,19 +79,19 @@ Quest::Quest(Field* questRecord) ++_rewChoiceItemsCount; } - POIContinent = questRecord[64].GetUInt32(); - POIx = questRecord[65].GetFloat(); - POIy = questRecord[66].GetFloat(); - POIPriority = questRecord[67].GetUInt32(); + _poiContinent = questRecord[64].GetUInt32(); + _poix = questRecord[65].GetFloat(); + _poiy = questRecord[66].GetFloat(); + _poiPriority = questRecord[67].GetUInt32(); - RewardTitleId = questRecord[68].GetUInt32(); - RewardArenaPoints = questRecord[69].GetUInt32(); - RewardSkillId = questRecord[70].GetUInt32(); - RewardSkillPoints = questRecord[71].GetUInt32(); + _rewardTitleId = questRecord[68].GetUInt32(); + _rewardArenaPoints = questRecord[69].GetUInt32(); + _rewardSkillId = questRecord[70].GetUInt32(); + _rewardSkillPoints = questRecord[71].GetUInt32(); - QuestGiverPortrait = questRecord[72].GetUInt32(); - QuestGiverPortraitMount = questRecord[73].GetUInt32(); - QuestTurnInPortrait = questRecord[74].GetUInt32(); + _questGiverPortrait = questRecord[72].GetUInt32(); + _questGiverPortraitMount = questRecord[73].GetUInt32(); + _questTurnInPortrait = questRecord[74].GetUInt32(); for (uint32 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i) { @@ -108,7 +101,7 @@ Quest::Quest(Field* questRecord) RewardFactionCapIn[i] = questRecord[78 + i * 4].GetUInt32(); } - RewardReputationMask = questRecord[95].GetUInt32(); + _rewardReputationMask = questRecord[95].GetUInt32(); for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) { @@ -119,33 +112,25 @@ Quest::Quest(Field* questRecord) ++_rewCurrencyCount; } - SoundAccept = questRecord[104].GetUInt32(); - SoundTurnIn = questRecord[105].GetUInt32(); - AreaGroupID = questRecord[106].GetUInt32(); - LimitTime = questRecord[107].GetUInt32(); - AllowableRaces.RawValue = questRecord[108].GetUInt64(); - TreasurePickerID = questRecord[109].GetInt32(); - Expansion = questRecord[110].GetInt32(); - ManagedWorldStateID = questRecord[111].GetInt32(); - QuestSessionBonus = questRecord[112].GetInt32(); - - LogTitle = questRecord[113].GetString(); - LogDescription = questRecord[114].GetString(); - QuestDescription = questRecord[115].GetString(); - AreaDescription = questRecord[116].GetString(); - PortraitGiverText = questRecord[117].GetString(); - PortraitGiverName = questRecord[118].GetString(); - PortraitTurnInText = questRecord[119].GetString(); - PortraitTurnInName = questRecord[120].GetString(); - QuestCompletionLog = questRecord[121].GetString(); - - for (uint32 i = 0; i < QUEST_EMOTE_COUNT; ++i) - { - DetailsEmote[i] = 0; - DetailsEmoteDelay[i] = 0; - OfferRewardEmote[i] = 0; - OfferRewardEmoteDelay[i] = 0; - } + _soundAccept = questRecord[104].GetUInt32(); + _soundTurnIn = questRecord[105].GetUInt32(); + _areaGroupID = questRecord[106].GetUInt32(); + _limitTime = questRecord[107].GetUInt32(); + _allowableRaces.RawValue = questRecord[108].GetUInt64(); + _treasurePickerID = questRecord[109].GetInt32(); + _expansion = questRecord[110].GetInt32(); + _managedWorldStateID = questRecord[111].GetInt32(); + _questSessionBonus = questRecord[112].GetInt32(); + + _logTitle = questRecord[113].GetString(); + _logDescription = questRecord[114].GetString(); + _questDescription = questRecord[115].GetString(); + _areaDescription = questRecord[116].GetString(); + _portraitGiverText = questRecord[117].GetString(); + _portraitGiverName = questRecord[118].GetString(); + _portraitTurnInText = questRecord[119].GetString(); + _portraitTurnInName = questRecord[120].GetString(); + _questCompletionLog = questRecord[121].GetString(); } void Quest::LoadQuestDetails(Field* fields) @@ -167,18 +152,18 @@ void Quest::LoadQuestDetails(Field* fields) void Quest::LoadQuestRequestItems(Field* fields) { - EmoteOnComplete = fields[1].GetUInt16(); - EmoteOnIncomplete = fields[2].GetUInt16(); + _emoteOnComplete = fields[1].GetUInt16(); + _emoteOnIncomplete = fields[2].GetUInt16(); - if (!sEmotesStore.LookupEntry(EmoteOnComplete)) - TC_LOG_ERROR("sql.sql", "Table `quest_request_items` has non-existing EmoteOnComplete (%u) set for quest %u.", EmoteOnComplete, fields[0].GetUInt32()); + if (!sEmotesStore.LookupEntry(_emoteOnComplete)) + TC_LOG_ERROR("sql.sql", "Table `quest_request_items` has non-existing EmoteOnComplete (%u) set for quest %u.", _emoteOnComplete, fields[0].GetUInt32()); - if (!sEmotesStore.LookupEntry(EmoteOnIncomplete)) - TC_LOG_ERROR("sql.sql", "Table `quest_request_items` has non-existing EmoteOnIncomplete (%u) set for quest %u.", EmoteOnIncomplete, fields[0].GetUInt32()); + if (!sEmotesStore.LookupEntry(_emoteOnIncomplete)) + TC_LOG_ERROR("sql.sql", "Table `quest_request_items` has non-existing EmoteOnIncomplete (%u) set for quest %u.", _emoteOnIncomplete, fields[0].GetUInt32()); - EmoteOnCompleteDelay = fields[3].GetUInt32(); - EmoteOnIncompleteDelay = fields[4].GetUInt32(); - RequestItemsText = fields[5].GetString(); + _emoteOnCompleteDelay = fields[3].GetUInt32(); + _emoteOnIncompleteDelay = fields[4].GetUInt32(); + _requestItemsText = fields[5].GetString(); } void Quest::LoadQuestOfferReward(Field* fields) @@ -197,39 +182,43 @@ void Quest::LoadQuestOfferReward(Field* fields) for (uint32 i = 0; i < QUEST_EMOTE_COUNT; ++i) OfferRewardEmoteDelay[i] = fields[5 + i].GetUInt32(); - OfferRewardText = fields[9].GetString(); + _offerRewardText = fields[9].GetString(); } void Quest::LoadQuestTemplateAddon(Field* fields) { - MaxLevel = fields[1].GetUInt8(); - AllowableClasses = fields[2].GetUInt32(); - SourceSpellID = fields[3].GetUInt32(); - PrevQuestID = fields[4].GetInt32(); - NextQuestID = fields[5].GetInt32(); - ExclusiveGroup = fields[6].GetInt32(); - RewardMailTemplateId = fields[7].GetUInt32(); - RewardMailDelay = fields[8].GetUInt32(); - RequiredSkillId = fields[9].GetUInt16(); - RequiredSkillPoints = fields[10].GetUInt16(); - RequiredMinRepFaction = fields[11].GetUInt16(); - RequiredMaxRepFaction = fields[12].GetUInt16(); - RequiredMinRepValue = fields[13].GetInt32(); - RequiredMaxRepValue = fields[14].GetInt32(); - SourceItemIdCount = fields[15].GetUInt8(); - RewardMailSenderEntry = fields[16].GetUInt32(); - SpecialFlags = fields[17].GetUInt8(); - ScriptId = sObjectMgr->GetScriptId(fields[18].GetString()); - - if (SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) - Flags |= QUEST_FLAGS_AUTO_ACCEPT; + _maxLevel = fields[1].GetUInt8(); + _allowableClasses = fields[2].GetUInt32(); + _sourceSpellID = fields[3].GetUInt32(); + _prevQuestID = fields[4].GetInt32(); + _nextQuestID = fields[5].GetUInt32(); + _exclusiveGroup = fields[6].GetInt32(); + _rewardMailTemplateId = fields[7].GetUInt32(); + _rewardMailDelay = fields[8].GetUInt32(); + _requiredSkillId = fields[9].GetUInt16(); + _requiredSkillPoints = fields[10].GetUInt16(); + _requiredMinRepFaction = fields[11].GetUInt16(); + _requiredMaxRepFaction = fields[12].GetUInt16(); + _requiredMinRepValue = fields[13].GetInt32(); + _requiredMaxRepValue = fields[14].GetInt32(); + _sourceItemIdCount = fields[15].GetUInt8(); + _specialFlags = fields[16].GetUInt8(); + _scriptId = sObjectMgr->GetScriptId(fields[17].GetString()); + + if (_specialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) + _flags |= QUEST_FLAGS_AUTO_ACCEPT; +} + +void Quest::LoadQuestMailSender(Field* fields) +{ + _rewardMailSenderEntry = fields[1].GetUInt32(); } void Quest::LoadQuestObjective(Field* fields) { QuestObjective obj; - obj.ID = fields[0].GetUInt32(); - obj.QuestID = fields[1].GetUInt32(); + obj.QuestID = fields[0].GetUInt32(); + obj.ID = fields[1].GetUInt32(); obj.Type = fields[2].GetUInt8(); obj.StorageIndex = fields[3].GetInt8(); obj.ObjectID = fields[4].GetInt32(); @@ -252,7 +241,7 @@ void Quest::LoadQuestObjectiveVisualEffect(Field* fields) { uint8 effectIndex = fields[3].GetUInt8(); if (effectIndex >= obj.VisualEffects.size()) - obj.VisualEffects.resize(effectIndex+1, 0); + obj.VisualEffects.resize(effectIndex + 1, 0); obj.VisualEffects[effectIndex] = fields[4].GetInt32(); break; @@ -266,20 +255,20 @@ uint32 Quest::XPValue(Player const* player) const { uint32 questLevel = player->GetQuestLevel(this); QuestXPEntry const* questXp = sQuestXPStore.LookupEntry(questLevel); - if (!questXp || RewardXPDifficulty >= 10) + if (!questXp || _rewardXPDifficulty >= 10) return 0; float multiplier = 1.0f; if (questLevel != player->getLevel()) multiplier = sXpGameTable.GetRow(std::min<int32>(player->getLevel(), questLevel))->Divisor / sXpGameTable.GetRow(player->getLevel())->Divisor; - int32 diffFactor = 2 * (questLevel + (Level == -1 ? 0 : 5) - player->getLevel()) + 10; + int32 diffFactor = 2 * (questLevel + (_level == -1 ? 0 : 5) - player->getLevel()) + 10; if (diffFactor < 1) diffFactor = 1; else if (diffFactor > 10) diffFactor = 10; - uint32 xp = diffFactor * questXp->Difficulty[RewardXPDifficulty] * RewardXPMultiplier / 10 * multiplier; + uint32 xp = diffFactor * questXp->Difficulty[_rewardXPDifficulty] * _rewardXPMultiplier / 10 * multiplier; if (xp <= 100) xp = 5 * ((xp + 2) / 5); else if (xp <= 500) @@ -354,7 +343,7 @@ uint32 Quest::GetRewMoneyMaxLevel() const return 0; // Else, return the rewarded copper sum modified by the rate - return uint32(RewardBonusMoney * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST)); + return uint32(_rewardBonusMoney * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST)); } bool Quest::IsAutoAccept() const @@ -364,12 +353,12 @@ bool Quest::IsAutoAccept() const bool Quest::IsAutoComplete() const { - return !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) && Type == QUEST_TYPE_AUTOCOMPLETE; + return !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) && _type == QUEST_TYPE_AUTOCOMPLETE; } bool Quest::IsRaidQuest(Difficulty difficulty) const { - switch (QuestInfoID) + switch (_questInfoID) { case QUEST_INFO_RAID: return true; @@ -381,7 +370,7 @@ bool Quest::IsRaidQuest(Difficulty difficulty) const break; } - if ((Flags & QUEST_FLAGS_RAID) != 0) + if ((_flags & QUEST_FLAGS_RAID) != 0) return true; return false; @@ -481,7 +470,7 @@ WorldPacket Quest::BuildQueryData(LocaleConstant loc) const response.Info.RewardXPMultiplier = GetXPMultiplier(); if (!HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) - response.Info.RewardMoney = RewardMoney; + response.Info.RewardMoney = GetRewMoney(); response.Info.RewardMoneyDifficulty = GetRewMoneyDifficulty(); response.Info.RewardMoneyMultiplier = GetMoneyMultiplier(); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index aefd9509f6b..2023a4de8e8 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -351,113 +351,138 @@ class TC_GAME_API Quest void LoadQuestRequestItems(Field* fields); void LoadQuestOfferReward(Field* fields); void LoadQuestTemplateAddon(Field* fields); + void LoadQuestMailSender(Field* fields); void LoadQuestObjective(Field* fields); void LoadQuestObjectiveVisualEffect(Field* fields); uint32 XPValue(Player const* player) const; uint32 MoneyValue(Player const* player) const; - bool HasFlag(QuestFlags flag) const { return (Flags & uint32(flag)) != 0; } - bool HasFlagEx(QuestFlagsEx flag) const { return (FlagsEx & uint32(flag)) != 0; } - bool HasFlagEx2(QuestFlagsEx2 flag) const { return (FlagsEx2 & uint32(flag)) != 0; } + bool HasFlag(QuestFlags flag) const { return (_flags & uint32(flag)) != 0; } + bool HasFlagEx(QuestFlagsEx flag) const { return (_flagsEx & uint32(flag)) != 0; } + bool HasFlagEx2(QuestFlagsEx2 flag) const { return (_flagsEx2 & uint32(flag)) != 0; } - bool HasSpecialFlag(uint32 flag) const { return (SpecialFlags & flag) != 0; } - void SetSpecialFlag(uint32 flag) { SpecialFlags |= flag; } + bool HasSpecialFlag(uint32 flag) const { return (_specialFlags & flag) != 0; } + void SetSpecialFlag(uint32 flag) { _specialFlags |= flag; } // table data accessors: - uint32 GetQuestId() const { return ID; } - uint32 GetQuestType() const { return Type; } - uint32 GetQuestPackageID() const { return PackageID; } - int32 GetZoneOrSort() const { return QuestSortID; } - int32 GetMinLevel() const { return MinLevel; } - uint32 GetMaxLevel() const { return MaxLevel; } - int32 GetQuestLevel() const { return Level; } - int32 GetQuestScalingFactionGroup() const { return ScalingFactionGroup; } - int32 GetQuestMaxScalingLevel() const { return MaxScalingLevel; } - uint32 GetQuestInfoID() const { return QuestInfoID; } - uint32 GetAllowableClasses() const { return AllowableClasses; } - Trinity::RaceMask<uint64> GetAllowableRaces() const { return AllowableRaces; } - uint32 GetRequiredSkill() const { return RequiredSkillId; } - uint32 GetRequiredSkillValue() const { return RequiredSkillPoints; } - uint32 GetRequiredMinRepFaction() const { return RequiredMinRepFaction; } - int32 GetRequiredMinRepValue() const { return RequiredMinRepValue; } - uint32 GetRequiredMaxRepFaction() const { return RequiredMaxRepFaction; } - int32 GetRequiredMaxRepValue() const { return RequiredMaxRepValue; } - uint32 GetSuggestedPlayers() const { return SuggestedPlayers; } - uint32 GetLimitTime() const { return LimitTime; } - int32 GetPrevQuestId() const { return PrevQuestID; } - int32 GetNextQuestId() const { return NextQuestID; } - int32 GetExclusiveGroup() const { return ExclusiveGroup; } - uint32 GetNextQuestInChain() const { return NextQuestInChain; } - int32 GetRewArenaPoints() const {return RewardArenaPoints; } - uint32 GetXPDifficulty() const { return RewardXPDifficulty; } - float GetXPMultiplier() const { return RewardXPMultiplier; } - float GetMoneyMultiplier() const { return RewardMoneyMultiplier; } - uint32 GetSrcItemId() const { return SourceItemId; } - uint32 GetSrcItemCount() const { return SourceItemIdCount; } - uint32 GetSrcSpell() const { return SourceSpellID; } - std::string const& GetLogTitle() const { return LogTitle; } - std::string const& GetLogDescription() const { return LogDescription; } - std::string const& GetQuestDescription() const { return QuestDescription; } - std::string const& GetAreaDescription() const { return AreaDescription; } - std::string const& GetOfferRewardText() const { return OfferRewardText; } - std::string const& GetRequestItemsText() const { return RequestItemsText; } - std::string const& GetQuestCompletionLog() const { return QuestCompletionLog; } - std::string const& GetPortraitGiverText() const { return PortraitGiverText; } - std::string const& GetPortraitGiverName() const { return PortraitGiverName; } - std::string const& GetPortraitTurnInText() const { return PortraitTurnInText; } - std::string const& GetPortraitTurnInName() const { return PortraitTurnInName; } + uint32 GetQuestId() const { return _id; } + uint32 GetQuestType() const { return _type; } + uint32 GetQuestPackageID() const { return _packageID; } + int32 GetZoneOrSort() const { return _questSortID; } + int32 GetMinLevel() const { return _minLevel; } + uint32 GetMaxLevel() const { return _maxLevel; } + int32 GetQuestLevel() const { return _level; } + int32 GetQuestScalingFactionGroup() const { return _scalingFactionGroup; } + int32 GetQuestMaxScalingLevel() const { return _maxScalingLevel; } + uint32 GetQuestInfoID() const { return _questInfoID; } + uint32 GetAllowableClasses() const { return _allowableClasses; } + Trinity::RaceMask<uint64> GetAllowableRaces() const { return _allowableRaces; } + uint32 GetRequiredSkill() const { return _requiredSkillId; } + uint32 GetRequiredSkillValue() const { return _requiredSkillPoints; } + uint32 GetRequiredMinRepFaction() const { return _requiredMinRepFaction; } + int32 GetRequiredMinRepValue() const { return _requiredMinRepValue; } + uint32 GetRequiredMaxRepFaction() const { return _requiredMaxRepFaction; } + int32 GetRequiredMaxRepValue() const { return _requiredMaxRepValue; } + uint32 GetSuggestedPlayers() const { return _suggestedPlayers; } + uint32 GetLimitTime() const { return _limitTime; } + int32 GetPrevQuestId() const { return _prevQuestID; } + uint32 GetNextQuestId() const { return _nextQuestID; } + int32 GetExclusiveGroup() const { return _exclusiveGroup; } + uint32 GetNextQuestInChain() const { return _nextQuestInChain; } + int32 GetRewArenaPoints() const {return _rewardArenaPoints; } + uint32 GetXPDifficulty() const { return _rewardXPDifficulty; } + float GetXPMultiplier() const { return _rewardXPMultiplier; } + float GetMoneyMultiplier() const { return _rewardMoneyMultiplier; } + uint32 GetSrcItemId() const { return _sourceItemId; } + uint32 GetSrcItemCount() const { return _sourceItemIdCount; } + uint32 GetSrcSpell() const { return _sourceSpellID; } + std::string const& GetLogTitle() const { return _logTitle; } + std::string const& GetLogDescription() const { return _logDescription; } + std::string const& GetQuestDescription() const { return _questDescription; } + std::string const& GetAreaDescription() const { return _areaDescription; } + std::string const& GetOfferRewardText() const { return _offerRewardText; } + std::string const& GetRequestItemsText() const { return _requestItemsText; } + std::string const& GetQuestCompletionLog() const { return _questCompletionLog; } + std::string const& GetPortraitGiverText() const { return _portraitGiverText; } + std::string const& GetPortraitGiverName() const { return _portraitGiverName; } + std::string const& GetPortraitTurnInText() const { return _portraitTurnInText; } + std::string const& GetPortraitTurnInName() const { return _portraitTurnInName; } QuestObjectives const& GetObjectives() const { return Objectives; } - uint32 GetRewMoneyDifficulty() const { return RewardMoneyDifficulty; } - uint32 GetRewHonor() const { return RewardHonor; } - uint32 GetRewKillHonor() const { return RewardKillHonor; } - uint32 GetArtifactXPDifficulty() const { return RewardArtifactXPDifficulty; } - float GetArtifactXPMultiplier() const { return RewardArtifactXPMultiplier; } - uint32 GetArtifactCategoryId() const { return RewardArtifactCategoryID; } + uint32 GetRewMoney() const { return _rewardMoney; } + uint32 GetRewMoneyDifficulty() const { return _rewardMoneyDifficulty; } + uint32 GetRewHonor() const { return _rewardHonor; } + uint32 GetRewKillHonor() const { return _rewardKillHonor; } + uint32 GetArtifactXPDifficulty() const { return _rewardArtifactXPDifficulty; } + float GetArtifactXPMultiplier() const { return _rewardArtifactXPMultiplier; } + uint32 GetArtifactCategoryId() const { return _rewardArtifactCategoryID; } uint32 GetRewMoneyMaxLevel() const; // use in XP calculation at client - uint32 GetRewSpell() const { return RewardSpell; } - uint32 GetRewMailTemplateId() const { return RewardMailTemplateId; } - uint32 GetRewMailDelaySecs() const { return RewardMailDelay; } - uint32 GetRewMailSenderEntry() const { return RewardMailSenderEntry; } - uint32 GetRewTitle() const { return RewardTitleId; } - uint32 GetPOIContinent() const { return POIContinent; } - float GetPOIx() const { return POIx; } - float GetPOIy() const { return POIy; } - uint32 GetPOIPriority() const { return POIPriority; } - uint32 GetSoundAccept() const { return SoundAccept; } - uint32 GetSoundTurnIn() const { return SoundTurnIn; } - uint32 GetIncompleteEmote() const { return EmoteOnIncomplete; } - uint32 GetCompleteEmote() const { return EmoteOnComplete; } - bool IsRepeatable() const { return SpecialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE; } + uint32 GetRewSpell() const { return _rewardSpell; } + uint32 GetRewMailTemplateId() const { return _rewardMailTemplateId; } + uint32 GetRewMailDelaySecs() const { return _rewardMailDelay; } + uint32 GetRewMailSenderEntry() const { return _rewardMailSenderEntry; } + uint32 GetRewTitle() const { return _rewardTitleId; } + uint32 GetPOIContinent() const { return _poiContinent; } + float GetPOIx() const { return _poix; } + float GetPOIy() const { return _poiy; } + uint32 GetPOIPriority() const { return _poiPriority; } + uint32 GetSoundAccept() const { return _soundAccept; } + uint32 GetSoundTurnIn() const { return _soundTurnIn; } + uint32 GetIncompleteEmote() const { return _emoteOnIncomplete; } + uint32 GetCompleteEmote() const { return _emoteOnComplete; } + uint32 GetIncompleteEmoteDelay() const { return _emoteOnIncompleteDelay; } + uint32 GetCompleteEmoteDelay() const { return _emoteOnCompleteDelay; } + bool IsRepeatable() const { return _specialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE; } bool IsAutoAccept() const; bool IsAutoComplete() const; - uint32 GetFlags() const { return Flags; } - uint32 GetFlagsEx() const { return FlagsEx; } - uint32 GetFlagsEx2() const { return FlagsEx2; } - uint32 GetSpecialFlags() const { return SpecialFlags; } - uint32 GetScriptId() const { return ScriptId; } - uint32 GetAreaGroupID() const { return AreaGroupID; } - uint32 GetRewardSkillId() const { return RewardSkillId; } - uint32 GetRewardSkillPoints() const { return RewardSkillPoints; } - uint32 GetRewardReputationMask() const { return RewardReputationMask; } - int32 GetTreasurePickerId() const { return TreasurePickerID; } - int32 GetExpansion() const { return Expansion; } - int32 GetManagedWorldStateId() const { return ManagedWorldStateID; } - int32 GetQuestSessionBonus() const { return QuestSessionBonus; } - uint32 GetQuestGiverPortrait() const { return QuestGiverPortrait; } - int32 GetQuestGiverPortraitMount() const { return QuestGiverPortraitMount; } - uint32 GetQuestTurnInPortrait() const { return QuestTurnInPortrait; } - bool IsDaily() const { return (Flags & QUEST_FLAGS_DAILY) != 0; } - bool IsWeekly() const { return (Flags & QUEST_FLAGS_WEEKLY) != 0; } - bool IsMonthly() const { return (SpecialFlags & QUEST_SPECIAL_FLAGS_MONTHLY) != 0; } - bool IsSeasonal() const { return (QuestSortID == -QUEST_SORT_SEASONAL || QuestSortID == -QUEST_SORT_SPECIAL || QuestSortID == -QUEST_SORT_LUNAR_FESTIVAL || QuestSortID == -QUEST_SORT_MIDSUMMER || QuestSortID == -QUEST_SORT_BREWFEST || QuestSortID == -QUEST_SORT_LOVE_IS_IN_THE_AIR || QuestSortID == -QUEST_SORT_NOBLEGARDEN) && !IsRepeatable(); } - bool IsDailyOrWeekly() const { return (Flags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY)) != 0; } + uint32 GetFlags() const { return _flags; } + uint32 GetFlagsEx() const { return _flagsEx; } + uint32 GetFlagsEx2() const { return _flagsEx2; } + uint32 GetSpecialFlags() const { return _specialFlags; } + uint32 GetScriptId() const { return _scriptId; } + uint32 GetAreaGroupID() const { return _areaGroupID; } + uint32 GetRewardSkillId() const { return _rewardSkillId; } + uint32 GetRewardSkillPoints() const { return _rewardSkillPoints; } + uint32 GetRewardReputationMask() const { return _rewardReputationMask; } + int32 GetTreasurePickerId() const { return _treasurePickerID; } + int32 GetExpansion() const { return _expansion; } + int32 GetManagedWorldStateId() const { return _managedWorldStateID; } + int32 GetQuestSessionBonus() const { return _questSessionBonus; } + uint32 GetQuestGiverPortrait() const { return _questGiverPortrait; } + int32 GetQuestGiverPortraitMount() const { return _questGiverPortraitMount; } + uint32 GetQuestTurnInPortrait() const { return _questTurnInPortrait; } + bool IsDaily() const { return (_flags & QUEST_FLAGS_DAILY) != 0; } + bool IsWeekly() const { return (_flags & QUEST_FLAGS_WEEKLY) != 0; } + bool IsMonthly() const { return (_specialFlags & QUEST_SPECIAL_FLAGS_MONTHLY) != 0; } + bool IsSeasonal() const { return (_questSortID == -QUEST_SORT_SEASONAL || _questSortID == -QUEST_SORT_SPECIAL || _questSortID == -QUEST_SORT_LUNAR_FESTIVAL || _questSortID == -QUEST_SORT_MIDSUMMER || _questSortID == -QUEST_SORT_BREWFEST || _questSortID == -QUEST_SORT_LOVE_IS_IN_THE_AIR || _questSortID == -QUEST_SORT_NOBLEGARDEN) && !IsRepeatable(); } + bool IsDailyOrWeekly() const { return (_flags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY)) != 0; } bool IsRaidQuest(Difficulty difficulty) const; bool IsAllowedInRaid(Difficulty difficulty) const; - bool IsDFQuest() const { return (SpecialFlags & QUEST_SPECIAL_FLAGS_DF_QUEST) != 0; } + bool IsDFQuest() const { return (_specialFlags & QUEST_SPECIAL_FLAGS_DF_QUEST) != 0; } uint32 CalculateHonorGain(uint8 level) const; bool CanIncreaseRewardedQuestCounters() const; + // multiple values + uint32 RewardDisplaySpell[QUEST_REWARD_DISPLAY_SPELL_COUNT] = { }; + uint32 RewardItemId[QUEST_REWARD_ITEM_COUNT] = { }; + uint32 RewardItemCount[QUEST_REWARD_ITEM_COUNT] = { }; + uint32 ItemDrop[QUEST_ITEM_DROP_COUNT] = { }; + uint32 ItemDropQuantity[QUEST_ITEM_DROP_COUNT] = { }; + uint32 RewardChoiceItemId[QUEST_REWARD_CHOICES_COUNT] = { }; + uint32 RewardChoiceItemCount[QUEST_REWARD_CHOICES_COUNT] = { }; + uint32 RewardChoiceItemDisplayId[QUEST_REWARD_CHOICES_COUNT] = { }; + uint32 RewardFactionId[QUEST_REWARD_REPUTATIONS_COUNT] = { }; + int32 RewardFactionValue[QUEST_REWARD_REPUTATIONS_COUNT] = { }; + int32 RewardFactionOverride[QUEST_REWARD_REPUTATIONS_COUNT] = { }; + uint32 RewardFactionCapIn[QUEST_REWARD_REPUTATIONS_COUNT] = { }; + uint32 RewardCurrencyId[QUEST_REWARD_CURRENCY_COUNT] = { }; + uint32 RewardCurrencyCount[QUEST_REWARD_CURRENCY_COUNT] = { }; + QuestObjectives Objectives = { }; + uint32 DetailsEmote[QUEST_EMOTE_COUNT] = { }; + uint32 DetailsEmoteDelay[QUEST_EMOTE_COUNT] = { }; + uint32 OfferRewardEmote[QUEST_EMOTE_COUNT] = { }; + uint32 OfferRewardEmoteDelay[QUEST_EMOTE_COUNT] = { }; + uint32 GetRewChoiceItemsCount() const { return _rewChoiceItemsCount; } uint32 GetRewItemsCount() const { return _rewItemsCount; } uint32 GetRewCurrencyCount() const { return _rewCurrencyCount; } @@ -471,141 +496,111 @@ class TC_GAME_API Quest void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const; - typedef std::vector<int32> PrevQuests; - PrevQuests prevQuests; - typedef std::vector<uint32> PrevChainQuests; - PrevChainQuests prevChainQuests; + std::vector<uint32> DependentPreviousQuests; + std::vector<uint32> PrevChainQuests; WorldPacket QueryData[TOTAL_LOCALES]; private: - uint32 _rewChoiceItemsCount; - uint32 _rewItemsCount; - uint16 _eventIdForQuest; - uint32 _rewCurrencyCount; + uint32 _rewChoiceItemsCount = 0; + uint32 _rewItemsCount = 0; + uint16 _eventIdForQuest = 0; + uint32 _rewCurrencyCount = 0; - public: // wdb data (quest query response) - uint32 ID; - uint32 Type; - int32 Level; - int32 ScalingFactionGroup; - int32 MaxScalingLevel; - uint32 PackageID; - int32 MinLevel; - int32 QuestSortID; - uint32 QuestInfoID; - uint32 SuggestedPlayers; - uint32 NextQuestInChain; - uint32 RewardXPDifficulty; - float RewardXPMultiplier; - int32 RewardMoney; - uint32 RewardMoneyDifficulty; - float RewardMoneyMultiplier; - uint32 RewardBonusMoney; - uint32 RewardDisplaySpell[QUEST_REWARD_DISPLAY_SPELL_COUNT]; - uint32 RewardSpell; - uint32 RewardHonor; - uint32 RewardKillHonor; - uint32 RewardArtifactXPDifficulty; - float RewardArtifactXPMultiplier; - uint32 RewardArtifactCategoryID; - uint32 SourceItemId; - uint32 Flags; - uint32 FlagsEx; - uint32 FlagsEx2; - uint32 RewardItemId[QUEST_REWARD_ITEM_COUNT]; - uint32 RewardItemCount[QUEST_REWARD_ITEM_COUNT]; - uint32 ItemDrop[QUEST_ITEM_DROP_COUNT]; - uint32 ItemDropQuantity[QUEST_ITEM_DROP_COUNT]; - uint32 RewardChoiceItemId[QUEST_REWARD_CHOICES_COUNT]; - uint32 RewardChoiceItemCount[QUEST_REWARD_CHOICES_COUNT]; - uint32 RewardChoiceItemDisplayId[QUEST_REWARD_CHOICES_COUNT]; - uint32 POIContinent; - float POIx; - float POIy; - uint32 POIPriority; - uint32 RewardTitleId; - int32 RewardArenaPoints; - uint32 RewardSkillId; - uint32 RewardSkillPoints; - uint32 QuestGiverPortrait; - int32 QuestGiverPortraitMount; - uint32 QuestTurnInPortrait; - uint32 RewardFactionId[QUEST_REWARD_REPUTATIONS_COUNT]; - int32 RewardFactionValue[QUEST_REWARD_REPUTATIONS_COUNT]; - int32 RewardFactionOverride[QUEST_REWARD_REPUTATIONS_COUNT]; - uint32 RewardFactionCapIn[QUEST_REWARD_REPUTATIONS_COUNT]; - uint32 RewardReputationMask; - uint32 RewardCurrencyId[QUEST_REWARD_CURRENCY_COUNT]; - uint32 RewardCurrencyCount[QUEST_REWARD_CURRENCY_COUNT]; - uint32 SoundAccept; - uint32 SoundTurnIn; - uint32 AreaGroupID; - uint32 LimitTime; - Trinity::RaceMask<uint64> AllowableRaces; - int32 TreasurePickerID; - int32 Expansion; - int32 ManagedWorldStateID; - int32 QuestSessionBonus; - QuestObjectives Objectives; - std::string LogTitle; - std::string LogDescription; - std::string QuestDescription; - std::string AreaDescription; - std::string PortraitGiverText; - std::string PortraitGiverName; - std::string PortraitTurnInText; - std::string PortraitTurnInName; - std::string QuestCompletionLog; - - protected: - - // quest_detais table - uint32 DetailsEmote[QUEST_EMOTE_COUNT] = { }; - uint32 DetailsEmoteDelay[QUEST_EMOTE_COUNT] = { }; + uint32 _id = 0; + uint32 _type = 0; + int32 _level = 0; + int32 _scalingFactionGroup = 0; + int32 _maxScalingLevel = 0; + uint32 _packageID = 0; + int32 _minLevel = 0; + int32 _questSortID = 0; + uint32 _questInfoID = 0; + uint32 _suggestedPlayers = 0; + uint32 _nextQuestInChain = 0; + uint32 _rewardXPDifficulty = 0; + float _rewardXPMultiplier = 0.f; + int32 _rewardMoney = 0; + uint32 _rewardMoneyDifficulty = 0; + float _rewardMoneyMultiplier = 0.f; + uint32 _rewardBonusMoney = 0; + uint32 _rewardSpell = 0; + uint32 _rewardHonor = 0; + uint32 _rewardKillHonor = 0; + uint32 _rewardArtifactXPDifficulty = 0; + float _rewardArtifactXPMultiplier = 0.f; + uint32 _rewardArtifactCategoryID = 0; + uint32 _sourceItemId = 0; + uint32 _flags = 0; + uint32 _flagsEx = 0; + uint32 _flagsEx2 = 0; + uint32 _poiContinent = 0; + float _poix = 0.f; + float _poiy = 0.f; + uint32 _poiPriority = 0; + uint32 _rewardTitleId = 0; + int32 _rewardArenaPoints = 0; + uint32 _rewardSkillId = 0; + uint32 _rewardSkillPoints = 0; + uint32 _questGiverPortrait = 0; + int32 _questGiverPortraitMount = 0; + uint32 _questTurnInPortrait = 0; + uint32 _rewardReputationMask; + uint32 _soundAccept = 0; + uint32 _soundTurnIn = 0; + uint32 _areaGroupID = 0; + uint32 _limitTime = 0; + Trinity::RaceMask<uint64> _allowableRaces; + int32 _treasurePickerID = 0; + int32 _expansion = 0; + int32 _managedWorldStateID = 0; + int32 _questSessionBonus = 0; + std::string _logTitle; + std::string _logDescription; + std::string _questDescription; + std::string _areaDescription; + std::string _portraitGiverText; + std::string _portraitGiverName; + std::string _portraitTurnInText; + std::string _portraitTurnInName; + std::string _questCompletionLog; // quest_request_items table - uint32 EmoteOnComplete = 0; - uint32 EmoteOnIncomplete = 0; - uint32 EmoteOnCompleteDelay = 0; - uint32 EmoteOnIncompleteDelay = 0; - std::string RequestItemsText; + uint32 _emoteOnComplete = 0; + uint32 _emoteOnIncomplete = 0; + uint32 _emoteOnCompleteDelay = 0; + uint32 _emoteOnIncompleteDelay = 0; + std::string _requestItemsText; // quest_offer_reward table - uint32 OfferRewardEmote[QUEST_EMOTE_COUNT] = { }; - uint32 OfferRewardEmoteDelay[QUEST_EMOTE_COUNT] = { }; - std::string OfferRewardText; + std::string _offerRewardText; // quest_template_addon table (custom data) - uint32 MaxLevel = 0; - uint32 AllowableClasses = 0; - uint32 SourceSpellID = 0; - int32 PrevQuestID = 0; - int32 NextQuestID = 0; - int32 ExclusiveGroup = 0; - uint32 RewardMailTemplateId = 0; - uint32 RewardMailDelay = 0; - uint32 RequiredSkillId = 0; - uint32 RequiredSkillPoints = 0; - uint32 RequiredMinRepFaction = 0; - int32 RequiredMinRepValue = 0; - uint32 RequiredMaxRepFaction = 0; - int32 RequiredMaxRepValue = 0; - uint32 SourceItemIdCount = 0; - uint32 RewardMailSenderEntry = 0; - uint32 SpecialFlags = 0; // custom flags, not sniffed/WDB - uint32 ScriptId = 0; + uint32 _maxLevel = 0; + uint32 _allowableClasses = 0; + uint32 _sourceSpellID = 0; + int32 _prevQuestID = 0; + uint32 _nextQuestID = 0; + int32 _exclusiveGroup = 0; + uint32 _rewardMailTemplateId = 0; + uint32 _rewardMailDelay = 0; + uint32 _requiredSkillId = 0; + uint32 _requiredSkillPoints = 0; + uint32 _requiredMinRepFaction = 0; + int32 _requiredMinRepValue = 0; + uint32 _requiredMaxRepFaction = 0; + int32 _requiredMaxRepValue = 0; + uint32 _sourceItemIdCount = 0; + uint32 _rewardMailSenderEntry = 0; + uint32 _specialFlags = 0; // custom flags, not sniffed/WDB + uint32 _scriptId = 0; }; struct QuestStatusData { - QuestStatusData(): Status(QUEST_STATUS_NONE), Timer(0) - { - } - - QuestStatus Status; - uint32 Timer; - std::vector<int32> ObjectiveData; + QuestStatus Status = QUEST_STATUS_NONE; + uint32 Timer = 0; + std::vector<int32> ObjectiveData = { }; }; #endif diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 14db03c5b92..566ecfd9df8 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -215,7 +215,7 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleModMechanicImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK &AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS &AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK - &AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT + &AuraEffect::HandleShieldBlockValuePercent, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT &AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED &AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance &AuraEffect::HandleUnused, //153 Unused (4.3.4) old SPELL_AURA_SPLIT_DAMAGE_FLAT @@ -347,7 +347,7 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //279 SPELL_AURA_INITIALIZE_IMAGES &AuraEffect::HandleUnused, //280 unused (4.3.4) old SPELL_AURA_MOD_ARMOR_PENETRATION_PCT &AuraEffect::HandleNULL, //281 SPELL_AURA_MOD_GUILD_REPUTATION_GAIN_PCT - &AuraEffect::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT + &AuraEffect::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_MOD_BASE_HEALTH_PCT &AuraEffect::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus &AuraEffect::HandleAuraLinked, //284 SPELL_AURA_LINKED &AuraEffect::HandleAuraLinked, //285 SPELL_AURA_LINKED_2 @@ -790,6 +790,9 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply) for (AuraApplication* aurApp : effectApplications) { + if (aurApp->GetRemoveMode() != AURA_REMOVE_NONE) + continue; + aurApp->GetTarget()->_RegisterAuraEffect(this, true); HandleEffect(aurApp, handleMask, true); } @@ -2038,7 +2041,7 @@ void AuraEffect::HandleAuraModScale(AuraApplication const* aurApp, uint8 mode, b Unit* target = aurApp->GetTarget(); float scale = target->GetObjectScale(); - ApplyPercentModFloatVar(scale, float(GetAmount()), apply); + scale += CalculatePct(1.0f, apply ? GetAmount() : -GetAmount()); target->SetObjectScale(scale); } @@ -2223,11 +2226,15 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, Player* player = target->ToPlayer(); if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) { - uint8 attacktype = Player::GetAttackBySlot(slot, item->GetTemplate()->GetInventoryType()); + WeaponAttackType const attackType = Player::GetAttackBySlot(slot, item->GetTemplate()->GetInventoryType()); player->ApplyItemDependentAuras(item, !apply); - if (attacktype < MAX_ATTACK) + if (attackType != MAX_ATTACK) + { player->_ApplyWeaponDamage(slot, item, !apply); + if (!apply) // apply case already handled on item dependent aura removal (if any) + player->UpdateWeaponDependentAuras(attackType); + } } } @@ -2719,9 +2726,19 @@ void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool return; Unit* target = aurApp->GetTarget(); - for (int8 i = 0; i < MAX_SPELL_SCHOOL; ++i) + for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i) + { if (GetMiscValue() & (1 << i)) - ApplyPercentModFloatVar(target->m_threatModifier[i], float(GetAmount()), apply); + { + if (apply) + AddPct(target->m_threatModifier[i], GetAmount()); + else + { + float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_THREAT, 1 << i); + target->m_threatModifier[i] = amount; + } + } + } } void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3210,9 +3227,9 @@ void AuraEffect::HandleAuraModResistance(AuraApplication const* aurApp, uint8 mo Unit* target = aurApp->GetTarget(); - for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) - if (GetMiscValue() & int32(1<<x)) - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply); + for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; ++x) + if (GetMiscValue() & (1 << x)) + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3227,36 +3244,50 @@ void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, u { //pets only have base armor if (target->IsPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) - target->HandleStatModifier(UNIT_MOD_ARMOR, BASE_PCT, float(GetAmount()), apply); + { + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_ARMOR, BASE_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_BASE_RESISTANCE_PCT, SPELL_SCHOOL_MASK_NORMAL); + target->SetStatPctModifier(UNIT_MOD_ARMOR, BASE_PCT, amount); + } + } } else { - for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) + for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; ++x) { - if (GetMiscValue() & int32(1<<x)) - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount()), apply); + if (GetMiscValue() & (1 << x)) + { + if (apply) + target->ApplyStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_BASE_RESISTANCE_PCT, 1 << x); + target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, amount); + } + } } } } -void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_RESISTANCE_PCT); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; - for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) { - if (GetMiscValue() & int32(1<<i)) + if (GetMiscValue() & (1 << i)) { - if (spellGroupVal) - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, (float)spellGroupVal, !apply); + float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_RESISTANCE_PCT, 1 << i); + if (target->GetPctModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT) == amount) + continue; - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply); + target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, amount); } } } @@ -3271,15 +3302,15 @@ void AuraEffect::HandleModBaseResistance(AuraApplication const* aurApp, uint8 mo // only players have base stats if (target->GetTypeId() != TYPEID_PLAYER) { - //only pets have base stats + //pets only have base armor if (target->IsPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) - target->HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(GetAmount()), apply); } else { - for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) - if (GetMiscValue() & (1<<i)) - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply); + for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) + if (GetMiscValue() & (1 << i)) + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply); } } @@ -3323,22 +3354,21 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo if (abs(spellGroupVal) >= abs(GetAmount())) return; - for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { // -1 or -2 is all stats (misc < -2 checked in function beginning) if (GetMiscValue() < 0 || GetMiscValue() == i) { if (spellGroupVal) { - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply); + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatBuffMod(Stats(i), float(spellGroupVal), !apply); + target->UpdateStatBuffMod(Stats(i)); } - //target->ApplyStatMod(Stats(i), m_amount, apply); - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatBuffMod(Stats(i), (float)GetAmount(), apply); + target->UpdateStatBuffMod(Stats(i)); } } } @@ -3363,7 +3393,20 @@ void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode, for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { if (GetMiscValue() == i || GetMiscValue() == -1) - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount), apply); + { + if (apply) + target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount)); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1) + return true; + return false; + }); + target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, amount); + } + } } } @@ -3450,28 +3493,12 @@ void AuraEffect::HandleModHealingDonePct(AuraApplication const* aurApp, uint8 mo player->UpdateHealingDonePercentMod(); } -void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, -1); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; - - if (spellGroupVal) - { - for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) - { - if (GetMiscValue() == i || GetMiscValue() == -1) // affect the same stats - { - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal), !apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal), !apply); - } - } - } // save current health state float healthPct = target->GetHealthPct(); @@ -3483,30 +3510,29 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 if (target->getDeathState() == CORPSE) zeroHealth = (target->GetHealth() == 0); - for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { if (GetMiscValueB() & 1 << i || !GetMiscValueB()) // 0 is also used for all stats { - int32 spellGroupVal2 = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, i); - if (abs(spellGroupVal2) >= abs(GetAmount())) - continue; - - if (spellGroupVal2) + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [i](AuraEffect const* aurEff) -> bool { - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal2), !apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal2), !apply); - } + if (aurEff->GetMiscValueB() & 1 << i || !aurEff->GetMiscValueB()) + return true; + return false; + }); - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetAmount()), apply); + if (target->GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT) == amount) + continue; + + target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, amount); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatPercentBuffMod(Stats(i), float(GetAmount()), apply); + target->UpdateStatBuffMod(Stats(i)); } } - // recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_UNK4 0x00000010 flag) + // recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_ABILITY 0x00000010 flag) // this check is total bullshit i think - if (GetMiscValueB() & 1 << STAT_STAMINA && (m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY))) + if ((GetMiscValueB() & 1 << STAT_STAMINA || !GetMiscValueB()) && (m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY))) target->SetHealth(std::max<uint32>(CalculatePct(target->GetMaxHealth(), healthPct), (zeroHealth ? 0 : 1))); } @@ -3567,8 +3593,8 @@ void AuraEffect::HandleModStatBonusPercent(AuraApplication const* aurApp, uint8 { if (GetMiscValue() == i || GetMiscValue() == -1) { - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT_EXCLUDE_CREATE, float(m_amount), apply); - target->ApplyStatPercentBuffMod(Stats(i), float(m_amount), apply); + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT_EXCLUDE_CREATE, float(m_amount), apply); + target->UpdateStatBuffMod(Stats(i)); } } } @@ -3623,7 +3649,7 @@ void AuraEffect::HandleAuraModMaxPower(AuraApplication const* aurApp, uint8 mode Powers power = Powers(GetMiscValue()); UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - target->HandleStatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); } /********************************/ @@ -3688,7 +3714,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint if (apply) { - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); target->ModifyHealth(GetAmount()); } else @@ -3698,7 +3724,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint int32 value = std::min<int32>(target->GetHealth() - 1, GetAmount()); target->ModifyHealth(-value); } - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); } } @@ -3711,7 +3737,7 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u float percent = target->GetHealthPct(); - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); // refresh percentage if (target->GetHealth() > 0) @@ -3730,7 +3756,7 @@ void AuraEffect::HandleAuraModIncreaseEnergy(AuraApplication const* aurApp, uint Powers powerType = Powers(GetMiscValue()); UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType); - target->HandleStatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3748,7 +3774,26 @@ void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurAp int32 oldMaxPower = target->GetMaxPower(powerType); // Handle aura effect for max power - target->HandleStatModifier(unitMod, TOTAL_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(unitMod, TOTAL_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT, [powerType](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == powerType) + return true; + return false; + }); + + amount *= target->GetTotalAuraMultiplier(SPELL_AURA_MOD_MAX_POWER_PCT, [powerType](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == powerType) + return true; + return false; + }); + + target->SetStatPctModifier(unitMod, TOTAL_PCT, amount); + } // Calculate the current power change int32 change = target->GetMaxPower(powerType) - oldMaxPower; @@ -3765,11 +3810,17 @@ void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurAp // Unit will keep hp% after MaxHealth being modified if unit is alive. float percent = target->GetHealthPct(); - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); + target->SetStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, amount); + } if (target->GetHealth() > 0) { - uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1); + uint32 newHealth = std::max<uint32>(CalculatePct(target->GetMaxHealth(), percent), 1); target->SetHealth(newHealth); } } @@ -3781,7 +3832,13 @@ void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurA Unit* target = aurApp->GetTarget(); - target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_BASE_HEALTH_PCT); + target->SetStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, amount); + } } void AuraEffect::HandleAuraModIncreaseBaseManaPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3789,7 +3846,15 @@ void AuraEffect::HandleAuraModIncreaseBaseManaPercent(AuraApplication const* aur if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - aurApp->GetTarget()->HandleStatModifier(UNIT_MOD_MANA, BASE_PCT, float(GetAmount()), apply); + Unit* target = aurApp->GetTarget(); + + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_MANA, BASE_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_BASE_MANA_PCT); + target->SetStatPctModifier(UNIT_MOD_MANA, BASE_PCT, amount); + } } void AuraEffect::HandleAuraModPowerDisplay(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3845,7 +3910,26 @@ void AuraEffect::HandleAuraModMaxPowerPct(AuraApplication const* aurApp, uint8 m int32 oldMaxPower = target->GetMaxPower(powerType); // Handle aura effect for max power - target->HandleStatModifier(unitMod, TOTAL_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(unitMod, TOTAL_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_MAX_POWER_PCT, [powerType](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == powerType) + return true; + return false; + }); + + amount *= target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT, [powerType](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == powerType) + return true; + return false; + }); + + target->SetStatPctModifier(unitMod, TOTAL_PCT, amount); + } // Calculate the current power change int32 change = target->GetMaxPower(powerType) - oldMaxPower; @@ -3901,19 +3985,16 @@ void AuraEffect::HandleAuraModRegenInterrupt(AuraApplication const* aurApp, uint HandleModManaRegen(aurApp, mode, apply); } -void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Player* target = aurApp->GetTarget()->ToPlayer(); - if (!target) return; - target->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); - target->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); - target->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); + target->UpdateAllWeaponDependentCritAuras(); } void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3945,7 +4026,7 @@ void AuraEffect::HandleModSpellHitChance(AuraApplication const* aurApp, uint8 mo if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->UpdateSpellHitChances(); else - target->m_modSpellHitChance += (apply) ? GetAmount(): (-GetAmount()); + target->m_modSpellHitChance += (apply) ? GetAmount() : (-GetAmount()); } void AuraEffect::HandleModSpellCritChance(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3958,7 +4039,7 @@ void AuraEffect::HandleModSpellCritChance(AuraApplication const* aurApp, uint8 m if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->UpdateSpellCritChance(); else - target->m_baseSpellCritChance += (apply) ? GetAmount():-GetAmount(); + target->m_baseSpellCritChance += (apply) ? GetAmount() : -GetAmount(); } void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3970,13 +4051,11 @@ void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode, if (target->GetTypeId() != TYPEID_PLAYER) { - target->m_baseSpellCritChance += (apply) ? GetAmount():-GetAmount(); + target->m_baseSpellCritChance += (apply) ? GetAmount() : -GetAmount(); return; } - target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); + target->ToPlayer()->UpdateAllWeaponDependentCritAuras(); // included in Player::UpdateSpellCritChance calculation target->ToPlayer()->UpdateSpellCritChance(); @@ -4136,7 +4215,7 @@ void AuraEffect::HandleAuraModAttackPower(AuraApplication const* aurApp, uint8 m Unit* target = aurApp->GetTarget(); - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4149,7 +4228,7 @@ void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, u if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0) return; - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4160,7 +4239,13 @@ void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, Unit* target = aurApp->GetTarget(); //UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1 - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_ATTACK_POWER_PCT); + target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, amount); + } } void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4174,7 +4259,13 @@ void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* au return; //UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1 - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT); + target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, amount); + } } /********************************/ @@ -4188,11 +4279,7 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, Unit* target = aurApp->GetTarget(); if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - { - target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply); - } + target->UpdateAllDamageDoneMods(); // Magic damage modifiers implemented in Unit::SpellBaseDamageBonusDone // This information for client side use only @@ -4212,53 +4299,40 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, } } -void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; + // also handles spell group stacks if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - { - if (spellGroupVal) - { - target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(spellGroupVal), !apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(spellGroupVal), !apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(spellGroupVal), !apply); - } - - target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply); - } + target->UpdateAllDamagePctDoneMods(); if (Player* thisPlayer = target->ToPlayer()) { - for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i) + for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i) { if (GetMiscValue() & (1 << i)) { - if (spellGroupVal) - thisPlayer->ApplyModDamageDonePercent(SpellSchools(i), float(spellGroupVal), !apply); - - thisPlayer->ApplyModDamageDonePercent(SpellSchools(i), float(GetAmount()), apply); + // only aura type modifying PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + float amount = thisPlayer->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, 1 << i); + thisPlayer->SetModDamageDonePercent(i, amount); } } } } -void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); + // also handles spell group stacks + target->UpdateDamagePctDoneMods(OFF_ATTACK); } void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4267,7 +4341,25 @@ void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mod return; if (Player* player = aurApp->GetTarget()->ToPlayer()) - player->HandleBaseModValue(SHIELD_BLOCK_VALUE, PCT_MOD, float(GetAmount()), apply); + player->HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(GetAmount()), apply); +} + +void AuraEffect::HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; + + Player* target = aurApp->GetTarget()->ToPlayer(); + if (!target) + return; + + if (apply) + target->ApplyBaseModPctValue(SHIELD_BLOCK_VALUE, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT); + target->SetBaseModPctValue(SHIELD_BLOCK_VALUE, amount); + } } /********************************/ diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 138ea474e31..7b74320bdef 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -290,6 +290,7 @@ class TC_GAME_API AuraEffect void HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; // power cost void HandleModPowerCostPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModPowerCost(AuraApplication const* aurApp, uint8 mode, bool apply) const; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 074da315ad3..175959a15d4 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -2312,7 +2312,7 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* c case SPELL_EFFECT_APPLY_AREA_AURA_RAID: { units.push_back(GetUnitOwner()); - Trinity::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, effect->Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS)); + Trinity::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, effect->Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS), false, true); Trinity::UnitListSearcher<Trinity::AnyGroupedUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check); Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); break; @@ -2320,14 +2320,14 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* c case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: { units.push_back(GetUnitOwner()); - Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS)); + Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS), false, true); Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check); Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); break; } case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: { - Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo); // No GetCharmer in searcher + Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo, false, true); // No GetCharmer in searcher Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check); Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); break; @@ -2396,13 +2396,13 @@ void DynObjAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* if (effect->TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY || effect->TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY) { - Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS)); + Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS), false, true); Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check); Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius); } else { - Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius); + Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, nullptr, false, true); Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check); Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius); } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 8ef877e6881..779b0d0495c 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1245,6 +1245,11 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge if (!effect) return; float radius = effect->CalcRadius(m_caster) * m_spellValue->RadiusMod; + + // if this is a proximity based aoe (Frost Nova, Psychic Scream, ...), include the caster's own combat reach + if (targetType.IsProximityBasedAoe()) + radius += GetCaster()->GetCombatReach(); + SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), effect->ImplicitTargetConditions); CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType); @@ -1300,7 +1305,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici float dist = frand(minDist, maxDist); float x, y, z; float angle = float(rand_norm()) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f); - m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dist, angle); + m_caster->GetClosePoint(x, y, z, DEFAULT_PLAYER_BOUNDING_RADIUS, dist, angle); float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseShift(), x, y, z, true, 50.0f); float liquidLevel = VMAP_INVALID_HEIGHT_VALUE; @@ -1333,7 +1338,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici { float dist = effect->CalcRadius(m_caster); float angle = targetType.CalcDirectionAngle(); - float objSize = m_caster->GetObjectSize(); + float objSize = m_caster->GetCombatReach(); switch (targetType.GetTarget()) { @@ -1391,7 +1396,7 @@ void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplici if (SpellEffectInfo const* effect = GetEffect(effIndex)) { float angle = targetType.CalcDirectionAngle(); - float objSize = target->GetObjectSize(); + float objSize = target->GetCombatReach(); float dist = effect->CalcRadius(m_caster); if (dist < objSize) dist = objSize; @@ -1615,7 +1620,7 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge } } - const float size = std::max((*itr)->GetObjectSize(), 1.0f); + const float size = std::max((*itr)->GetCombatReach(), 1.0f); const float objDist2d = srcPos.GetExactDist2d(*itr); const float dz = (*itr)->GetPositionZ() - srcPos.m_positionZ; @@ -5300,13 +5305,13 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint if (!target->IsWithinLOSInMap(m_caster)) //Do full LoS/Path check. Don't exclude m2 return SPELL_FAILED_LINE_OF_SIGHT; - float objSize = target->GetObjectSize(); + float objSize = target->GetCombatReach(); float range = m_spellInfo->GetMaxRange(true, m_caster, this) * 1.5f + objSize; // can't be overly strict m_preGeneratedPath = Trinity::make_unique<PathGenerator>(m_caster); m_preGeneratedPath->SetPathLengthLimit(range); // first try with raycast, if it fails fall back to normal path - float targetObjectSize = std::min(target->GetObjectSize(), 4.0f); + float targetObjectSize = std::min(target->GetCombatReach(), 4.0f); bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + targetObjectSize, false, true); if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT) return SPELL_FAILED_OUT_OF_RANGE; @@ -7895,8 +7900,20 @@ WorldObjectSpellAreaTargetCheck::WorldObjectSpellAreaTargetCheck(float range, Po bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target) { - if (!target->IsWithinDist3d(_position, _range) && !(target->ToGameObject() && target->ToGameObject()->IsInRange(_position->GetPositionX(), _position->GetPositionY(), _position->GetPositionZ(), _range))) - return false; + if (target->ToGameObject()) + { + // isInRange including the dimension of the GO + bool isInRange = target->ToGameObject()->IsInRange(_position->GetPositionX(), _position->GetPositionY(), _position->GetPositionZ(), _range); + if (!isInRange) + return false; + } + else + { + bool isInsideCylinder = target->IsWithinDist2d(_position, _range) && std::abs(target->GetPositionZ() - _position->GetPositionZ()) <= _range; + if (!isInsideCylinder) + return false; + } + return WorldObjectSpellTargetCheck::operator ()(target); } @@ -7913,7 +7930,7 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target) } else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE)) { - if (!_caster->HasInLine(target, target->GetObjectSize(), _caster->GetObjectSize())) + if (!_caster->HasInLine(target, target->GetCombatReach(), _caster->GetCombatReach())) return false; } else @@ -7933,7 +7950,7 @@ WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Po bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target) { // return all targets on missile trajectory (0 - size of a missile) - if (!_caster->HasInLine(target, target->GetObjectSize(), TRAJECTORY_MISSILE_SIZE)) + if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE)) return false; if (target->GetExactDist2d(_position) > _range) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 6acb790d8e8..56a050eea65 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2306,7 +2306,7 @@ void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex /*effIndex*/) float dis = effectInfo->CalcRadius(m_caster); float fx, fy, fz; - m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetObjectSize(), dis); + m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetCombatReach(), dis); unitTarget->NearTeleportTo(fx, fy, fz, -m_caster->GetOrientation(), unitTarget == m_caster); } @@ -2659,7 +2659,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex) //OldSummon->GetMap()->Remove(OldSummon->ToCreature(), false); float px, py, pz; - owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize()); + owner->GetClosePoint(px, py, pz, OldSummon->GetCombatReach()); OldSummon->NearTeleportTo(px, py, pz, OldSummon->GetOrientation()); //OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation()); @@ -2679,7 +2679,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex) } float x, y, z; - owner->GetClosePoint(x, y, z, owner->GetObjectSize()); + owner->GetClosePoint(x, y, z, owner->GetCombatReach()); Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0); if (!pet) return; @@ -2912,7 +2912,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; } - float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); + float weapon_total_pct = m_caster->GetPctModifierValue(unitMod, TOTAL_PCT); if (fixed_bonus) fixed_bonus = int32(fixed_bonus * weapon_total_pct); if (spell_bonus) @@ -3041,7 +3041,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (m_targets.HasDst()) destTarget->GetPosition(x, y, z); else - m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); + m_caster->GetClosePoint(x, y, z, DEFAULT_PLAYER_BOUNDING_RADIUS); Map* map = target->GetMap(); Position pos = Position(x, y, z, target->GetOrientation()); @@ -3922,7 +3922,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) destTarget->GetPosition(x, y, z); // Summon in random point all other units if location present else - m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); + m_caster->GetClosePoint(x, y, z, DEFAULT_PLAYER_BOUNDING_RADIUS); Map* map = m_caster->GetMap(); Position pos = Position(x, y, z, m_caster->GetOrientation()); @@ -4219,7 +4219,7 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/) if (m_preGeneratedPath->GetPathType() == PATHFIND_BLANK) { //unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ); - Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster)); + Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetCombatReach(), unitTarget->GetRelativeAngle(m_caster)); if (G3D::fuzzyGt(m_spellInfo->Speed, 0.0f) && m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION)) speed = pos.GetExactDist(m_caster) / speed; @@ -4493,7 +4493,7 @@ void Spell::EffectResurrectPet(SpellEffIndex /*effIndex*/) // Reposition the pet's corpse before reviving so as not to grab aggro // We can use a different, more accurate version of GetClosePoint() since we have a pet float x, y, z; // Will be used later to reposition the pet if we have one - player->GetClosePoint(x, y, z, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle()); + player->GetClosePoint(x, y, z, pet->GetCombatReach(), PET_FOLLOW_DIST, pet->GetFollowAngle()); pet->NearTeleportTo(x, y, z, player->GetOrientation()); pet->Relocate(x, y, z, player->GetOrientation()); // This is needed so SaveStayPosition() will get the proper coords. } @@ -4501,7 +4501,7 @@ void Spell::EffectResurrectPet(SpellEffIndex /*effIndex*/) pet->SetDynamicFlags(UNIT_DYNFLAG_NONE); pet->RemoveUnitFlag(UNIT_FLAG_SKINNABLE); pet->setDeathState(ALIVE); - pet->ClearUnitState(uint32(UNIT_STATE_ALL_STATE)); + pet->ClearUnitState(UNIT_STATE_ALL_ERASABLE); pet->SetHealth(pet->CountPctFromMaxHealth(damage)); // Reset things for when the AI to takes over @@ -4656,7 +4656,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) else if (effectInfo->HasRadius() && m_spellInfo->Speed == 0) { float dis = effectInfo->CalcRadius(m_originalCaster); - m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis); + m_caster->GetClosePoint(fx, fy, fz, DEFAULT_PLAYER_BOUNDING_RADIUS, dis); } else { @@ -4665,7 +4665,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) float max_dis = m_spellInfo->GetMaxRange(true); float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis; - m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis); + m_caster->GetClosePoint(fx, fy, fz, DEFAULT_PLAYER_BOUNDING_RADIUS, dis); } Map* cMap = m_caster->GetMap(); @@ -5076,7 +5076,7 @@ void Spell::EffectCreateTamedPet(SpellEffIndex /*effIndex*/) // relocate float px, py, pz; - unitTarget->GetClosePoint(px, py, pz, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle()); + unitTarget->GetClosePoint(px, py, pz, pet->GetCombatReach(), PET_FOLLOW_DIST, pet->GetFollowAngle()); pet->Relocate(px, py, pz, unitTarget->GetOrientation()); // add to world diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 3266343d8b3..12eb37b6861 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -75,6 +75,35 @@ bool SpellImplicitTargetInfo::IsArea() const return GetSelectionCategory() == TARGET_SELECT_CATEGORY_AREA || GetSelectionCategory() == TARGET_SELECT_CATEGORY_CONE; } +bool SpellImplicitTargetInfo::IsProximityBasedAoe() const +{ + switch (_target) + { + case TARGET_UNIT_SRC_AREA_ENTRY: + case TARGET_UNIT_SRC_AREA_ENEMY: + case TARGET_UNIT_CASTER_AREA_PARTY: + case TARGET_UNIT_SRC_AREA_ALLY: + case TARGET_UNIT_SRC_AREA_PARTY: + case TARGET_UNIT_LASTTARGET_AREA_PARTY: + case TARGET_GAMEOBJECT_SRC_AREA: + case TARGET_UNIT_CASTER_AREA_RAID: + case TARGET_CORPSE_SRC_AREA_ENEMY: + return true; + + case TARGET_UNIT_DEST_AREA_ENTRY: + case TARGET_UNIT_DEST_AREA_ENEMY: + case TARGET_UNIT_DEST_AREA_ALLY: + case TARGET_UNIT_DEST_AREA_PARTY: + case TARGET_GAMEOBJECT_DEST_AREA: + case TARGET_UNIT_TARGET_AREA_RAID_CLASS: + return false; + + default: + TC_LOG_WARN("spells", "SpellImplicitTargetInfo::IsProximityBasedAoe called a non-aoe spell"); + return false; + } +} + SpellTargetSelectionCategories SpellImplicitTargetInfo::GetSelectionCategory() const { return _data[_target].SelectionCategory; diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index d663c2359f0..e4b8709308b 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -286,6 +286,7 @@ public: SpellImplicitTargetInfo(uint32 target); bool IsArea() const; + bool IsProximityBasedAoe() const; SpellTargetSelectionCategories GetSelectionCategory() const; SpellTargetReferenceTypes GetReferenceType() const; SpellTargetObjectTypes GetObjectType() const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 5bb9d23c7db..3c15a374d1b 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -369,10 +369,14 @@ bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const { + ASSERT(spellInfo1); + ASSERT(spellInfo2); + uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id; uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id; if (spellid_1 == spellid_2) return SPELL_GROUP_STACK_RULE_DEFAULT; + // find SpellGroups which are common for both spells SpellSpellGroupMapBounds spellGroup1 = GetSpellSpellGroupMapBounds(spellid_1); std::set<SpellGroup> groups; @@ -3363,6 +3367,12 @@ void SpellMgr::LoadSpellInfoCorrections() const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd }); + // Val'kyr Target Search + ApplySpellFix({ 69030 }, [](SpellInfo* spellInfo) + { + spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY; + }); + // Raging Spirit Visual ApplySpellFix({ 69198 }, [](SpellInfo* spellInfo) { @@ -3408,14 +3418,16 @@ void SpellMgr::LoadSpellInfoCorrections() // Jump ApplySpellFix({ 71809 }, [](SpellInfo* spellInfo) { - spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(3); // 20yd - const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd + spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->MiscValue = 190; }); // Broken Frostmourne ApplySpellFix({ 72405 }, [](SpellInfo* spellInfo) { - const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS); // 20yd + spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT; }); // ENDOF ICECROWN CITADEL SPELLS @@ -3631,6 +3643,10 @@ void SpellMgr::LoadSpellInfoCorrections() if (spellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_SPELL_MAGNET)) spellInfo->ProcFlags = 0; + // due to the way spell system works, unit would change orientation in Spell::_cast + if (spellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_CONTROL_VEHICLE)) + spellInfo->AttributesEx5 |= SPELL_ATTR5_DONT_TURN_DURING_CAST; + if (spellInfo->ActiveIconFileDataId == 135754) // flight spellInfo->Attributes |= SPELL_ATTR0_PASSIVE; } diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 3cd797d5e00..11417b305a5 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -918,7 +918,7 @@ public: uint32 entry = atoul(e); float x, y, z, o = handler->GetSession()->GetPlayer()->GetOrientation(); - handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, handler->GetSession()->GetPlayer()->GetObjectSize()); + handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, handler->GetSession()->GetPlayer()->GetCombatReach()); if (!i) return handler->GetSession()->GetPlayer()->SummonCreature(entry, x, y, z, o) != nullptr; diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp index afe3b3c2645..f6866734a7c 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -143,7 +143,7 @@ public: // before GM float x, y, z; - gmPlayer->GetClosePoint(x, y, z, player->GetObjectSize()); + gmPlayer->GetClosePoint(x, y, z, player->GetCombatReach()); player->TeleportTo(gmPlayer->GetMapId(), x, y, z, player->GetOrientation()); } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 1067283431d..23dbd8e3d1a 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -591,7 +591,7 @@ public: // before GM float x, y, z; - handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, target->GetObjectSize()); + handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, target->GetCombatReach()); target->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, target->GetOrientation()); PhasingHandler::InheritPhaseShift(target, handler->GetSession()->GetPlayer()); target->UpdateObjectVisibility(); @@ -2201,9 +2201,6 @@ public: case WAYPOINT_MOTION_TYPE: handler->SendSysMessage(LANG_MOVEGENS_WAYPOINT); break; - case ANIMAL_RANDOM_MOTION_TYPE: - handler->SendSysMessage(LANG_MOVEGENS_ANIMAL_RANDOM); - break; case CONFUSED_MOTION_TYPE: handler->SendSysMessage(LANG_MOVEGENS_CONFUSED); break; diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index ac4d8abb366..7a2e6cff30e 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1457,7 +1457,7 @@ public: // place pet before player float x, y, z; - player->GetClosePoint (x, y, z, creatureTarget->GetObjectSize(), CONTACT_DISTANCE); + player->GetClosePoint (x, y, z, creatureTarget->GetCombatReach(), CONTACT_DISTANCE); pet->Relocate(x, y, z, float(M_PI) - player->GetOrientation()); // set pet to defensive mode by default (some classes can't control controlled pets in fact). diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp index 22efdea4071..c0ae774c5f1 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp @@ -126,7 +126,7 @@ class boss_selin_fireheart : public CreatureScript Crystals.remove(CrystalChosen); float x, y, z; - CrystalChosen->GetClosePoint(x, y, z, me->GetObjectSize(), CONTACT_DISTANCE); + CrystalChosen->GetClosePoint(x, y, z, me->GetCombatReach(), CONTACT_DISTANCE); events.SetPhase(PHASE_DRAIN); me->SetWalk(false); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp index d47bf3c7862..fea8c330b9c 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp @@ -101,7 +101,7 @@ public: FlyBackTimer = 500; break; case 1: - player->GetClosePoint(x, y, z, me->GetObjectSize()); + player->GetClosePoint(x, y, z, me->GetCombatReach()); z += 2.5f; x -= 2.0f; y -= 1.5f; diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.h b/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.h index 9f72ffe8183..c905702d3bc 100644 --- a/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.h +++ b/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.h @@ -20,17 +20,9 @@ #define DataHeader "ST" -#define TROLLBOSS1_DEATH 1 -#define TROLLBOSS2_DEATH 2 -#define TROLLBOSS3_DEATH 3 -#define TROLLBOSS4_DEATH 4 -#define TROLLBOSS5_DEATH 5 -#define TROLLBOSS6_DEATH 6 -#define JAMMALAN_DEATH 7 -#define MORPHAZ_DEATH 8 -#define HAZZAS_DEATH 9 -#define ERANIKUS_DEATH 10 -#define ATALALARION_DEATH 11 //optional +enum STEvents +{ + EVENT_STATE = 1 +}; -#define EVENT_STATE 1 #endif diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp index 58690c3a171..71784911f34 100644 --- a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp +++ b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp @@ -539,7 +539,7 @@ public: /// TODO: Remove this once we find a general rule for WorldObject::MovePosition (this spell shouldn't take the Z change into consideration) Unit* caster = GetCaster(); float angle = float(rand_norm()) * static_cast<float>(2 * M_PI); - uint32 dist = caster->GetObjectSize() + GetSpellInfo()->GetEffect(EFFECT_0)->CalcRadius(caster) * (float)rand_norm(); + uint32 dist = caster->GetCombatReach() + GetSpellInfo()->GetEffect(EFFECT_0)->CalcRadius(caster) * (float)rand_norm(); float x = caster->GetPositionX() + dist * std::cos(angle); float y = caster->GetPositionY() + dist * std::sin(angle); diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp index f00f96660a8..9112fd9ccd2 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp @@ -483,15 +483,6 @@ class npc_anubarak_anub_ar_assassin : public CreatureScript { npc_anubarak_anub_ar_assassinAI(Creature* creature) : npc_anubarak_pet_template(creature, false), _backstabTimer(6 * IN_MILLISECONDS) { } - bool IsInBounds(Position const& jumpTo, CreatureBoundary const* boundary) - { - if (!boundary) - return true; - for (AreaBoundary const* it : *boundary) - if (!it->IsWithinBoundary(&jumpTo)) - return false; - return true; - } Position GetRandomPositionAround(Creature* anubarak) { static float DISTANCE_MIN = 10.0f; @@ -508,7 +499,7 @@ class npc_anubarak_anub_ar_assassin : public CreatureScript Position jumpTo; do jumpTo = GetRandomPositionAround(anubarak); - while (!IsInBounds(jumpTo, boundary)); + while (!CreatureAI::IsInBounds(boundary, &jumpTo)); me->GetMotionMaster()->MoveJump(jumpTo, 40.0f, 40.0f); DoCastSelf(SPELL_ASSASSIN_VISUAL, true); } diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_king_dred.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_king_dred.cpp index 1df68607625..ff4343f31fd 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_king_dred.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_king_dred.cpp @@ -146,7 +146,7 @@ class boss_king_dred : public CreatureScript float x, y, z; - me->GetClosePoint(x, y, z, me->GetObjectSize() / 3, 10.0f); + me->GetClosePoint(x, y, z, me->GetCombatReach() / 3, 10.0f); me->SummonCreature(RAND(NPC_DRAKKARI_GUTRIPPER, NPC_DRAKKARI_SCYTHECLAW), x, y, z, 0, TEMPSUMMON_DEAD_DESPAWN, 1000); events.ScheduleEvent(EVENT_RAPTOR_CALL, urand(20000, 25000)); break; diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp index c67179d67eb..c78424c0078 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp @@ -131,7 +131,7 @@ class boss_bronjahm : public CreatureScript { summons.Summon(summon); summon->SetReactState(REACT_PASSIVE); - summon->GetMotionMaster()->MoveFollow(me, me->GetObjectSize(), 0.0f); + summon->GetMotionMaster()->MoveFollow(me, me->GetCombatReach(), 0.0f); summon->CastSpell(summon, SPELL_PURPLE_BANISH_VISUAL, true); } } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 98ee4e6194e..80ab44fe32a 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -790,7 +790,7 @@ class npc_high_overlord_saurfang_icc : public CreatureScript if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) { float x, y, z; - deathbringer->GetClosePoint(x, y, z, deathbringer->GetObjectSize()); + deathbringer->GetClosePoint(x, y, z, deathbringer->GetCombatReach()); me->SetWalk(true); me->GetMotionMaster()->MovePoint(POINT_CORPSE, x, y, z); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 99060220471..1ab35165e5a 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -387,7 +387,7 @@ class npc_coldflame : public CreatureScript { float ang = Position::NormalizeOrientation(pos.GetAngle(me)); me->SetOrientation(ang); - owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 5.0f - owner->GetObjectSize(), ang); + owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 5.0f - owner->GetCombatReach(), ang); } else { @@ -400,7 +400,7 @@ class npc_coldflame : public CreatureScript float ang = Position::NormalizeOrientation(pos.GetAngle(target)); me->SetOrientation(ang); - owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 15.0f - owner->GetObjectSize(), ang); + owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 15.0f - owner->GetCombatReach(), ang); } me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), me->GetPositionZ(), me->GetOrientation()); @@ -518,7 +518,7 @@ class spell_marrowgar_coldflame : public SpellScriptLoader { targets.clear(); // select any unit but not the tank (by owners threatlist) - Unit* target = GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 1, -GetCaster()->GetObjectSize(), true, -SPELL_IMPALED); + Unit* target = GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 1, -GetCaster()->GetCombatReach(), true, -SPELL_IMPALED); if (!target) target = GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true); // or the tank if its solo if (!target) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index e525c2efa45..94bf769b771 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -197,77 +197,80 @@ enum Events { // The Lich King // intro events - EVENT_INTRO_MOVE_1 = 1, - EVENT_INTRO_MOVE_2 = 2, - EVENT_INTRO_MOVE_3 = 3, - EVENT_INTRO_TALK_1 = 4, - EVENT_EMOTE_CAST_SHOUT = 5, - EVENT_INTRO_EMOTE_1 = 6, - EVENT_INTRO_CHARGE = 7, - EVENT_INTRO_CAST_FREEZE = 8, - EVENT_FINISH_INTRO = 9, + EVENT_INTRO_MOVE_1 = 1, + EVENT_INTRO_MOVE_2, + EVENT_INTRO_MOVE_3, + EVENT_INTRO_TALK_1, + EVENT_EMOTE_CAST_SHOUT, + EVENT_INTRO_EMOTE_1, + EVENT_INTRO_CHARGE, + EVENT_INTRO_CAST_FREEZE, + EVENT_FINISH_INTRO, // combat events - EVENT_SUMMON_SHAMBLING_HORROR = 10, - EVENT_SUMMON_DRUDGE_GHOUL = 11, - EVENT_INFEST = 12, - EVENT_NECROTIC_PLAGUE = 13, - EVENT_SHADOW_TRAP = 14, // heroic only - EVENT_SOUL_REAPER = 15, - EVENT_DEFILE = 16, - EVENT_HARVEST_SOUL = 17, // normal mode only - EVENT_PAIN_AND_SUFFERING = 18, - EVENT_SUMMON_ICE_SPHERE = 19, - EVENT_SUMMON_RAGING_SPIRIT = 20, - EVENT_QUAKE = 21, - EVENT_SUMMON_VALKYR = 22, - EVENT_GRAB_PLAYER = 23, - EVENT_MOVE_TO_DROP_POS = 24, - EVENT_LIFE_SIPHON = 25, // heroic only - EVENT_START_ATTACK = 26, - EVENT_QUAKE_2 = 27, - EVENT_VILE_SPIRITS = 28, - EVENT_HARVEST_SOULS = 29, // heroic only - EVENT_BERSERK = 30, - EVENT_SOUL_RIP = 31, - EVENT_DESTROY_SOUL = 32, - EVENT_FROSTMOURNE_TALK_1 = 33, - EVENT_FROSTMOURNE_TALK_2 = 34, - EVENT_FROSTMOURNE_TALK_3 = 35, - EVENT_TELEPORT_BACK = 36, - EVENT_FROSTMOURNE_HEROIC = 37, - EVENT_OUTRO_TALK_1 = 38, - EVENT_OUTRO_TALK_2 = 39, - EVENT_OUTRO_EMOTE_TALK = 40, - EVENT_OUTRO_TALK_3 = 41, - EVENT_OUTRO_MOVE_CENTER = 42, - EVENT_OUTRO_TALK_4 = 43, - EVENT_OUTRO_RAISE_DEAD = 44, - EVENT_OUTRO_TALK_5 = 45, - EVENT_OUTRO_BLESS = 46, - EVENT_OUTRO_REMOVE_ICE = 47, - EVENT_OUTRO_MOVE_1 = 48, - EVENT_OUTRO_JUMP = 49, - EVENT_OUTRO_TALK_6 = 50, - EVENT_OUTRO_KNOCK_BACK = 51, - EVENT_OUTRO_SOUL_BARRAGE = 52, - EVENT_OUTRO_SUMMON_TERENAS = 53, - EVENT_OUTRO_TERENAS_TALK_1 = 54, - EVENT_OUTRO_TERENAS_TALK_2 = 55, - EVENT_OUTRO_TALK_7 = 56, - EVENT_OUTRO_TALK_8 = 57, + EVENT_SUMMON_SHAMBLING_HORROR, + EVENT_SUMMON_DRUDGE_GHOUL, + EVENT_INFEST, + EVENT_NECROTIC_PLAGUE, + EVENT_SHADOW_TRAP, // heroic only + EVENT_SOUL_REAPER, + EVENT_DEFILE, + EVENT_HARVEST_SOUL, // normal mode only + EVENT_PAIN_AND_SUFFERING, + EVENT_SUMMON_ICE_SPHERE, + EVENT_SUMMON_RAGING_SPIRIT, + EVENT_QUAKE, + EVENT_SUMMON_VALKYR, + EVENT_GRAB_PLAYER, + EVENT_MOVE_TO_DROP_POS, + EVENT_LIFE_SIPHON, // heroic only + EVENT_MOVE_TO_CENTER, // heroic only + EVENT_START_ATTACK, + EVENT_SUMMON_RAGING_SPIRIT_2, + EVENT_QUAKE_2, + EVENT_VILE_SPIRITS, + EVENT_HARVEST_SOULS, // heroic only + EVENT_BERSERK, + EVENT_SOUL_RIP, + EVENT_DESTROY_SOUL, + EVENT_FROSTMOURNE_TALK_1, + EVENT_FROSTMOURNE_TALK_2, + EVENT_FROSTMOURNE_TALK_3, + EVENT_TELEPORT_BACK, + EVENT_FROSTMOURNE_HEROIC, + EVENT_OUTRO_TALK_1, + EVENT_OUTRO_TALK_2, + EVENT_OUTRO_EMOTE_TALK, + EVENT_OUTRO_TALK_3, + EVENT_OUTRO_MOVE_CENTER, + EVENT_OUTRO_TALK_4, + EVENT_OUTRO_RAISE_DEAD, + EVENT_OUTRO_TALK_5, + EVENT_OUTRO_BLESS, + EVENT_OUTRO_REMOVE_ICE, + EVENT_OUTRO_MOVE_1, + EVENT_OUTRO_JUMP, + EVENT_OUTRO_TALK_6, + EVENT_OUTRO_KNOCK_BACK, + EVENT_OUTRO_SOUL_BARRAGE, + EVENT_OUTRO_SUMMON_TERENAS, + EVENT_OUTRO_TERENAS_TALK_1, + EVENT_OUTRO_TERENAS_TALK_2, + EVENT_OUTRO_TALK_7, + EVENT_OUTRO_TALK_8, // Shambling Horror - EVENT_SHOCKWAVE = 58, - EVENT_ENRAGE = 59, + EVENT_SHOCKWAVE, + EVENT_ENRAGE, // Raging Spirit - EVENT_SOUL_SHRIEK = 60, + EVENT_SOUL_SHRIEK, + EVENT_SET_AGRESSIVE, // Strangulate Vehicle (Harvest Soul) - EVENT_TELEPORT = 61, - EVENT_MOVE_TO_LICH_KING = 62, - EVENT_DESPAWN_SELF = 63, + EVENT_TELEPORT, + EVENT_MOVE_TO_LICH_KING, + EVENT_DESPAWN_SELF, }; enum EventGroups @@ -320,6 +323,7 @@ enum MovePoints POINT_OUTRO_JUMP = 11, POINT_LK_OUTRO_2 = 12, POINT_GROUND = 13, + POINT_SIPHON = 14, POINT_CHARGE = 1003, // globally used number for charge spell effects }; @@ -334,12 +338,14 @@ enum EncounterActions ACTION_SUMMON_TERENAS = 6, ACTION_FINISH_OUTRO = 7, ACTION_TELEPORT_BACK = 8, + ACTION_DISABLE_RAGING = 9 }; enum MiscData { LIGHT_SNOWSTORM = 2490, LIGHT_SOULSTORM = 2508, + LIGHT_FOG = 2509, MUSIC_FROZEN_THRONE = 17457, MUSIC_SPECIAL = 17458, // Summon Shambling Horror, Remorseless Winter, Quake, Summon Val'kyr Periodic, Harvest Soul, Vile Spirits @@ -499,17 +505,7 @@ class boss_the_lich_king : public CreatureScript _vileSpiritExplosions = 0; } - void InitializeAI() override - { - SetupEncounter(); - } - - void JustRespawned() override - { - SetupEncounter(); - } - - void SetupEncounter() + void Reset() override { _Reset(); me->AddUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); @@ -524,9 +520,10 @@ class boss_the_lich_king : public CreatureScript Cell::VisitGridObjects(me, worker, 333.0f); // Reset any light override - me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, 0, 5000); + me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, 0, 5000); - me->SummonCreature(NPC_HIGHLORD_TIRION_FORDRING_LK, TirionSpawn, TEMPSUMMON_MANUAL_DESPAWN); + if (!ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) + me->SummonCreature(NPC_HIGHLORD_TIRION_FORDRING_LK, TirionSpawn, TEMPSUMMON_MANUAL_DESPAWN); } void JustDied(Unit* /*killer*/) override @@ -538,6 +535,8 @@ class boss_the_lich_king : public CreatureScript me->GetMotionMaster()->MoveFall(); if (Creature* frostmourne = me->FindNearestCreature(NPC_FROSTMOURNE_TRIGGER, 50.0f)) frostmourne->DespawnOrUnsummon(); + me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_FOG, 5000); + me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_FOG, 0.0f); } void EnterCombat(Unit* target) override @@ -550,6 +549,7 @@ class boss_the_lich_king : public CreatureScript } me->setActive(true); + me->SetCombatPulseDelay(5); DoZoneInCombat(); events.SetPhase(PHASE_ONE); @@ -592,7 +592,7 @@ class boss_the_lich_king : public CreatureScript case ACTION_START_ENCOUNTER: instance->SetBossState(DATA_THE_LICH_KING, IN_PROGRESS); Talk(SAY_LK_INTRO_1); - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_FROZEN_THRONE); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FROZEN_THRONE); // schedule talks me->SetStandState(UNIT_STAND_STATE_STAND); events.ScheduleEvent(EVENT_INTRO_MOVE_1, 4000); @@ -601,10 +601,10 @@ class boss_the_lich_king : public CreatureScript events.ScheduleEvent(EVENT_START_ATTACK, 5000); break; case ACTION_PLAY_MUSIC: - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_FINAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FINAL); break; case ACTION_RESTORE_LIGHT: - me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, 0, 5000); + me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, 0, 5000); break; case ACTION_BREAK_FROSTMOURNE: me->CastSpell((Unit*)NULL, SPELL_SUMMON_BROKEN_FROSTMOURNE, TRIGGERED_IGNORE_CAST_IN_PROGRESS); @@ -666,6 +666,7 @@ class boss_the_lich_king : public CreatureScript events.SetPhase(PHASE_TRANSITION); me->SetReactState(REACT_PASSIVE); me->AttackStop(); + me->InterruptNonMeleeSpells(true); me->GetMotionMaster()->MovePoint(POINT_CENTER_1, CenterPosition); return; } @@ -675,6 +676,7 @@ class boss_the_lich_king : public CreatureScript events.SetPhase(PHASE_TRANSITION); me->SetReactState(REACT_PASSIVE); me->AttackStop(); + me->InterruptNonMeleeSpells(true); me->GetMotionMaster()->MovePoint(POINT_CENTER_2, CenterPosition); return; } @@ -686,7 +688,7 @@ class boss_the_lich_king : public CreatureScript events.Reset(); events.SetPhase(PHASE_OUTRO); summons.DespawnAll(); - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_FURY_OF_FROSTMOURNE); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FURY_OF_FROSTMOURNE); me->InterruptNonMeleeSpells(true); me->CastSpell((Unit*)NULL, SPELL_FURY_OF_FROSTMOURNE, TRIGGERED_NONE); me->SetWalk(true); @@ -738,8 +740,8 @@ class boss_the_lich_king : public CreatureScript { summon->CastSpell((Unit*)NULL, SPELL_BROKEN_FROSTMOURNE, true); - me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, LIGHT_SOULSTORM, 10000); - me->GetMap()->SetZoneWeather(AREA_THE_FROZEN_THRONE, WEATHER_STATE_BLACKSNOW, 0.5f); + me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_SOULSTORM, 10000); + me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_BLACKSNOW, 0.5f); events.ScheduleEvent(EVENT_OUTRO_SOUL_BARRAGE, 5000, 0, PHASE_OUTRO); return; @@ -793,8 +795,8 @@ class boss_the_lich_king : public CreatureScript { if (spell->Id == REMORSELESS_WINTER_1 || spell->Id == REMORSELESS_WINTER_2) { - me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, LIGHT_SNOWSTORM, 5000); - me->GetMap()->SetZoneWeather(AREA_THE_FROZEN_THRONE, WEATHER_STATE_LIGHT_SNOW, 0.5f); + me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_SNOWSTORM, 5000); + me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_LIGHT_SNOW, 0.5f); } } @@ -820,13 +822,14 @@ class boss_the_lich_king : public CreatureScript case POINT_CENTER_1: me->SetFacingTo(0.0f, true); Talk(SAY_LK_REMORSELESS_WINTER); - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); DoCast(me, SPELL_REMORSELESS_WINTER_1); + summons.DespawnEntry(NPC_SHADOW_TRAP); events.DelayEvents(62500, EVENT_GROUP_BERSERK); // delay berserk timer, its not ticking during phase transitions events.ScheduleEvent(EVENT_QUAKE, 62500, 0, PHASE_TRANSITION); events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 4000, 0, PHASE_TRANSITION); events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8000, 0, PHASE_TRANSITION); - events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 3000, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 6000, 0, PHASE_TRANSITION); events.ScheduleEvent(EVENT_SUMMON_VALKYR, 78000, 0, PHASE_TWO); events.ScheduleEvent(EVENT_INFEST, 70000, 0, PHASE_TWO); events.ScheduleEvent(EVENT_DEFILE, 97000, 0, PHASE_TWO); @@ -835,14 +838,14 @@ class boss_the_lich_king : public CreatureScript case POINT_CENTER_2: me->SetFacingTo(0.0f, true); Talk(SAY_LK_REMORSELESS_WINTER); - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); DoCast(me, SPELL_REMORSELESS_WINTER_2); summons.DespawnEntry(NPC_VALKYR_SHADOWGUARD); events.DelayEvents(62500, EVENT_GROUP_BERSERK); // delay berserk timer, its not ticking during phase transitions events.ScheduleEvent(EVENT_QUAKE_2, 62500, 0, PHASE_TRANSITION); events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 6000, 0, PHASE_TRANSITION); events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8000, 0, PHASE_TRANSITION); - events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 5000, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT_2, 5000, 0, PHASE_TRANSITION); events.ScheduleEvent(EVENT_DEFILE, 95500, 0, PHASE_THREE); events.ScheduleEvent(EVENT_SOUL_REAPER, 99500, 0, PHASE_THREE); events.ScheduleEvent(EVENT_VILE_SPIRITS, 79500, EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); @@ -921,7 +924,7 @@ class boss_the_lich_king : public CreatureScript break; case EVENT_SUMMON_SHAMBLING_HORROR: DoCast(me, SPELL_SUMMON_SHAMBLING_HORROR); - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 60000, 0, PHASE_ONE); break; case EVENT_SUMMON_DRUDGE_GHOUL: @@ -977,24 +980,29 @@ class boss_the_lich_king : public CreatureScript me->CastSpell(target, SPELL_RAGING_SPIRIT, TRIGGERED_NONE); events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, urand(22000, 23000), 0, PHASE_TRANSITION); break; + case EVENT_SUMMON_RAGING_SPIRIT_2: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + me->CastSpell(target, SPELL_RAGING_SPIRIT, TRIGGERED_NONE); + events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 18000, 0, PHASE_TRANSITION); + break; case EVENT_QUAKE: events.SetPhase(PHASE_TWO); me->ClearUnitState(UNIT_STATE_CASTING); // clear state to ensure check in DoCastAOE passes DoCastAOE(SPELL_QUAKE); - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); Talk(SAY_LK_QUAKE); break; case EVENT_QUAKE_2: events.SetPhase(PHASE_THREE); me->ClearUnitState(UNIT_STATE_CASTING); // clear state to ensure check in DoCastAOE passes DoCastAOE(SPELL_QUAKE); - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); Talk(SAY_LK_QUAKE); break; case EVENT_SUMMON_VALKYR: - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); Talk(SAY_LK_SUMMON_VALKYR); - DoCastAOE(SUMMON_VALKYR); + DoCastAOE(SUMMON_VALKYR, true); events.ScheduleEvent(EVENT_SUMMON_VALKYR, urand(45000, 50000), 0, PHASE_TWO); break; case EVENT_START_ATTACK: @@ -1003,7 +1011,7 @@ class boss_the_lich_king : public CreatureScript events.SetPhase(PHASE_THREE); break; case EVENT_VILE_SPIRITS: - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); DoCastAOE(SPELL_VILE_SPIRITS); events.ScheduleEvent(EVENT_VILE_SPIRITS, urand(35000, 40000), EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); break; @@ -1019,6 +1027,25 @@ class boss_the_lich_king : public CreatureScript events.RescheduleEvent(EVENT_SOUL_REAPER, urand(57000, 62000), 0, PHASE_THREE); events.ScheduleEvent(EVENT_START_ATTACK, 49000); events.ScheduleEvent(EVENT_FROSTMOURNE_HEROIC, 6500); + for (ObjectGuid guid : summons) + { + if (Creature* summon = ObjectAccessor::GetCreature(*me, guid)) + { + if (summon->GetEntry() == NPC_VILE_SPIRIT) + { + summon->m_Events.KillAllEvents(true); + summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(56500)); + summon->SetReactState(REACT_PASSIVE); + summon->CombatStop(true); + summon->RemoveAurasDueToSpell(SPELL_VILE_SPIRIT_MOVE_SEARCH); + summon->RemoveAurasDueToSpell(SPELL_VILE_SPIRIT_DAMAGE_SEARCH); + summon->GetMotionMaster()->MoveTargetedHome(); + summon->GetMotionMaster()->MoveRandom(10.0f); + } + else if (summon->GetEntry() == NPC_RAGING_SPIRIT) + summon->AI()->DoAction(ACTION_DISABLE_RAGING); + } + } break; case EVENT_FROSTMOURNE_HEROIC: if (TempSummon* terenas = me->GetMap()->SummonCreature(NPC_TERENAS_MENETHIL_FROSTMOURNE_H, TerenasSpawnHeroic, NULL, 50000)) @@ -1034,18 +1061,6 @@ class boss_the_lich_king : public CreatureScript spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_2, true); // summons bombs on players spawner->m_Events.AddEvent(new TriggerWickedSpirit(spawner), spawner->m_Events.CalculateTime(3000)); } - - for (SummonList::iterator i = summons.begin(); i != summons.end(); ++i) - { - Creature* summon = ObjectAccessor::GetCreature(*me, *i); - if (summon && summon->GetEntry() == NPC_VILE_SPIRIT) - { - summon->m_Events.KillAllEvents(true); - summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(50000)); - summon->GetMotionMaster()->MoveRandom(10.0f); - summon->SetReactState(REACT_PASSIVE); - } - } } break; case EVENT_OUTRO_TALK_1: @@ -1074,7 +1089,7 @@ class boss_the_lich_king : public CreatureScript case EVENT_OUTRO_RAISE_DEAD: DoCastAOE(SPELL_RAISE_DEAD); me->ClearUnitState(UNIT_STATE_CASTING); - me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_FINAL); + me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FINAL); break; case EVENT_OUTRO_TALK_5: Talk(SAY_LK_OUTRO_5); @@ -1189,7 +1204,7 @@ class npc_tirion_fordring_tft : public CreatureScript if (spell->Id == SPELL_ICE_LOCK) me->SetFacingTo(3.085098f); else if (spell->Id == SPELL_BROKEN_FROSTMOURNE_KNOCK) - SetEquipmentSlots(true); // remove glow on ashbringer + me->LoadEquipment(1); // remove glow on ashbringer } void sGossipSelect(Player* /*player*/, uint32 menuId, uint32 gossipListId) override @@ -1357,7 +1372,9 @@ class npc_raging_spirit : public CreatureScript void Reset() override { + me->SetReactState(REACT_PASSIVE); _events.Reset(); + _events.ScheduleEvent(EVENT_SET_AGRESSIVE, 2000); _events.ScheduleEvent(EVENT_SOUL_SHRIEK, urand(12000, 15000)); DoCast(me, SPELL_PLAGUE_AVOIDANCE, true); DoCast(me, SPELL_RAGING_SPIRIT_VISUAL, true); @@ -1367,6 +1384,19 @@ class npc_raging_spirit : public CreatureScript DoCast(me, SPELL_BOSS_HITTIN_YA, true); } + void DoAction(int32 action) override + { + if (action == ACTION_DISABLE_RAGING) + { + _events.Reset(); + _events.SetPhase(PHASE_FROSTMOURNE); + _events.ScheduleEvent(EVENT_SET_AGRESSIVE, 52000); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->InterruptNonMeleeSpells(true); + } + } + void IsSummonedBy(Unit* /*summoner*/) override { // player is the spellcaster so register summon manually @@ -1384,7 +1414,7 @@ class npc_raging_spirit : public CreatureScript void UpdateAI(uint32 diff) override { - if (!UpdateVictim()) + if (!_events.IsInPhase(PHASE_FROSTMOURNE) && !UpdateVictim()) return; _events.Update(diff); @@ -1400,6 +1430,14 @@ class npc_raging_spirit : public CreatureScript DoCastAOE(SPELL_SOUL_SHRIEK); _events.ScheduleEvent(EVENT_SOUL_SHRIEK, urand(12000, 15000)); break; + case EVENT_SET_AGRESSIVE: + me->SetReactState(REACT_AGGRESSIVE); + if (_events.IsInPhase(PHASE_FROSTMOURNE)) + { + _events.SetPhase(PHASE_THREE); + _events.ScheduleEvent(EVENT_SOUL_SHRIEK, urand(12000, 15000)); + } + break; default: break; } @@ -1454,19 +1492,18 @@ class npc_valkyr_shadowguard : public CreatureScript if (me->HealthBelowPctDamaged(50, damage)) { - _events.Reset(); DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); - me->GetMotionMaster()->MoveTargetedHome(); - me->ClearUnitState(UNIT_STATE_EVADE); + ScheduleHeroicEvents(); } } - void JustReachedHome() override + void ScheduleHeroicEvents() { - // schedule siphon life event (heroic only) DoZoneInCombat(); _events.Reset(); + _events.ScheduleEvent(EVENT_MOVE_TO_CENTER, 1); _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2000); + me->ClearUnitState(UNIT_STATE_EVADE); } void AttackStart(Unit* /*target*/) override @@ -1482,7 +1519,10 @@ class npc_valkyr_shadowguard : public CreatureScript { case POINT_DROP_PLAYER: DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); - me->DespawnOrUnsummon(1000); + if (IsHeroic()) + ScheduleHeroicEvents(); + else + me->DespawnOrUnsummon(1000); break; case POINT_CHARGE: if (Player* target = ObjectAccessor::GetPlayer(*me, _grabbedPlayer)) @@ -1545,6 +1585,13 @@ class npc_valkyr_shadowguard : public CreatureScript DoCast(target, SPELL_LIFE_SIPHON); _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2500); break; + case EVENT_MOVE_TO_CENTER: + { + Position pos = me->GetRandomPoint(CenterPosition, 4.0f); + pos.m_positionZ = me->GetHomePosition().m_positionZ; + me->GetMotionMaster()->MovePoint(POINT_SIPHON, pos); + break; + } default: break; } @@ -1607,6 +1654,7 @@ class npc_strangulate_vehicle : public CreatureScript if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) lichKing->AI()->SummonedCreatureDespawn(me); + me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override @@ -2099,7 +2147,7 @@ class spell_the_lich_king_necrotic_plague_jump : public SpellScriptLoader } private: - void SelectTarget(std::list<Unit*>& targets) + void SelectTarget(std::list<WorldObject*>& targets) { targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster())); if (targets.size() < 2) @@ -2125,6 +2173,7 @@ class spell_the_lich_king_necrotic_plague_jump : public SpellScriptLoader void Register() override { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_necrotic_plague_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); BeforeHit += BeforeSpellHitFn(spell_the_lich_king_necrotic_plague_SpellScript::CheckAura); OnHit += SpellHitFn(spell_the_lich_king_necrotic_plague_SpellScript::AddMissingStack); } @@ -2357,12 +2406,6 @@ class spell_the_lich_king_raging_spirit : public SpellScriptLoader { PrepareSpellScript(spell_the_lich_king_raging_spirit_SpellScript); - bool Validate(SpellInfo const* spell) override - { - SpellEffectInfo const* effect0 = spell->GetEffect(EFFECT_0); - return effect0 && ValidateSpellInfo({ uint32(effect0->CalcValue()) }); - } - void HandleScript(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); @@ -3134,6 +3177,34 @@ class spell_the_lich_king_jump_remove_aura : public SpellScriptLoader } }; +class spell_the_lich_king_harvest_souls_teleport : public SpellScriptLoader +{ +public: + spell_the_lich_king_harvest_souls_teleport() : SpellScriptLoader("spell_the_lich_king_harvest_souls_teleport") { } + + class spell_the_lich_king_harvest_souls_teleport_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_harvest_souls_teleport_SpellScript); + + void RelocateTransportOffset(SpellEffIndex /*effIndex*/) + { + float randCoordX = frand(-18.0f, 18.0f); + float randCoordY = frand(-18.0f, 18.0f); + GetHitDest()->RelocateOffset({ randCoordX, randCoordY, 0.0f, 0.0f }); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_harvest_souls_teleport_SpellScript::RelocateTransportOffset, EFFECT_1, SPELL_EFFECT_TELEPORT_UNITS); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_the_lich_king_harvest_souls_teleport_SpellScript(); + } +}; + class achievement_been_waiting_long_time : public AchievementCriteriaScript { public: @@ -3203,6 +3274,7 @@ void AddSC_boss_the_lich_king() new spell_the_lich_king_jump(); new spell_the_lich_king_jump_remove_aura(); new spell_trigger_spell_from_caster("spell_the_lich_king_mass_resurrection", SPELL_MASS_RESURRECTION_REAL); + new spell_the_lich_king_harvest_souls_teleport(); new achievement_been_waiting_long_time(); new achievement_neck_deep_in_vile(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 1f9d88ea885..8fff8922983 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -321,6 +321,7 @@ enum ICCreaturesIds NPC_WORLD_TRIGGER_INFINITE_AOI = 36171, NPC_SPIRIT_BOMB = 39189, NPC_FROSTMOURNE_TRIGGER = 38584, + NPC_SHADOW_TRAP = 39137, // Generic NPC_INVISIBLE_STALKER = 30298 @@ -524,8 +525,7 @@ enum ICWorldStatesICC enum ICAreaIds { - AREA_ICECROWN_CITADEL = 4812, - AREA_THE_FROZEN_THRONE = 4859 + AREA_ICECROWN_CITADEL = 4812 }; class spell_trigger_spell_from_caster : public SpellScriptLoader diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 1d0ef4ccea0..d70f0d07c54 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -881,26 +881,20 @@ public: { PrepareAuraScript(spell_kelthuzad_chains_AuraScript); - void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes mode) { - Unit* target = GetTarget(); - float scale = target->GetObjectScale(); - ApplyPercentModFloatVar(scale, 200.0f, true); - target->SetObjectScale(scale); + aurEff->HandleAuraModScale(GetTargetApplication(), mode, true); } - void HandleRemove(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes mode) { - Unit* target = GetTarget(); - float scale = target->GetObjectScale(); - ApplyPercentModFloatVar(scale, 200.0f, false); - target->SetObjectScale(scale); + aurEff->HandleAuraModScale(GetTargetApplication(), mode, false); } void Register() override { - AfterEffectApply += AuraEffectApplyFn(spell_kelthuzad_chains_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectApplyFn(spell_kelthuzad_chains_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); + AfterEffectApply += AuraEffectApplyFn(spell_kelthuzad_chains_AuraScript::HandleApply, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectApplyFn(spell_kelthuzad_chains_AuraScript::HandleRemove, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, AURA_EFFECT_HANDLE_REAL); } }; diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index b61e42974ac..1569697c81c 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -43,7 +43,7 @@ BossBoundaryData const boundaries = /* Military Quarter */ { BOSS_RAZUVIOUS, new ZRangeBoundary(260.0f, 287.0f) }, // will not chase onto the upper floor { BOSS_GOTHIK, new RectangleBoundary(2627.0f, 2764.0f, -3440.0f, -3275.0f) }, - { BOSS_HORSEMEN, new ParallelogramBoundary(AreaBoundary::DoublePosition(2646.0, -2959.0), AreaBoundary::DoublePosition(2529.0, -3075.0), AreaBoundary::DoublePosition(2506.0, -2854.0)) }, + { BOSS_HORSEMEN, new ParallelogramBoundary(Position(2646.0f, -2959.0f), Position(2529.0f, -3075.0f), Position(2506.0f, -2854.0f)) }, /* Construct Quarter */ { BOSS_PATCHWERK, new CircleBoundary(Position(3204.0f, -3241.4f), 240.0f) }, @@ -51,9 +51,9 @@ BossBoundaryData const boundaries = { BOSS_GROBBULUS, new CircleBoundary(Position(3204.0f, -3241.4f), 240.0f) }, { BOSS_GROBBULUS, new RectangleBoundary(3295.0f, 3340.0f, -3254.2f, -3230.18f, true) }, // entrance door blocker { BOSS_GLUTH, new CircleBoundary(Position(3293.0f, -3142.0f), 80.0) }, - { BOSS_GLUTH, new ParallelogramBoundary(AreaBoundary::DoublePosition(3401.0, -3149.0), AreaBoundary::DoublePosition(3261.0, -3028.0), AreaBoundary::DoublePosition(3320.0, -3267.0)) }, + { BOSS_GLUTH, new ParallelogramBoundary(Position(3401.0f, -3149.0f), Position(3261.0f, -3028.0f), Position(3320.0f, -3267.0f)) }, { BOSS_GLUTH, new ZRangeBoundary(285.0f, 310.0f) }, - { BOSS_THADDIUS, new ParallelogramBoundary(AreaBoundary::DoublePosition(3478.3, -3070.0), AreaBoundary::DoublePosition(3370.0, -2961.5), AreaBoundary::DoublePosition(3580.0, -2961.5)) }, + { BOSS_THADDIUS, new ParallelogramBoundary(Position(3478.3f, -3070.0f), Position(3370.0f, -2961.5f), Position(3580.0f, -2961.5f)) }, /* Frostwyrm Lair */ { BOSS_SAPPHIRON, new CircleBoundary(Position(3517.627f, -5255.5f), 110.0) }, diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h index b066eb59bea..4c3faf67b5a 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h @@ -23,7 +23,7 @@ #define EoEScriptName "instance_eye_of_eternity" #define DataHeader "EOE" -enum InstanceData +enum EOEInstanceData { DATA_MALYGOS_EVENT, MAX_ENCOUNTER, @@ -33,7 +33,7 @@ enum InstanceData DATA_RESPAWN_IRIS }; -enum InstanceData64 +enum EOEInstanceData64 { DATA_TRIGGER, DATA_MALYGOS, @@ -44,7 +44,7 @@ enum InstanceData64 DATA_GIFT_BOX_BUNNY_GUID }; -enum InstanceNpcs +enum EOEInstanceNpcs { NPC_MALYGOS = 28859, NPC_VORTEX_TRIGGER = 30090, @@ -60,7 +60,7 @@ enum InstanceNpcs NPC_SURGE_OF_POWER = 30334 }; -enum InstanceGameObjects +enum EOEInstanceGameObjects { GO_NEXUS_RAID_PLATFORM = 193070, GO_EXIT_PORTAL = 193908, @@ -72,12 +72,12 @@ enum InstanceGameObjects GO_HEART_OF_MAGIC_25 = 194159 }; -enum InstanceEvents +enum EOEInstanceEvents { EVENT_FOCUSING_IRIS = 20711 }; -enum InstanceSpells +enum EOEInstanceSpells { SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 818485e4440..4e5019618ec 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -410,7 +410,7 @@ class boss_algalon_the_observer : public CreatureScript { _firstPull = false; Talk(SAY_ALGALON_START_TIMER); - if (Creature* brann = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_BRANN_BRONZEBEARD_ALG))) + if (Creature* brann = instance->GetCreature(DATA_BRANN_BRONZEBEARD_ALG)) brann->AI()->DoAction(ACTION_FINISH_INTRO); me->setActive(true); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp index b8f23964df6..fe01a917cd6 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp @@ -393,8 +393,8 @@ class npc_sanctum_sentry : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Auriaya = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_AURIAYA))) - Auriaya->AI()->DoAction(ACTION_CRAZY_CAT_LADY); + if (Creature* auriaya = instance->GetCreature(BOSS_AURIAYA)) + auriaya->AI()->DoAction(ACTION_CRAZY_CAT_LADY); } private: @@ -472,8 +472,8 @@ class npc_feral_defender : public CreatureScript void JustDied(Unit* /*killer*/) override { DoCast(me, SPELL_SUMMON_ESSENCE); - if (Creature* Auriaya = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_AURIAYA))) - Auriaya->AI()->DoAction(ACTION_RESPAWN_DEFENDER); + if (Creature* auriaya = instance->GetCreature(BOSS_AURIAYA)) + auriaya->AI()->DoAction(ACTION_RESPAWN_DEFENDER); } private: diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index b2958daf07c..8e734e6d3e7 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -974,11 +974,6 @@ class npc_mimirons_inferno : public CreatureScript public: npc_mimirons_inferno() : CreatureScript("npc_mimirons_inferno") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<npc_mimirons_infernoAI>(creature); - } - struct npc_mimirons_infernoAI : public npc_escortAI { npc_mimirons_infernoAI(Creature* creature) : npc_escortAI(creature) @@ -1031,6 +1026,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_mimirons_infernoAI>(creature); + } }; class npc_hodirs_fury : public CreatureScript @@ -1247,7 +1246,7 @@ class npc_lorekeeper : public CreatureScript CloseGossipMenuFor(player); me->GetMap()->LoadGrid(364, -16); // make sure leviathan is loaded - if (Creature* leviathan = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_LEVIATHAN))) + if (Creature* leviathan = _instance->GetCreature(BOSS_LEVIATHAN)) { leviathan->AI()->DoAction(ACTION_START_HARD_MODE); me->SetVisible(false); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index ad4b7c6413f..5cfc0d75481 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -1061,8 +1061,8 @@ class npc_ancient_water_spirit : public CreatureScript { Initialize(); instance = me->GetInstanceScript(); - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_FREYA))) - waveCount = ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; + if (Creature* freya = instance->GetCreature(BOSS_FREYA)) + waveCount = ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->trioWaveCount; else waveCount = 0; } @@ -1099,10 +1099,10 @@ class npc_ancient_water_spirit : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_FREYA))) + if (Creature* freya = instance->GetCreature(BOSS_FREYA)) { - ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; - ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(1); + ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->checkElementalAlive[waveCount] = false; + ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->LasherDead(1); } } @@ -1129,8 +1129,8 @@ class npc_storm_lasher : public CreatureScript { Initialize(); instance = me->GetInstanceScript(); - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_FREYA))) - waveCount = ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; + if (Creature* freya = instance->GetCreature(BOSS_FREYA)) + waveCount = ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->trioWaveCount; else waveCount = 0; } @@ -1173,10 +1173,10 @@ class npc_storm_lasher : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_FREYA))) + if (Creature* freya = instance->GetCreature(BOSS_FREYA)) { - ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; - ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(2); + ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->checkElementalAlive[waveCount] = false; + ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->LasherDead(2); } } @@ -1203,8 +1203,8 @@ class npc_snaplasher : public CreatureScript npc_snaplasherAI(Creature* creature) : ScriptedAI(creature) { instance = me->GetInstanceScript(); - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_FREYA))) - waveCount = ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; + if (Creature* freya = instance->GetCreature(BOSS_FREYA)) + waveCount = ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->trioWaveCount; else waveCount = 0; } @@ -1222,10 +1222,10 @@ class npc_snaplasher : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Freya = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_FREYA))) + if (Creature* freya = instance->GetCreature(BOSS_FREYA)) { - ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->checkElementalAlive[waveCount] = false; - ENSURE_AI(boss_freya::boss_freyaAI, Freya->AI())->LasherDead(4); + ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->checkElementalAlive[waveCount] = false; + ENSURE_AI(boss_freya::boss_freyaAI, freya->AI())->LasherDead(4); } } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp index 9630f1ddbfe..6c03b9f5ecb 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -336,8 +336,8 @@ class boss_saronite_animus : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Vezax = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_VEZAX))) - Vezax->AI()->DoAction(ACTION_ANIMUS_DIE); + if (Creature* vezax = instance->GetCreature(BOSS_VEZAX)) + vezax->AI()->DoAction(ACTION_ANIMUS_DIE); } void UpdateAI(uint32 diff) override @@ -434,8 +434,8 @@ class npc_saronite_vapors : public CreatureScript DoCast(me, SPELL_SARONITE_VAPORS); me->DespawnOrUnsummon(30000); - if (Creature* Vezax = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_VEZAX))) - Vezax->AI()->DoAction(ACTION_VAPORS_DIE); + if (Creature* vezax = instance->GetCreature(BOSS_VEZAX)) + vezax->AI()->DoAction(ACTION_VAPORS_DIE); } } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index 57b96e26943..4d8a49160bc 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -242,8 +242,8 @@ class npc_flash_freeze : public CreatureScript // Prevents to have Ice Block on other place than target is me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation()); if (target->GetTypeId() == TYPEID_PLAYER) - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_HODIR))) - Hodir->AI()->DoAction(ACTION_CHEESE_THE_FREEZE); + if (Creature* hodir = instance->GetCreature(BOSS_HODIR)) + hodir->AI()->DoAction(ACTION_CHEESE_THE_FREEZE); } } }; @@ -291,21 +291,21 @@ class npc_ice_block : public CreatureScript void DamageTaken(Unit* who, uint32& /*damage*/) override { - if (Creature* Helper = ObjectAccessor::GetCreature(*me, targetGUID)) + if (Creature* helper = ObjectAccessor::GetCreature(*me, targetGUID)) { - Helper->RemoveUnitFlag(UnitFlags(UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED)); - Helper->SetControlled(false, UNIT_STATE_ROOT); + helper->RemoveUnitFlag(UnitFlags(UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED)); + helper->SetControlled(false, UNIT_STATE_ROOT); - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_HODIR))) + if (Creature* hodir = instance->GetCreature(BOSS_HODIR)) { - if (!Hodir->IsInCombat()) + if (!hodir->IsInCombat()) { - Hodir->SetReactState(REACT_AGGRESSIVE); - Hodir->AI()->DoZoneInCombat(); - Hodir->AI()->AttackStart(who); + hodir->SetReactState(REACT_AGGRESSIVE); + hodir->AI()->DoZoneInCombat(); + hodir->AI()->AttackStart(who); } - Helper->AI()->AttackStart(Hodir); + helper->AI()->AttackStart(hodir); } } } @@ -717,8 +717,8 @@ class npc_hodir_priest : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_HODIR))) - Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); + if (Creature* hodir = instance->GetCreature(BOSS_HODIR)) + hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); } private: @@ -782,8 +782,8 @@ class npc_hodir_shaman : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_HODIR))) - Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); + if (Creature* hodir = instance->GetCreature(BOSS_HODIR)) + hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); } private: @@ -846,8 +846,8 @@ class npc_hodir_druid : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_HODIR))) - Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); + if (Creature* hodir = instance->GetCreature(BOSS_HODIR)) + hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); } private: @@ -929,8 +929,8 @@ class npc_hodir_mage : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_HODIR))) - Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); + if (Creature* hodir = instance->GetCreature(BOSS_HODIR)) + hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS); } private: diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index e4040a44a36..37141085731 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -328,7 +328,7 @@ class npc_iron_construct : public CreatureScript if (me->HasAura(RAID_MODE(SPELL_BRITTLE, SPELL_BRITTLE_25)) && damage >= 5000) { DoCast(SPELL_SHATTER); - if (Creature* ignis = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_IGNIS))) + if (Creature* ignis = _instance->GetCreature(BOSS_IGNIS)) if (ignis->AI()) ignis->AI()->DoAction(ACTION_REMOVE_BUFF); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 5cf1cf67de8..fd4d7b02229 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -371,7 +371,7 @@ static bool IsEncounterFinished(Unit* who) mkii->DespawnOrUnsummon(120000); vx001->DespawnOrUnsummon(120000); aerial->DespawnOrUnsummon(120000); - if (Creature* mimiron = ObjectAccessor::GetCreature(*who, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->JustDied(who); return true; } @@ -428,7 +428,7 @@ class boss_mimiron : public CreatureScript me->RemoveAurasDueToSpell(SPELL_WELD); DoCast(me->GetVehicleBase(), SPELL_SEAT_6); - if (GameObject* button = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_MIMIRON_BUTTON))) + if (GameObject* button = instance->GetGameObject(DATA_MIMIRON_BUTTON)) button->AddFlag(GO_FLAG_NOT_SELECTABLE); if (_fireFighter) @@ -458,14 +458,14 @@ class boss_mimiron : public CreatureScript _Reset(); me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_MIMIRON_ELEVATOR))) + if (GameObject* elevator = instance->GetGameObject(DATA_MIMIRON_ELEVATOR)) elevator->SetGoState(GO_STATE_ACTIVE); if (_fireFighter) - if (Creature* computer = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_COMPUTER))) + if (Creature* computer = instance->GetCreature(DATA_COMPUTER)) computer->AI()->DoAction(DO_DEACTIVATE_COMPUTER); - if (GameObject* button = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_MIMIRON_BUTTON))) + if (GameObject* button = instance->GetGameObject(DATA_MIMIRON_BUTTON)) { button->SetGoState(GO_STATE_READY); button->RemoveFlag(GO_FLAG_NOT_SELECTABLE); @@ -493,7 +493,7 @@ class boss_mimiron : public CreatureScript switch (eventId) { case EVENT_SUMMON_FLAMES: - if (Unit* worldtrigger = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_MIMIRON_WORLD_TRIGGER))) + if (Creature* worldtrigger = instance->GetCreature(DATA_MIMIRON_WORLD_TRIGGER)) worldtrigger->CastCustomSpell(SPELL_SCRIPT_EFFECT_SUMMON_FLAMES_INITIAL, SPELLVALUE_MAX_TARGETS, 3, NULL, true, NULL, NULL, me->GetGUID()); events.RescheduleEvent(EVENT_SUMMON_FLAMES, 28000); break; @@ -529,14 +529,14 @@ class boss_mimiron : public CreatureScript events.ScheduleEvent(EVENT_VX001_ACTIVATION_4, 5000); break; case EVENT_VX001_ACTIVATION_4: - if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_MIMIRON_ELEVATOR))) + if (GameObject* elevator = instance->GetGameObject(DATA_MIMIRON_ELEVATOR)) elevator->SetGoState(GO_STATE_READY); - if (Unit* worldtrigger = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_MIMIRON_WORLD_TRIGGER))) + if (Creature* worldtrigger = instance->GetCreature(DATA_MIMIRON_WORLD_TRIGGER)) worldtrigger->CastSpell(worldtrigger, SPELL_ELEVATOR_KNOCKBACK); events.ScheduleEvent(EVENT_VX001_ACTIVATION_5, 6000); break; case EVENT_VX001_ACTIVATION_5: - if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_MIMIRON_ELEVATOR))) + if (GameObject* elevator = instance->GetGameObject(DATA_MIMIRON_ELEVATOR)) elevator->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); if (Creature* vx001 = me->SummonCreature(NPC_VX_001, VX001SummonPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000)) vx001->CastSpell(vx001, SPELL_FREEZE_ANIM); @@ -644,7 +644,7 @@ class boss_mimiron : public CreatureScript Talk(SAY_V07TRON_DEATH); if (_fireFighter) { - if (Creature* computer = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_COMPUTER))) + if (Creature* computer = instance->GetCreature(DATA_COMPUTER)) computer->AI()->DoAction(DO_DEACTIVATE_COMPUTER); me->SummonGameObject(RAID_MODE(GO_CACHE_OF_INNOVATION_FIREFIGHTER, GO_CACHE_OF_INNOVATION_FIREFIGHTER_HERO), 2744.040f, 2569.352f, 364.3135f, 3.124123f, QuaternionData(0.f, 0.f, 0.9999619f, 0.008734641f), 604800); } @@ -783,7 +783,7 @@ class boss_leviathan_mk_ii : public CreatureScript void KilledUnit(Unit* victim) override { if (victim->GetTypeId() == TYPEID_PLAYER) - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->Talk(events.IsInPhase(PHASE_LEVIATHAN_MK_II) ? SAY_MKII_SLAY : SAY_V07TRON_SLAY); } @@ -798,7 +798,7 @@ class boss_leviathan_mk_ii : public CreatureScript me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); DoCast(me, SPELL_HALF_HEAL); - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->DoAction(DO_ACTIVATE_VX001); break; case WP_MKII_P4_POS_1: @@ -808,7 +808,7 @@ class boss_leviathan_mk_ii : public CreatureScript events.ScheduleEvent(EVENT_MOVE_POINT_3, 1); break; case WP_MKII_P4_POS_3: - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->DoAction(DO_ACTIVATE_V0L7R0N_2); break; case WP_MKII_P4_POS_4: @@ -951,7 +951,7 @@ class boss_vx_001 : public CreatureScript me->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); // | UNIT_FLAG_NOT_SELECTABLE); DoCast(me, SPELL_HALF_HEAL); // has no effect, wat DoCast(me, SPELL_TORSO_DISABLED); - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->DoAction(DO_ACTIVATE_AERIAL); } else if (events.IsInPhase(PHASE_VOL7RON)) @@ -1022,7 +1022,7 @@ class boss_vx_001 : public CreatureScript void KilledUnit(Unit* victim) override { if (victim->GetTypeId() == TYPEID_PLAYER) - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->Talk(events.IsInPhase(PHASE_VX_001) ? SAY_VX001_SLAY : SAY_V07TRON_SLAY); } @@ -1201,7 +1201,7 @@ class boss_aerial_command_unit : public CreatureScript void KilledUnit(Unit* victim) override { if (victim->GetTypeId() == TYPEID_PLAYER) - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->Talk(events.IsInPhase(PHASE_AERIAL_COMMAND_UNIT) ? SAY_AERIAL_SLAY : SAY_V07TRON_SLAY); } @@ -1211,7 +1211,7 @@ class boss_aerial_command_unit : public CreatureScript { me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->DoAction(DO_ACTIVATE_V0L7R0N_1); } } @@ -1435,7 +1435,7 @@ class npc_mimiron_computer : public CreatureScript { case EVENT_SELF_DESTRUCT_10: Talk(SAY_SELF_DESTRUCT_10); - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->DoAction(DO_ACTIVATE_HARD_MODE); events.ScheduleEvent(EVENT_SELF_DESTRUCT_9, 60000); break; @@ -1477,7 +1477,7 @@ class npc_mimiron_computer : public CreatureScript break; case EVENT_SELF_DESTRUCT_FINALIZED: Talk(SAY_SELF_DESTRUCT_FINALIZED); - if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MIMIRON))) + if (Creature* mimiron = instance->GetCreature(BOSS_MIMIRON)) mimiron->AI()->DoAction(DO_ACTIVATE_SELF_DESTRUCT); DoCast(me, SPELL_SELF_DESTRUCTION_AURA); DoCast(me, SPELL_SELF_DESTRUCTION_VISUAL); @@ -1658,7 +1658,7 @@ class go_mimiron_hardmode_button : public GameObjectScript if (!instance) return false; - if (Creature* computer = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_COMPUTER))) + if (Creature* computer = instance->GetCreature(DATA_COMPUTER)) computer->AI()->DoAction(DO_ACTIVATE_COMPUTER); go->SetGoState(GO_STATE_ACTIVE); go->AddFlag(GO_FLAG_NOT_SELECTABLE); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index 8a1bbfe712c..3f56f4523cc 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -189,16 +189,22 @@ class boss_razorscale_controller : public CreatureScript public: boss_razorscale_controller() : CreatureScript("boss_razorscale_controller") { } - struct boss_razorscale_controllerAI : public BossAI + struct boss_razorscale_controllerAI : public ScriptedAI { - boss_razorscale_controllerAI(Creature* creature) : BossAI(creature, DATA_RAZORSCALE_CONTROL) + boss_razorscale_controllerAI(Creature* creature) : ScriptedAI(creature), summons(me) { + instance = creature->GetInstanceScript(); me->SetDisplayFromModel(1); } + InstanceScript* instance; + EventMap events; + SummonList summons; + void Reset() override { - _Reset(); + events.Reset(); + summons.DespawnAll(); me->SetReactState(REACT_PASSIVE); } @@ -207,14 +213,14 @@ class boss_razorscale_controller : public CreatureScript switch (spell->Id) { case SPELL_FLAMED: - if (GameObject* Harpoon1 = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_RAZOR_HARPOON_1))) - Harpoon1->RemoveFromWorld(); - if (GameObject* Harpoon2 = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_RAZOR_HARPOON_2))) - Harpoon2->RemoveFromWorld(); - if (GameObject* Harpoon3 = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_RAZOR_HARPOON_3))) - Harpoon3->RemoveFromWorld(); - if (GameObject* Harpoon4 = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_RAZOR_HARPOON_4))) - Harpoon4->RemoveFromWorld(); + if (GameObject* harpoon = instance->GetGameObject(GO_RAZOR_HARPOON_1)) + harpoon->RemoveFromWorld(); + if (GameObject* harpoon = instance->GetGameObject(GO_RAZOR_HARPOON_2)) + harpoon->RemoveFromWorld(); + if (GameObject* harpoon = instance->GetGameObject(GO_RAZOR_HARPOON_3)) + harpoon->RemoveFromWorld(); + if (GameObject* harpoon = instance->GetGameObject(GO_RAZOR_HARPOON_4)) + harpoon->RemoveFromWorld(); DoAction(ACTION_HARPOON_BUILD); DoAction(ACTION_PLACE_BROKEN_HARPOON); break; @@ -229,7 +235,8 @@ class boss_razorscale_controller : public CreatureScript void JustDied(Unit* /*killer*/) override { - _JustDied(); + events.Reset(); + summons.DespawnAll(); } void DoAction(int32 action) override @@ -261,39 +268,39 @@ class boss_razorscale_controller : public CreatureScript { case EVENT_BUILD_HARPOON_1: Talk(EMOTE_HARPOON); - if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_1, PosHarpoon[0].GetPositionX(), PosHarpoon[0].GetPositionY(), PosHarpoon[0].GetPositionZ(), 4.790f, QuaternionData::fromEulerAnglesZYX(4.790f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_1, PosHarpoon[0].GetPositionX(), PosHarpoon[0].GetPositionY(), PosHarpoon[0].GetPositionZ(), 4.790f, QuaternionData::fromEulerAnglesZYX(4.790f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) { - if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) //only nearest broken harpoon - BrokenHarpoon->RemoveFromWorld(); + if (GameObject* brokenHarpoon = harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) //only nearest broken harpoon + brokenHarpoon->RemoveFromWorld(); events.ScheduleEvent(EVENT_BUILD_HARPOON_2, 20000); events.CancelEvent(EVENT_BUILD_HARPOON_1); } return; case EVENT_BUILD_HARPOON_2: Talk(EMOTE_HARPOON); - if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_2, PosHarpoon[1].GetPositionX(), PosHarpoon[1].GetPositionY(), PosHarpoon[1].GetPositionZ(), 4.659f, QuaternionData::fromEulerAnglesZYX(4.659f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_2, PosHarpoon[1].GetPositionX(), PosHarpoon[1].GetPositionY(), PosHarpoon[1].GetPositionZ(), 4.659f, QuaternionData::fromEulerAnglesZYX(4.659f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) { - if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - BrokenHarpoon->RemoveFromWorld(); + if (GameObject* brokenHarpoon = harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) + brokenHarpoon->RemoveFromWorld(); events.CancelEvent(EVENT_BUILD_HARPOON_2); } return; case EVENT_BUILD_HARPOON_3: Talk(EMOTE_HARPOON); - if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_3, PosHarpoon[2].GetPositionX(), PosHarpoon[2].GetPositionY(), PosHarpoon[2].GetPositionZ(), 5.382f, QuaternionData::fromEulerAnglesZYX(5.382f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_3, PosHarpoon[2].GetPositionX(), PosHarpoon[2].GetPositionY(), PosHarpoon[2].GetPositionZ(), 5.382f, QuaternionData::fromEulerAnglesZYX(5.382f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) { - if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - BrokenHarpoon->RemoveFromWorld(); + if (GameObject* brokenHarpoon = harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) + brokenHarpoon->RemoveFromWorld(); events.ScheduleEvent(EVENT_BUILD_HARPOON_4, 20000); events.CancelEvent(EVENT_BUILD_HARPOON_3); } return; case EVENT_BUILD_HARPOON_4: Talk(EMOTE_HARPOON); - if (GameObject* Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_4, PosHarpoon[3].GetPositionX(), PosHarpoon[3].GetPositionY(), PosHarpoon[3].GetPositionZ(), 4.266f, QuaternionData::fromEulerAnglesZYX(4.266f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_4, PosHarpoon[3].GetPositionX(), PosHarpoon[3].GetPositionY(), PosHarpoon[3].GetPositionZ(), 4.266f, QuaternionData::fromEulerAnglesZYX(4.266f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) { - if (GameObject* BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - BrokenHarpoon->RemoveFromWorld(); + if (GameObject* brokenHarpoon = harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) + brokenHarpoon->RemoveFromWorld(); events.CancelEvent(EVENT_BUILD_HARPOON_4); } return; @@ -315,9 +322,9 @@ class go_razorscale_harpoon : public GameObjectScript bool OnGossipHello(Player* /*player*/, GameObject* go) override { - InstanceScript* instance = go->GetInstanceScript(); - if (ObjectAccessor::GetCreature(*go, instance->GetGuidData(BOSS_RAZORSCALE))) - go->AddFlag(GO_FLAG_NOT_SELECTABLE); + if (InstanceScript* instance = go->GetInstanceScript()) + if (instance->GetCreature(BOSS_RAZORSCALE)) + go->AddFlag(GO_FLAG_NOT_SELECTABLE); return false; } }; @@ -361,14 +368,14 @@ class boss_razorscale : public CreatureScript me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_PASSIVE); Initialize(); - if (Creature* commander = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXPEDITION_COMMANDER))) + if (Creature* commander = instance->GetCreature(DATA_EXPEDITION_COMMANDER)) commander->AI()->DoAction(ACTION_COMMANDER_RESET); } void EnterCombat(Unit* /*who*/) override { _EnterCombat(); - if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAZORSCALE_CONTROL))) + if (Creature* controller = instance->GetCreature(DATA_RAZORSCALE_CONTROL)) controller->AI()->DoAction(ACTION_HARPOON_BUILD); me->SetSpeedRate(MOVE_FLIGHT, 3.0f); me->SetReactState(REACT_PASSIVE); @@ -383,7 +390,7 @@ class boss_razorscale : public CreatureScript void JustDied(Unit* /*killer*/) override { _JustDied(); - if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAZORSCALE_CONTROL))) + if (Creature* controller = instance->GetCreature(DATA_RAZORSCALE_CONTROL)) controller->AI()->Reset(); } @@ -459,7 +466,7 @@ class boss_razorscale : public CreatureScript me->SetCanFly(false); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->AddUnitFlag(UnitFlags(UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED)); - if (Creature* commander = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXPEDITION_COMMANDER))) + if (Creature* commander = instance->GetCreature(DATA_EXPEDITION_COMMANDER)) commander->AI()->DoAction(ACTION_GROUND_PHASE); events.ScheduleEvent(EVENT_BREATH, 30000, 0, PHASE_GROUND); events.ScheduleEvent(EVENT_BUFFET, 33000, 0, PHASE_GROUND); @@ -475,7 +482,7 @@ class boss_razorscale : public CreatureScript return; case EVENT_BUFFET: DoCastAOE(SPELL_WINGBUFFET); - if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAZORSCALE_CONTROL))) + if (Creature* controller = instance->GetCreature(DATA_RAZORSCALE_CONTROL)) controller->CastSpell(controller, SPELL_FLAMED, true); events.CancelEvent(EVENT_BUFFET); return; @@ -717,10 +724,10 @@ class npc_expedition_commander : public CreatureScript Phase = 5; break; case 5: - if (Creature* Razorscale = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_RAZORSCALE))) + if (Creature* razorscale = instance->GetCreature(BOSS_RAZORSCALE)) { - Razorscale->AI()->DoAction(ACTION_EVENT_START); - me->SetInCombatWith(Razorscale); + razorscale->AI()->DoAction(ACTION_EVENT_START); + me->SetInCombatWith(razorscale); } if (Creature* firstEngineer = ObjectAccessor::GetCreature(*me, Engineer[0])) firstEngineer->AI()->Talk(SAY_AGGRO_1); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index 0366f1534ba..c6fc0925bf6 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -176,11 +176,6 @@ class boss_xt002 : public CreatureScript public: boss_xt002() : CreatureScript("boss_xt002") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<boss_xt002_AI>(creature); - } - struct boss_xt002_AI : public BossAI { boss_xt002_AI(Creature* creature) : BossAI(creature, BOSS_XT002) @@ -441,6 +436,12 @@ class boss_xt002 : public CreatureScript uint8 _heartExposed; uint32 _transferHealth; }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<boss_xt002_AI>(creature); + } + }; /*------------------------------------------------------- @@ -460,7 +461,7 @@ class npc_xt002_heart : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* xt002 = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_XT002))) + if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) { xt002->AI()->SetData(DATA_TRANSFERED_HEALTH, me->GetHealth()); xt002->AI()->DoAction(ACTION_ENTER_HARD_MODE); @@ -487,11 +488,6 @@ class npc_scrapbot : public CreatureScript public: npc_scrapbot() : CreatureScript("npc_scrapbot") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<npc_scrapbotAI>(creature); - } - struct npc_scrapbotAI : public ScriptedAI { npc_scrapbotAI(Creature* creature) : ScriptedAI(creature) @@ -511,15 +507,15 @@ class npc_scrapbot : public CreatureScript Initialize(); - if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_XT002))) - me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); + if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) + me->GetMotionMaster()->MoveFollow(xt002, 0.0f, 0.0f); } void UpdateAI(uint32 diff) override { if (_rangeCheckTimer <= diff) { - if (Creature* xt002 = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_XT002))) + if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) { if (me->IsWithinMeleeRange(xt002)) { @@ -538,6 +534,12 @@ class npc_scrapbot : public CreatureScript InstanceScript* _instance; uint32 _rangeCheckTimer; }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_scrapbotAI>(creature); + } + }; /*------------------------------------------------------- @@ -550,11 +552,6 @@ class npc_pummeller : public CreatureScript public: npc_pummeller() : CreatureScript("npc_pummeller") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<npc_pummellerAI>(creature); - } - struct npc_pummellerAI : public ScriptedAI { npc_pummellerAI(Creature* creature) : ScriptedAI(creature) @@ -574,7 +571,7 @@ class npc_pummeller : public CreatureScript { Initialize(); - if (Creature* xt002 = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_XT002))) + if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) { Position pos = xt002->GetPosition(); me->GetMotionMaster()->MovePoint(0, pos); @@ -622,6 +619,12 @@ class npc_pummeller : public CreatureScript uint32 _trampleTimer; uint32 _uppercutTimer; }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_pummellerAI>(creature); + } + }; /*------------------------------------------------------- @@ -657,11 +660,6 @@ class npc_boombot : public CreatureScript public: npc_boombot() : CreatureScript("npc_boombot") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<npc_boombotAI>(creature); - } - struct npc_boombotAI : public ScriptedAI { npc_boombotAI(Creature* creature) : ScriptedAI(creature) @@ -682,8 +680,8 @@ class npc_boombot : public CreatureScript DoCast(SPELL_AURA_BOOMBOT); // For achievement /// @todo proper waypoints? - if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_XT002))) - me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); + if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) + me->GetMotionMaster()->MoveFollow(xt002, 0.0f, 0.0f); } void DamageTaken(Unit* /*who*/, uint32& damage) override @@ -723,6 +721,12 @@ class npc_boombot : public CreatureScript InstanceScript* _instance; bool _boomed; }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_boombotAI>(creature); + } + }; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp index 6c1101d433d..79214b5b0e1 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -511,7 +511,7 @@ class boss_voice_of_yogg_saron : public CreatureScript void EnterCombat(Unit* /*who*/) override { - if (Creature* sara = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SARA))) + if (Creature* sara = instance->GetCreature(DATA_SARA)) sara->SetInCombatWith(me); for (uint8 i = DATA_FREYA_YS; i <= DATA_MIMIRON_YS; ++i) @@ -531,7 +531,7 @@ class boss_voice_of_yogg_saron : public CreatureScript void JustDied(Unit* killer) override { // don't despawn Yogg-Saron's corpse, remove him from SummonList! - if (Creature* yogg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_YOGG_SARON))) + if (Creature* yogg = instance->GetCreature(BOSS_YOGG_SARON)) summons.Despawn(yogg); BossAI::JustDied(killer); @@ -556,7 +556,7 @@ class boss_voice_of_yogg_saron : public CreatureScript instance->SetBossState(BOSS_YOGG_SARON, IN_PROGRESS); break; case EVENT_EXTINGUISH_ALL_LIFE: - if (Creature* yogg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_YOGG_SARON))) + if (Creature* yogg = instance->GetCreature(BOSS_YOGG_SARON)) { yogg->AI()->Talk(EMOTE_YOGG_SARON_EXTINGUISH_ALL_LIFE, me); yogg->CastSpell((Unit*)NULL, SPELL_EXTINGUISH_ALL_LIFE, true); @@ -584,7 +584,7 @@ class boss_voice_of_yogg_saron : public CreatureScript break; case EVENT_ILLUSION: { - if (Creature* yogg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_YOGG_SARON))) + if (Creature* yogg = instance->GetCreature(BOSS_YOGG_SARON)) { yogg->AI()->Talk(EMOTE_YOGG_SARON_MADNESS); yogg->AI()->Talk(SAY_YOGG_SARON_MADNESS); @@ -597,7 +597,7 @@ class boss_voice_of_yogg_saron : public CreatureScript uint8 illusion = urand(CHAMBER_ILLUSION, STORMWIND_ILLUSION); instance->SetData(DATA_ILLUSION, illusion); - if (Creature* brain = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_BRAIN_OF_YOGG_SARON))) + if (Creature* brain = instance->GetCreature(DATA_BRAIN_OF_YOGG_SARON)) brain->AI()->DoAction(ACTION_INDUCE_MADNESS); events.ScheduleEvent(EVENT_ILLUSION, 80000, 0, PHASE_TWO); // wowwiki says 80 secs, wowhead says something about 90 secs break; @@ -623,7 +623,7 @@ class boss_voice_of_yogg_saron : public CreatureScript case ACTION_PHASE_TWO: events.SetPhase(PHASE_TWO); me->SummonCreature(NPC_YOGG_SARON, YoggSaronSpawnPos); - if (Creature* brain = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_BRAIN_OF_YOGG_SARON))) + if (Creature* brain = instance->GetCreature(DATA_BRAIN_OF_YOGG_SARON)) brain->SetInCombatWithZone(); events.ScheduleEvent(EVENT_SUMMON_CORRUPTOR_TENTACLE, 1, EVENT_GROUP_SUMMON_TENTACLES, PHASE_TWO); events.ScheduleEvent(EVENT_SUMMON_CONSTRICTOR_TENTACLE, 1, EVENT_GROUP_SUMMON_TENTACLES, PHASE_TWO); @@ -722,7 +722,7 @@ class boss_sara : public CreatureScript if (_events.IsInPhase(PHASE_ONE)) { - if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->DoAction(ACTION_PHASE_TRANSFORM); Talk(SAY_SARA_TRANSFORM_1); @@ -818,14 +818,14 @@ class boss_sara : public CreatureScript Talk(SAY_SARA_TRANSFORM_4); DoCast(me, SPELL_FULL_HEAL); me->setFaction(16); - if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->DoAction(ACTION_PHASE_TWO); if (Creature* mimiron = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MIMIRON_YS))) mimiron->AI()->DoAction(ACTION_PHASE_TWO); break; case EVENT_TRANSFORM_4: DoCast(me, SPELL_PHASE_2_TRANSFORM); - if (Creature* yogg = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_YOGG_SARON))) + if (Creature* yogg = _instance->GetCreature(BOSS_YOGG_SARON)) DoCast(yogg, SPELL_RIDE_YOGG_SARON_VEHICLE); DoCast(me, SPELL_SHADOWY_BARRIER_SARA); _events.SetPhase(PHASE_TWO); @@ -881,7 +881,7 @@ class boss_sara : public CreatureScript break; } - if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->JustSummoned(summon); } @@ -948,7 +948,7 @@ class boss_yogg_saron : public CreatureScript { Talk(SAY_YOGG_SARON_DEATH); - if (Creature* creature = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* creature = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) me->Kill(creature); for (uint8 i = DATA_SARA; i <= DATA_BRAIN_OF_YOGG_SARON; ++i) @@ -1065,11 +1065,11 @@ class boss_brain_of_yogg_saron : public CreatureScript DoCast(me, SPELL_BRAIN_HURT_VISUAL, true); me->AddUnitFlag(UnitFlags(UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE)); - if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->DoAction(ACTION_PHASE_THREE); - if (Creature* sara = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SARA))) + if (Creature* sara = _instance->GetCreature(DATA_SARA)) sara->AI()->DoAction(ACTION_PHASE_THREE); - if (Creature* yogg = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(BOSS_YOGG_SARON))) + if (Creature* yogg = _instance->GetCreature(BOSS_YOGG_SARON)) yogg->AI()->DoAction(ACTION_PHASE_THREE); for (uint8 i = DATA_THORIM_YS; i <= DATA_MIMIRON_YS; ++i) @@ -1107,7 +1107,7 @@ class boss_brain_of_yogg_saron : public CreatureScript DoCastAOE(SPELL_SHATTERED_ILLUSION, true); _instance->HandleGameObject(_instance->GetGuidData(GO_BRAIN_ROOM_DOOR_1 + illusion), true); - if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->DoAction(ACTION_TOGGLE_SHATTERED_ILLUSION); } break; @@ -1214,7 +1214,7 @@ class npc_guardian_of_yogg_saron : public CreatureScript return; // Guardian can be summoned both by Voice of Yogg-Saron and by Ominous Cloud - if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->JustSummoned(me); } @@ -1317,7 +1317,7 @@ class npc_constrictor_tentacle : public CreatureScript void IsSummonedBy(Unit* /*summoner*/) override { - if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->JustSummoned(me); } @@ -1408,7 +1408,7 @@ class npc_influence_tentacle : public CreatureScript void JustDied(Unit* /*killer*/) override { - if (Creature* brain = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BRAIN_OF_YOGG_SARON))) + if (Creature* brain = _instance->GetCreature(DATA_BRAIN_OF_YOGG_SARON)) brain->AI()->DoAction(ACTION_TENTACLE_KILLED); } @@ -2779,7 +2779,7 @@ class spell_yogg_saron_induce_madness : public SpellScriptLoader // 64059 GetCaster()->CastSpell((Unit*)NULL, SPELL_SHATTERED_ILLUSION_REMOVE); if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - if (Creature* voice = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_VOICE_OF_YOGG_SARON))) + if (Creature* voice = instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->DoAction(ACTION_TOGGLE_SHATTERED_ILLUSION); } @@ -3053,7 +3053,9 @@ class spell_yogg_saron_in_the_maws_of_the_old_god : public SpellScriptLoader SpellCastResult CheckRequirement() { if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - if (Creature* yogg = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(BOSS_YOGG_SARON))) + { + if (Creature* yogg = instance->GetCreature(BOSS_YOGG_SARON)) + { if (yogg->FindCurrentSpellBySpellId(SPELL_DEAFENING_ROAR)) { if (GetCaster()->GetDistance(yogg) > 20.0f) @@ -3061,6 +3063,8 @@ class spell_yogg_saron_in_the_maws_of_the_old_god : public SpellScriptLoader else return SPELL_CAST_OK; } + } + } return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 3683e9f5ea3..d34a7ac516c 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -79,6 +79,28 @@ MinionData const minionData[] = ObjectData const creatureData[] = { + { NPC_FLAME_LEVIATHAN, BOSS_LEVIATHAN }, + { NPC_IGNIS, BOSS_IGNIS }, + { NPC_RAZORSCALE, BOSS_RAZORSCALE }, + { NPC_XT002, BOSS_XT002 }, + { NPC_KOLOGARN, BOSS_KOLOGARN }, + { NPC_AURIAYA, BOSS_AURIAYA }, + { NPC_HODIR, BOSS_HODIR }, + { NPC_THORIM, BOSS_THORIM }, + { NPC_FREYA, BOSS_FREYA }, + { NPC_MIMIRON, BOSS_MIMIRON }, + { NPC_VEZAX, BOSS_VEZAX }, + { NPC_YOGG_SARON, BOSS_YOGG_SARON }, + { NPC_ALGALON, BOSS_ALGALON }, + + { NPC_EXPEDITION_COMMANDER, DATA_EXPEDITION_COMMANDER }, + { NPC_RAZORSCALE_CONTROLLER, DATA_RAZORSCALE_CONTROL }, + { NPC_COMPUTER, DATA_COMPUTER }, + { NPC_WORLD_TRIGGER_MIMIRON, DATA_MIMIRON_WORLD_TRIGGER }, + { NPC_VOICE_OF_YOGG_SARON, DATA_VOICE_OF_YOGG_SARON }, + { NPC_SARA, DATA_SARA }, + { NPC_BRAIN_OF_YOGG_SARON, DATA_BRAIN_OF_YOGG_SARON }, + { NPC_BRANN_BRONZBEARD_ALG, DATA_BRANN_BRONZEBEARD_ALG }, { NPC_BRANN_BRONZEBEARD_INTRO, DATA_BRANN_BRONZEBEARD_INTRO }, { NPC_LORE_KEEPER_OF_NORGANNON, DATA_LORE_KEEPER_OF_NORGANNON }, { NPC_HIGH_EXPLORER_DELLORAH, DATA_DELLORAH }, @@ -86,6 +108,19 @@ ObjectData const creatureData[] = { 0, 0, } }; +ObjectData const objectData[] = +{ + { GO_MIMIRON_ELEVATOR, DATA_MIMIRON_ELEVATOR }, + { GO_MIMIRON_BUTTON, DATA_MIMIRON_BUTTON }, + { GO_DOODAD_UL_UNIVERSEGLOBE01, DATA_UNIVERSE_GLOBE }, + { GO_DOODAD_UL_ULDUAR_TRAPDOOR_03, DATA_ALGALON_TRAPDOOR }, + { GO_RAZOR_HARPOON_1, GO_RAZOR_HARPOON_1 }, + { GO_RAZOR_HARPOON_2, GO_RAZOR_HARPOON_2 }, + { GO_RAZOR_HARPOON_3, GO_RAZOR_HARPOON_3 }, + { GO_RAZOR_HARPOON_4, GO_RAZOR_HARPOON_4 }, + { 0, 0 } +}; + class instance_ulduar : public InstanceMapScript { public: @@ -100,7 +135,7 @@ class instance_ulduar : public InstanceMapScript LoadBossBoundaries(boundaries); LoadDoorData(doorData); LoadMinionData(minionData); - LoadObjectData(creatureData, nullptr); + LoadObjectData(creatureData, objectData); _algalonTimer = 61; _maxArmorItemLevel = 0; @@ -124,51 +159,29 @@ class instance_ulduar : public InstanceMapScript } // Creatures - ObjectGuid LeviathanGUID; GuidVector LeviathanVehicleGUIDs; - ObjectGuid IgnisGUID; - ObjectGuid RazorscaleGUID; - ObjectGuid RazorscaleController; - ObjectGuid ExpeditionCommanderGUID; - ObjectGuid XT002GUID; + ObjectGuid XTToyPileGUIDs[4]; ObjectGuid AssemblyGUIDs[3]; - ObjectGuid KologarnGUID; - ObjectGuid AuriayaGUID; - ObjectGuid HodirGUID; - ObjectGuid ThorimGUID; - ObjectGuid FreyaGUID; + ObjectGuid ElderGUIDs[3]; ObjectGuid FreyaAchieveTriggerGUID; - ObjectGuid MimironGUID; ObjectGuid MimironVehicleGUIDs[3]; - ObjectGuid MimironComputerGUID; - ObjectGuid MimironWorldTriggerGUID; - ObjectGuid VezaxGUID; - ObjectGuid YoggSaronGUID; - ObjectGuid VoiceOfYoggSaronGUID; - ObjectGuid SaraGUID; - ObjectGuid BrainOfYoggSaronGUID; ObjectGuid KeeperGUIDs[4]; - ObjectGuid AlgalonGUID; - ObjectGuid BrannBronzebeardAlgGUID; // GameObjects ObjectGuid LeviathanGateGUID; - ObjectGuid RazorHarpoonGUIDs[4]; ObjectGuid KologarnChestGUID; ObjectGuid KologarnBridgeGUID; ObjectGuid ThorimChestGUID; ObjectGuid HodirRareCacheGUID; ObjectGuid HodirChestGUID; ObjectGuid MimironTramGUID; - ObjectGuid MimironElevatorGUID; - ObjectGuid MimironButtonGUID; + ObjectGuid BrainRoomDoorGUIDs[3]; ObjectGuid AlgalonSigilDoorGUID[3]; ObjectGuid AlgalonFloorGUID[2]; - ObjectGuid AlgalonUniverseGUID; - ObjectGuid AlgalonTrapdoorGUID; + ObjectGuid GiftOfTheObserverGUID; // Miscellaneous @@ -239,6 +252,8 @@ class instance_ulduar : public InstanceMapScript void OnCreatureCreate(Creature* creature) override { + InstanceScript::OnCreatureCreate(creature); + if (!TeamInInstance) { Map::PlayerList const& Players = instance->GetPlayers(); @@ -249,40 +264,22 @@ class instance_ulduar : public InstanceMapScript switch (creature->GetEntry()) { - case NPC_LEVIATHAN: - LeviathanGUID = creature->GetGUID(); - break; case NPC_SALVAGED_DEMOLISHER: case NPC_SALVAGED_SIEGE_ENGINE: case NPC_SALVAGED_CHOPPER: LeviathanVehicleGUIDs.push_back(creature->GetGUID()); break; - case NPC_IGNIS: - IgnisGUID = creature->GetGUID(); - break; - - // Razorscale - case NPC_RAZORSCALE: - RazorscaleGUID = creature->GetGUID(); - break; - case NPC_RAZORSCALE_CONTROLLER: - RazorscaleController = creature->GetGUID(); - break; - case NPC_EXPEDITION_COMMANDER: - ExpeditionCommanderGUID = creature->GetGUID(); - break; // XT-002 Deconstructor - case NPC_XT002: - XT002GUID = creature->GetGUID(); - break; case NPC_XT_TOY_PILE: for (uint8 i = 0; i < 4; ++i) + { if (!XTToyPileGUIDs[i]) { XTToyPileGUIDs[i] = creature->GetGUID(); break; } + } break; // Assembly of Iron @@ -299,17 +296,7 @@ class instance_ulduar : public InstanceMapScript AddMinion(creature, true); break; - case NPC_KOLOGARN: - KologarnGUID = creature->GetGUID(); - break; - case NPC_AURIAYA: - AuriayaGUID = creature->GetGUID(); - break; - // Hodir - case NPC_HODIR: - HodirGUID = creature->GetGUID(); - break; case NPC_EIVI_NIGHTFEATHER: if (TeamInInstance == HORDE) creature->UpdateEntry(NPC_TOR_GREYCLOUD); @@ -343,14 +330,7 @@ class instance_ulduar : public InstanceMapScript creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA); break; - case NPC_THORIM: - ThorimGUID = creature->GetGUID(); - break; - // Freya - case NPC_FREYA: - FreyaGUID = creature->GetGUID(); - break; case NPC_IRONBRANCH: ElderGUIDs[0] = creature->GetGUID(); if (GetBossState(BOSS_FREYA) == DONE) @@ -371,9 +351,6 @@ class instance_ulduar : public InstanceMapScript break; // Mimiron - case NPC_MIMIRON: - MimironGUID = creature->GetGUID(); - break; case NPC_LEVIATHAN_MKII: MimironVehicleGUIDs[0] = creature->GetGUID(); break; @@ -383,30 +360,8 @@ class instance_ulduar : public InstanceMapScript case NPC_AERIAL_COMMAND_UNIT: MimironVehicleGUIDs[2] = creature->GetGUID(); break; - case NPC_COMPUTER: - MimironComputerGUID = creature->GetGUID(); - break; - case NPC_WORLD_TRIGGER_MIMIRON: - MimironWorldTriggerGUID = creature->GetGUID(); - break; - - case NPC_VEZAX: - VezaxGUID = creature->GetGUID(); - break; // Yogg-Saron - case NPC_YOGG_SARON: - YoggSaronGUID = creature->GetGUID(); - break; - case NPC_VOICE_OF_YOGG_SARON: - VoiceOfYoggSaronGUID = creature->GetGUID(); - break; - case NPC_BRAIN_OF_YOGG_SARON: - BrainOfYoggSaronGUID = creature->GetGUID(); - break; - case NPC_SARA: - SaraGUID = creature->GetGUID(); - break; case NPC_FREYA_YS: KeeperGUIDs[0] = creature->GetGUID(); _summonYSKeeper[0] = false; @@ -436,12 +391,6 @@ class instance_ulduar : public InstanceMapScript break; // Algalon - case NPC_ALGALON: - AlgalonGUID = creature->GetGUID(); - break; - case NPC_BRANN_BRONZBEARD_ALG: - BrannBronzebeardAlgGUID = creature->GetGUID(); - break; //! These creatures are summoned by something else than Algalon //! but need to be controlled/despawned by him - so they need to be //! registered in his summon list @@ -449,7 +398,7 @@ class instance_ulduar : public InstanceMapScript case NPC_ALGALON_STALKER_ASTEROID_TARGET_01: case NPC_ALGALON_STALKER_ASTEROID_TARGET_02: case NPC_UNLEASHED_DARK_MATTER: - if (Creature* algalon = instance->GetCreature(AlgalonGUID)) + if (Creature* algalon = GetCreature(BOSS_ALGALON)) algalon->AI()->JustSummoned(creature); break; } @@ -459,34 +408,34 @@ class instance_ulduar : public InstanceMapScript void OnCreatureRemove(Creature* creature) override { + InstanceScript::OnCreatureRemove(creature); + switch (creature->GetEntry()) { case NPC_XT_TOY_PILE: for (uint8 i = 0; i < 4; ++i) + { if (XTToyPileGUIDs[i] == creature->GetGUID()) { XTToyPileGUIDs[i].Clear(); break; } + } break; case NPC_STEELBREAKER: case NPC_MOLGEIM: case NPC_BRUNDIR: AddMinion(creature, false); break; - case NPC_BRANN_BRONZBEARD_ALG: - if (BrannBronzebeardAlgGUID == creature->GetGUID()) - BrannBronzebeardAlgGUID.Clear(); - break; default: break; } - - InstanceScript::OnCreatureRemove(creature); } void OnGameObjectCreate(GameObject* gameObject) override { + InstanceScript::OnGameObjectCreate(gameObject); + switch (gameObject->GetEntry()) { case GO_KOLOGARN_CHEST_HERO: @@ -513,43 +462,11 @@ class instance_ulduar : public InstanceMapScript case GO_MIMIRON_TRAM: MimironTramGUID = gameObject->GetGUID(); break; - case GO_MIMIRON_ELEVATOR: - MimironElevatorGUID = gameObject->GetGUID(); - break; - case GO_MIMIRON_BUTTON: - MimironButtonGUID = gameObject->GetGUID(); - break; case GO_LEVIATHAN_GATE: LeviathanGateGUID = gameObject->GetGUID(); if (GetBossState(BOSS_LEVIATHAN) == DONE) gameObject->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); break; - case GO_LEVIATHAN_DOOR: - case GO_XT_002_DOOR: - case GO_IRON_COUNCIL_DOOR: - case GO_ARCHIVUM_DOOR: - case GO_HODIR_ENTRANCE: - case GO_HODIR_DOOR: - case GO_HODIR_ICE_DOOR: - case GO_MIMIRON_DOOR_1: - case GO_MIMIRON_DOOR_2: - case GO_MIMIRON_DOOR_3: - case GO_VEZAX_DOOR: - case GO_YOGG_SARON_DOOR: - AddDoor(gameObject, true); - break; - case GO_RAZOR_HARPOON_1: - RazorHarpoonGUIDs[0] = gameObject->GetGUID(); - break; - case GO_RAZOR_HARPOON_2: - RazorHarpoonGUIDs[1] = gameObject->GetGUID(); - break; - case GO_RAZOR_HARPOON_3: - RazorHarpoonGUIDs[2] = gameObject->GetGUID(); - break; - case GO_RAZOR_HARPOON_4: - RazorHarpoonGUIDs[3] = gameObject->GetGUID(); - break; case GO_MOLE_MACHINE: if (GetBossState(BOSS_RAZORSCALE) == IN_PROGRESS) gameObject->SetGoState(GO_STATE_ACTIVE); @@ -580,23 +497,12 @@ class instance_ulduar : public InstanceMapScript break; case GO_DOODAD_UL_SIGILDOOR_03: AlgalonSigilDoorGUID[2] = gameObject->GetGUID(); - AddDoor(gameObject, true); break; case GO_DOODAD_UL_UNIVERSEFLOOR_01: AlgalonFloorGUID[0] = gameObject->GetGUID(); - AddDoor(gameObject, true); break; case GO_DOODAD_UL_UNIVERSEFLOOR_02: AlgalonFloorGUID[1] = gameObject->GetGUID(); - AddDoor(gameObject, true); - break; - case GO_DOODAD_UL_UNIVERSEGLOBE01: - AlgalonUniverseGUID = gameObject->GetGUID(); - AddDoor(gameObject, true); - break; - case GO_DOODAD_UL_ULDUAR_TRAPDOOR_03: - AlgalonTrapdoorGUID = gameObject->GetGUID(); - AddDoor(gameObject, true); break; case GO_GIFT_OF_THE_OBSERVER_10: case GO_GIFT_OF_THE_OBSERVER_25: @@ -607,40 +513,12 @@ class instance_ulduar : public InstanceMapScript } } - void OnGameObjectRemove(GameObject* gameObject) override - { - switch (gameObject->GetEntry()) - { - case GO_LEVIATHAN_DOOR: - case GO_XT_002_DOOR: - case GO_IRON_COUNCIL_DOOR: - case GO_ARCHIVUM_DOOR: - case GO_HODIR_ENTRANCE: - case GO_HODIR_DOOR: - case GO_HODIR_ICE_DOOR: - case GO_MIMIRON_DOOR_1: - case GO_MIMIRON_DOOR_2: - case GO_MIMIRON_DOOR_3: - case GO_VEZAX_DOOR: - case GO_YOGG_SARON_DOOR: - case GO_DOODAD_UL_SIGILDOOR_03: - case GO_DOODAD_UL_UNIVERSEFLOOR_01: - case GO_DOODAD_UL_UNIVERSEFLOOR_02: - case GO_DOODAD_UL_UNIVERSEGLOBE01: - case GO_DOODAD_UL_ULDUAR_TRAPDOOR_03: - AddDoor(gameObject, false); - break; - default: - break; - } - } - void OnUnitDeath(Unit* unit) override { // Champion/Conqueror of Ulduar if (unit->GetTypeId() == TYPEID_PLAYER) { - for (uint8 i = 0; i < BOSS_ALGALON; i++) + for (uint8 i = 0; i < BOSS_ALGALON; ++i) { if (GetBossState(i) == IN_PROGRESS) { @@ -686,27 +564,27 @@ class instance_ulduar : public InstanceMapScript void ProcessEvent(WorldObject* /*gameObject*/, uint32 eventId) override { - // Flame Leviathan's Tower Event triggers - Creature* FlameLeviathan = instance->GetCreature(LeviathanGUID); - switch (eventId) { + // Flame Leviathan's Tower Event triggers case EVENT_TOWER_OF_STORM_DESTROYED: - if (FlameLeviathan && FlameLeviathan->IsAlive()) - FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_STORM_DESTROYED); + if (Creature* flameLeviathan = GetCreature(BOSS_LEVIATHAN)) + flameLeviathan->AI()->DoAction(ACTION_TOWER_OF_STORM_DESTROYED); break; case EVENT_TOWER_OF_FROST_DESTROYED: - if (FlameLeviathan && FlameLeviathan->IsAlive()) - FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FROST_DESTROYED); + if (Creature* flameLeviathan = GetCreature(BOSS_LEVIATHAN)) + flameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FROST_DESTROYED); break; case EVENT_TOWER_OF_FLAMES_DESTROYED: - if (FlameLeviathan && FlameLeviathan->IsAlive()) - FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FLAMES_DESTROYED); + if (Creature* flameLeviathan = GetCreature(BOSS_LEVIATHAN)) + flameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FLAMES_DESTROYED); break; case EVENT_TOWER_OF_LIFE_DESTROYED: - if (FlameLeviathan && FlameLeviathan->IsAlive()) - FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_LIFE_DESTROYED); + if (Creature* flameLeviathan = GetCreature(BOSS_LEVIATHAN)) + flameLeviathan->AI()->DoAction(ACTION_TOWER_OF_LIFE_DESTROYED); break; + + // Yogg-Saron Event triggers case EVENT_ACTIVATE_SANITY_WELL: if (Creature* freya = instance->GetCreature(KeeperGUIDs[0])) freya->AI()->DoAction(4/*ACTION_SANITY_WELLS*/); @@ -851,9 +729,9 @@ class instance_ulduar : public InstanceMapScript HodirRareCacheData = data; if (!HodirRareCacheData) { - if (Creature* Hodir = instance->GetCreature(HodirGUID)) + if (Creature* hodir = GetCreature(BOSS_HODIR)) if (GameObject* gameObject = instance->GetGameObject(HodirRareCacheGUID)) - Hodir->RemoveGameObject(gameObject, false); + hodir->RemoveGameObject(gameObject, false); } break; case DATA_UNBROKEN: @@ -888,30 +766,7 @@ class instance_ulduar : public InstanceMapScript { switch (data) { - case BOSS_LEVIATHAN: - return LeviathanGUID; - case BOSS_IGNIS: - return IgnisGUID; - - // Razorscale - case BOSS_RAZORSCALE: - return RazorscaleGUID; - case DATA_RAZORSCALE_CONTROL: - return RazorscaleController; - case DATA_EXPEDITION_COMMANDER: - return ExpeditionCommanderGUID; - case GO_RAZOR_HARPOON_1: - return RazorHarpoonGUIDs[0]; - case GO_RAZOR_HARPOON_2: - return RazorHarpoonGUIDs[1]; - case GO_RAZOR_HARPOON_3: - return RazorHarpoonGUIDs[2]; - case GO_RAZOR_HARPOON_4: - return RazorHarpoonGUIDs[3]; - // XT-002 Deconstructor - case BOSS_XT002: - return XT002GUID; case DATA_TOY_PILE_0: case DATA_TOY_PILE_1: case DATA_TOY_PILE_2: @@ -926,18 +781,7 @@ class instance_ulduar : public InstanceMapScript case DATA_BRUNDIR: return AssemblyGUIDs[2]; - case BOSS_KOLOGARN: - return KologarnGUID; - case BOSS_AURIAYA: - return AuriayaGUID; - case BOSS_HODIR: - return HodirGUID; - case BOSS_THORIM: - return ThorimGUID; - // Freya - case BOSS_FREYA: - return FreyaGUID; case BOSS_BRIGHTLEAF: return ElderGUIDs[0]; case BOSS_IRONBRANCH: @@ -946,35 +790,14 @@ class instance_ulduar : public InstanceMapScript return ElderGUIDs[2]; // Mimiron - case BOSS_MIMIRON: - return MimironGUID; case DATA_LEVIATHAN_MK_II: return MimironVehicleGUIDs[0]; case DATA_VX_001: return MimironVehicleGUIDs[1]; case DATA_AERIAL_COMMAND_UNIT: return MimironVehicleGUIDs[2]; - case DATA_COMPUTER: - return MimironComputerGUID; - case DATA_MIMIRON_WORLD_TRIGGER: - return MimironWorldTriggerGUID; - case DATA_MIMIRON_ELEVATOR: - return MimironElevatorGUID; - case DATA_MIMIRON_BUTTON: - return MimironButtonGUID; - - case BOSS_VEZAX: - return VezaxGUID; // Yogg-Saron - case BOSS_YOGG_SARON: - return YoggSaronGUID; - case DATA_VOICE_OF_YOGG_SARON: - return VoiceOfYoggSaronGUID; - case DATA_BRAIN_OF_YOGG_SARON: - return BrainOfYoggSaronGUID; - case DATA_SARA: - return SaraGUID; case GO_BRAIN_ROOM_DOOR_1: return BrainRoomDoorGUIDs[0]; case GO_BRAIN_ROOM_DOOR_2: @@ -991,8 +814,6 @@ class instance_ulduar : public InstanceMapScript return KeeperGUIDs[3]; // Algalon - case BOSS_ALGALON: - return AlgalonGUID; case DATA_SIGILDOOR_01: return AlgalonSigilDoorGUID[0]; case DATA_SIGILDOOR_02: @@ -1003,15 +824,9 @@ class instance_ulduar : public InstanceMapScript return AlgalonFloorGUID[0]; case DATA_UNIVERSE_FLOOR_02: return AlgalonFloorGUID[1]; - case DATA_UNIVERSE_GLOBE: - return AlgalonUniverseGUID; - case DATA_ALGALON_TRAPDOOR: - return AlgalonTrapdoorGUID; - case DATA_BRANN_BRONZEBEARD_ALG: - return BrannBronzebeardAlgGUID; } - return ObjectGuid::Empty; + return InstanceScript::GetGuidData(data); } uint32 GetData(uint32 type) const override @@ -1179,7 +994,7 @@ class instance_ulduar : public InstanceMapScript { DoUpdateWorldState(WORLD_STATE_ALGALON_TIMER_ENABLED, 0); _events.CancelEvent(EVENT_UPDATE_ALGALON_TIMER); - if (Creature* algalon = instance->GetCreature(AlgalonGUID)) + if (Creature* algalon = GetCreature(BOSS_ALGALON)) algalon->AI()->DoAction(EVENT_DESPAWN_ALGALON); } break; @@ -1200,8 +1015,8 @@ class instance_ulduar : public InstanceMapScript } break; case EVENT_LEVIATHAN_BREAK_DOOR: - if (Creature* Leviathan = instance->GetCreature(LeviathanGUID)) - Leviathan->AI()->DoAction(ACTION_MOVE_TO_CENTER_POSITION); + if (Creature* leviathan = GetCreature(BOSS_LEVIATHAN)) + leviathan->AI()->DoAction(ACTION_MOVE_TO_CENTER_POSITION); if (GameObject* gameObject = instance->GetGameObject(LeviathanGateGUID)) gameObject->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); break; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 74adb6d1d13..a26b699b396 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -279,7 +279,7 @@ enum UlduarGameObjects GO_GIFT_OF_THE_OBSERVER_25 = 194822, }; -enum EventIds +enum UUEventIds { EVENT_TOWER_OF_STORM_DESTROYED = 21031, EVENT_TOWER_OF_FROST_DESTROYED = 21032, diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp index e7f17a1033b..0e42a431d93 100644 --- a/src/server/scripts/Northrend/zone_zuldrak.cpp +++ b/src/server/scripts/Northrend/zone_zuldrak.cpp @@ -58,7 +58,7 @@ public: me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); float x, y, z; - me->GetClosePoint(x, y, z, me->GetObjectSize() / 3, 0.1f); + me->GetClosePoint(x, y, z, me->GetCombatReach() / 3, 0.1f); if (Creature* summon = me->SummonCreature(NPC_RAGECLAW, x, y, z, 0, TEMPSUMMON_DEAD_DESPAWN, 1000)) { @@ -183,7 +183,7 @@ public: void Reset() override { float x, y, z; - me->GetClosePoint(x, y, z, me->GetObjectSize() / 3, 25.0f); + me->GetClosePoint(x, y, z, me->GetCombatReach() / 3, 25.0f); me->GetMotionMaster()->MovePoint(0, x, y, z); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp index e2e8a6bbef7..50fbd937d53 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp @@ -351,6 +351,8 @@ public: Talk(SUFF_SAY_RECAP); me->AttackStop(); me->SetReactState(REACT_PASSIVE); + events.Reset(); + me->InterruptNonMeleeSpells(false); me->GetMotionMaster()->MovePoint(RELIQUARY_DESPAWN_WAYPOINT, DespawnPoint); } } @@ -479,6 +481,8 @@ public: Talk(DESI_SAY_RECAP); me->AttackStop(); me->SetReactState(REACT_PASSIVE); + events.Reset(); + me->InterruptNonMeleeSpells(false); me->GetMotionMaster()->MovePoint(RELIQUARY_DESPAWN_WAYPOINT, DespawnPoint); } } @@ -743,7 +747,7 @@ class spell_reliquary_of_souls_aura_of_desire : public SpellScriptLoader caster->CastCustomSpell(SPELL_AURA_OF_DESIRE_DAMAGE, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff); } - void UpdateAmount(AuraEffect const* /*effect*/) + void UpdateAmount(AuraEffect* /*aurEff*/) { if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1)) effect->ChangeAmount(effect->GetAmount() - 5); @@ -752,7 +756,7 @@ class spell_reliquary_of_souls_aura_of_desire : public SpellScriptLoader void Register() override { OnEffectProc += AuraEffectProcFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::OnProcSpell, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT); - OnEffectPeriodic += AuraEffectPeriodicFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::UpdateAmount, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::UpdateAmount, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; diff --git a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/instance_magtheridons_lair.cpp b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/instance_magtheridons_lair.cpp index 515039e987b..8cd4bbc9cf0 100644 --- a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/instance_magtheridons_lair.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/instance_magtheridons_lair.cpp @@ -55,7 +55,7 @@ ObjectData const gameObjectData[] = { 0, 0 } //END }; -static DataTypes const collapseObjectDatas[] = +static MLDataTypes const collapseObjectDatas[] = { DATA_MAGTHERIDON_COLUMN_0, DATA_MAGTHERIDON_COLUMN_1, @@ -116,7 +116,7 @@ class instance_magtheridons_lair : public InstanceMapScript HandleGameObject(ObjectGuid::Empty, value == ACTION_ENABLE ? true : false, hall); break; case DATA_COLLAPSE_2: - for (DataTypes data : collapseObjectDatas) + for (MLDataTypes data : collapseObjectDatas) if (GameObject* go = GetGameObject(data)) HandleGameObject(ObjectGuid::Empty, value == ACTION_ENABLE ? true : false, go); break; diff --git a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/magtheridons_lair.h b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/magtheridons_lair.h index 4e46ecd98e7..87190d446b0 100644 --- a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/magtheridons_lair.h +++ b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/magtheridons_lair.h @@ -25,7 +25,7 @@ uint32 const EncounterCount = 1; -enum DataTypes +enum MLDataTypes { DATA_MAGTHERIDON = 0, DATA_WORLD_TRIGGER = 1, @@ -42,13 +42,13 @@ enum DataTypes DATA_CALL_WARDERS = 12 }; -enum Actions +enum MLActions { ACTION_ENABLE = 1, ACTION_DISABLE = 2 }; -enum CreatureIds +enum MLCreatureIds { NPC_MAGTHERIDON = 17257, NPC_ABYSSAL = 17454, @@ -61,7 +61,7 @@ enum CreatureIds NPC_HELLFIRE_WARDER = 18829 }; -enum GameObjectIds +enum MLGameObjectIds { GO_MAGTHERIDON_DOOR = 183847, GO_MANTICRON_CUBE = 181713, diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp index a482096ce7c..a8bd85023a2 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -525,7 +525,7 @@ public: Tapped = true; float x, y, z; - caster->GetClosePoint(x, y, z, me->GetObjectSize()); + caster->GetClosePoint(x, y, z, me->GetCombatReach()); me->SetWalk(false); me->GetMotionMaster()->MovePoint(1, x, y, z); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 7adb0d0d4cf..eb800765b7c 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -4207,42 +4207,6 @@ class spell_gen_pony_mount_check : public SpellScriptLoader } }; -class spell_gen_shroud_of_death : public SpellScriptLoader -{ -public: - spell_gen_shroud_of_death() : SpellScriptLoader("spell_gen_shroud_of_death") { } - - class spell_gen_shroud_of_death_AuraScript : public AuraScript - { - PrepareAuraScript(spell_gen_shroud_of_death_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - PreventDefaultAction(); - GetUnitOwner()->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); - GetUnitOwner()->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - PreventDefaultAction(); - GetUnitOwner()->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); - GetUnitOwner()->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_gen_shroud_of_death_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - OnEffectRemove += AuraEffectRemoveFn(spell_gen_shroud_of_death_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_gen_shroud_of_death_AuraScript(); - } -}; - // 169869 - Transformation Sickness class spell_gen_decimatus_transformation_sickness : public SpellScriptLoader { @@ -4568,7 +4532,6 @@ void AddSC_generic_spell_scripts() new spell_gen_landmine_knockback_achievement(); new spell_gen_clear_debuffs(); new spell_gen_pony_mount_check(); - new spell_gen_shroud_of_death(); new spell_gen_decimatus_transformation_sickness(); new spell_gen_anetheron_summon_towering_infernal(); new spell_gen_mark_of_kazrogal_hellfire(); diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 9836318f066..7461e52e1b4 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -1100,6 +1100,46 @@ class spell_item_gnomish_death_ray : public SpellScriptLoader } }; +// Item 10721: Gnomish Harm Prevention Belt +// 13234 - Harm Prevention Belt +enum HarmPreventionBelt +{ + SPELL_FORCEFIELD_COLLAPSE = 13235 +}; + +class spell_item_harm_prevention_belt : public SpellScriptLoader +{ +public: + spell_item_harm_prevention_belt() : SpellScriptLoader("spell_item_harm_prevention_belt") { } + + class spell_item_harm_prevention_belt_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_harm_prevention_belt_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_FORCEFIELD_COLLAPSE)) + return false; + return true; + } + + void HandleProc(ProcEventInfo& /*eventInfo*/) + { + GetTarget()->CastSpell((Unit*)nullptr, SPELL_FORCEFIELD_COLLAPSE, true); + } + + void Register() override + { + OnProc += AuraProcFn(spell_item_harm_prevention_belt_AuraScript::HandleProc); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_item_harm_prevention_belt_AuraScript(); + } +}; + enum Heartpierce { SPELL_INVIGORATION_MANA = 71881, @@ -4839,6 +4879,7 @@ void AddSC_item_spell_scripts() new spell_item_flask_of_the_north(); new spell_item_frozen_shadoweave(); new spell_item_gnomish_death_ray(); + new spell_item_harm_prevention_belt(); new spell_item_heartpierce<SPELL_INVIGORATION_ENERGY, SPELL_INVIGORATION_MANA, SPELL_INVIGORATION_RAGE, SPELL_INVIGORATION_RP>("spell_item_heartpierce"); new spell_item_heartpierce<SPELL_INVIGORATION_ENERGY_HERO, SPELL_INVIGORATION_MANA_HERO, SPELL_INVIGORATION_RAGE_HERO, SPELL_INVIGORATION_RP_HERO>("spell_item_heartpierce_hero"); new spell_item_crystal_spire_of_karabor(); diff --git a/src/server/scripts/Spells/spell_pet.cpp b/src/server/scripts/Spells/spell_pet.cpp index c0b570cbf46..7aaba87a2da 100644 --- a/src/server/scripts/Spells/spell_pet.cpp +++ b/src/server/scripts/Spells/spell_pet.cpp @@ -314,7 +314,7 @@ public: { if (AuraEffect* /* aurEff */ect = owner->GetAuraEffect(56246, EFFECT_0)) { - float base_attPower = pet->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE) * pet->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_PCT); + float base_attPower = pet->GetFlatModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE) * pet->GetPctModifierValue(UNIT_MOD_ATTACK_POWER, BASE_PCT); amount += CalculatePct(amount+base_attPower, /* aurEff */ect->GetAmount()); } } diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 98814128a34..c0e1fdaae33 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -361,7 +361,7 @@ public: uint32 BirdEntry = 0; float fX, fY, fZ; - go->GetClosePoint(fX, fY, fZ, go->GetObjectSize(), INTERACTION_DISTANCE); + go->GetClosePoint(fX, fY, fZ, go->GetCombatReach(), INTERACTION_DISTANCE); switch (go->GetEntry()) { diff --git a/src/server/scripts/World/item_scripts.cpp b/src/server/scripts/World/item_scripts.cpp index 55b7d571d56..628ca0edcae 100644 --- a/src/server/scripts/World/item_scripts.cpp +++ b/src/server/scripts/World/item_scripts.cpp @@ -243,7 +243,7 @@ public: return true; float x, y, z; - go->GetClosePoint(x, y, z, go->GetObjectSize() / 3, 7.0f); + go->GetClosePoint(x, y, z, go->GetCombatReach() / 3, 7.0f); go->SummonGameObject(GO_HIGH_QUALITY_FUR, *go, QuaternionData::fromEulerAnglesZYX(go->GetOrientation(), 0.0f, 0.0f), 1); if (TempSummon* summon = player->SummonCreature(NPC_NESINGWARY_TRAPPER, x, y, z, go->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 1000)) { |