mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-15 18:10:26 +00:00
Big re-organization of repository [W.I.P]
This commit is contained in:
@@ -1,310 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BoundingIntervalHierarchy.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define isnan _isnan
|
||||
#else
|
||||
#define isnan std::isnan
|
||||
#endif
|
||||
|
||||
void BIH::buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats)
|
||||
{
|
||||
// create space for the first node
|
||||
tempTree.push_back(uint32(3 << 30)); // dummy leaf
|
||||
tempTree.insert(tempTree.end(), 2, 0);
|
||||
//tempTree.add(0);
|
||||
|
||||
// seed bbox
|
||||
AABound gridBox = { bounds.low(), bounds.high() };
|
||||
AABound nodeBox = gridBox;
|
||||
// seed subdivide function
|
||||
subdivide(0, dat.numPrims - 1, tempTree, dat, gridBox, nodeBox, 0, 1, stats);
|
||||
}
|
||||
|
||||
void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats)
|
||||
{
|
||||
if ((right - left + 1) <= dat.maxPrims || depth >= MAX_STACK_SIZE)
|
||||
{
|
||||
// write leaf node
|
||||
stats.updateLeaf(depth, right - left + 1);
|
||||
createNode(tempTree, nodeIndex, left, right);
|
||||
return;
|
||||
}
|
||||
// calculate extents
|
||||
int axis = -1, prevAxis, rightOrig;
|
||||
float clipL = G3D::fnan(), clipR = G3D::fnan(), prevClip = G3D::fnan();
|
||||
float split = G3D::fnan(), prevSplit;
|
||||
bool wasLeft = true;
|
||||
while (true)
|
||||
{
|
||||
prevAxis = axis;
|
||||
prevSplit = split;
|
||||
// perform quick consistency checks
|
||||
G3D::Vector3 d( gridBox.hi - gridBox.lo );
|
||||
if (d.x < 0 || d.y < 0 || d.z < 0)
|
||||
throw std::logic_error("negative node extents");
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i])
|
||||
{
|
||||
//UI.printError(Module.ACCEL, "Reached tree area in error - discarding node with: %d objects", right - left + 1);
|
||||
throw std::logic_error("invalid node overlap");
|
||||
}
|
||||
}
|
||||
// find longest axis
|
||||
axis = d.primaryAxis();
|
||||
split = 0.5f * (gridBox.lo[axis] + gridBox.hi[axis]);
|
||||
// partition L/R subsets
|
||||
clipL = -G3D::inf();
|
||||
clipR = G3D::inf();
|
||||
rightOrig = right; // save this for later
|
||||
float nodeL = G3D::inf();
|
||||
float nodeR = -G3D::inf();
|
||||
for (int i = left; i <= right;)
|
||||
{
|
||||
int obj = dat.indices[i];
|
||||
float minb = dat.primBound[obj].low()[axis];
|
||||
float maxb = dat.primBound[obj].high()[axis];
|
||||
float center = (minb + maxb) * 0.5f;
|
||||
if (center <= split)
|
||||
{
|
||||
// stay left
|
||||
i++;
|
||||
if (clipL < maxb)
|
||||
clipL = maxb;
|
||||
}
|
||||
else
|
||||
{
|
||||
// move to the right most
|
||||
int t = dat.indices[i];
|
||||
dat.indices[i] = dat.indices[right];
|
||||
dat.indices[right] = t;
|
||||
right--;
|
||||
if (clipR > minb)
|
||||
clipR = minb;
|
||||
}
|
||||
nodeL = std::min(nodeL, minb);
|
||||
nodeR = std::max(nodeR, maxb);
|
||||
}
|
||||
// check for empty space
|
||||
if (nodeL > nodeBox.lo[axis] && nodeR < nodeBox.hi[axis])
|
||||
{
|
||||
float nodeBoxW = nodeBox.hi[axis] - nodeBox.lo[axis];
|
||||
float nodeNewW = nodeR - nodeL;
|
||||
// node box is too big compare to space occupied by primitives?
|
||||
if (1.3f * nodeNewW < nodeBoxW)
|
||||
{
|
||||
stats.updateBVH2();
|
||||
int nextIndex = tempTree.size();
|
||||
// allocate child
|
||||
tempTree.push_back(0);
|
||||
tempTree.push_back(0);
|
||||
tempTree.push_back(0);
|
||||
// write bvh2 clip node
|
||||
stats.updateInner();
|
||||
tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex;
|
||||
tempTree[nodeIndex + 1] = floatToRawIntBits(nodeL);
|
||||
tempTree[nodeIndex + 2] = floatToRawIntBits(nodeR);
|
||||
// update nodebox and recurse
|
||||
nodeBox.lo[axis] = nodeL;
|
||||
nodeBox.hi[axis] = nodeR;
|
||||
subdivide(left, rightOrig, tempTree, dat, gridBox, nodeBox, nextIndex, depth + 1, stats);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ensure we are making progress in the subdivision
|
||||
if (right == rightOrig)
|
||||
{
|
||||
// all left
|
||||
if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) {
|
||||
// we are stuck here - create a leaf
|
||||
stats.updateLeaf(depth, right - left + 1);
|
||||
createNode(tempTree, nodeIndex, left, right);
|
||||
return;
|
||||
}
|
||||
if (clipL <= split) {
|
||||
// keep looping on left half
|
||||
gridBox.hi[axis] = split;
|
||||
prevClip = clipL;
|
||||
wasLeft = true;
|
||||
continue;
|
||||
}
|
||||
gridBox.hi[axis] = split;
|
||||
prevClip = G3D::fnan();
|
||||
}
|
||||
else if (left > right)
|
||||
{
|
||||
// all right
|
||||
if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) {
|
||||
// we are stuck here - create a leaf
|
||||
stats.updateLeaf(depth, right - left + 1);
|
||||
createNode(tempTree, nodeIndex, left, right);
|
||||
return;
|
||||
}
|
||||
right = rightOrig;
|
||||
if (clipR >= split) {
|
||||
// keep looping on right half
|
||||
gridBox.lo[axis] = split;
|
||||
prevClip = clipR;
|
||||
wasLeft = false;
|
||||
continue;
|
||||
}
|
||||
gridBox.lo[axis] = split;
|
||||
prevClip = G3D::fnan();
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are actually splitting stuff
|
||||
if (prevAxis != -1 && !isnan(prevClip))
|
||||
{
|
||||
// second time through - lets create the previous split
|
||||
// since it produced empty space
|
||||
int nextIndex = tempTree.size();
|
||||
// allocate child node
|
||||
tempTree.push_back(0);
|
||||
tempTree.push_back(0);
|
||||
tempTree.push_back(0);
|
||||
if (wasLeft) {
|
||||
// create a node with a left child
|
||||
// write leaf node
|
||||
stats.updateInner();
|
||||
tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex;
|
||||
tempTree[nodeIndex + 1] = floatToRawIntBits(prevClip);
|
||||
tempTree[nodeIndex + 2] = floatToRawIntBits(G3D::inf());
|
||||
} else {
|
||||
// create a node with a right child
|
||||
// write leaf node
|
||||
stats.updateInner();
|
||||
tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3);
|
||||
tempTree[nodeIndex + 1] = floatToRawIntBits(-G3D::inf());
|
||||
tempTree[nodeIndex + 2] = floatToRawIntBits(prevClip);
|
||||
}
|
||||
// count stats for the unused leaf
|
||||
depth++;
|
||||
stats.updateLeaf(depth, 0);
|
||||
// now we keep going as we are, with a new nodeIndex:
|
||||
nodeIndex = nextIndex;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// compute index of child nodes
|
||||
int nextIndex = tempTree.size();
|
||||
// allocate left node
|
||||
int nl = right - left + 1;
|
||||
int nr = rightOrig - (right + 1) + 1;
|
||||
if (nl > 0) {
|
||||
tempTree.push_back(0);
|
||||
tempTree.push_back(0);
|
||||
tempTree.push_back(0);
|
||||
} else
|
||||
nextIndex -= 3;
|
||||
// allocate right node
|
||||
if (nr > 0) {
|
||||
tempTree.push_back(0);
|
||||
tempTree.push_back(0);
|
||||
tempTree.push_back(0);
|
||||
}
|
||||
// write leaf node
|
||||
stats.updateInner();
|
||||
tempTree[nodeIndex + 0] = (axis << 30) | nextIndex;
|
||||
tempTree[nodeIndex + 1] = floatToRawIntBits(clipL);
|
||||
tempTree[nodeIndex + 2] = floatToRawIntBits(clipR);
|
||||
// prepare L/R child boxes
|
||||
AABound gridBoxL(gridBox), gridBoxR(gridBox);
|
||||
AABound nodeBoxL(nodeBox), nodeBoxR(nodeBox);
|
||||
gridBoxL.hi[axis] = gridBoxR.lo[axis] = split;
|
||||
nodeBoxL.hi[axis] = clipL;
|
||||
nodeBoxR.lo[axis] = clipR;
|
||||
// recurse
|
||||
if (nl > 0)
|
||||
subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats);
|
||||
else
|
||||
stats.updateLeaf(depth + 1, 0);
|
||||
if (nr > 0)
|
||||
subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats);
|
||||
else
|
||||
stats.updateLeaf(depth + 1, 0);
|
||||
}
|
||||
|
||||
bool BIH::writeToFile(FILE* wf) const
|
||||
{
|
||||
uint32 treeSize = tree.size();
|
||||
uint32 check=0, count;
|
||||
check += fwrite(&bounds.low(), sizeof(float), 3, wf);
|
||||
check += fwrite(&bounds.high(), sizeof(float), 3, wf);
|
||||
check += fwrite(&treeSize, sizeof(uint32), 1, wf);
|
||||
check += fwrite(&tree[0], sizeof(uint32), treeSize, wf);
|
||||
count = objects.size();
|
||||
check += fwrite(&count, sizeof(uint32), 1, wf);
|
||||
check += fwrite(&objects[0], sizeof(uint32), count, wf);
|
||||
return check == (3 + 3 + 2 + treeSize + count);
|
||||
}
|
||||
|
||||
bool BIH::readFromFile(FILE* rf)
|
||||
{
|
||||
uint32 treeSize;
|
||||
G3D::Vector3 lo, hi;
|
||||
uint32 check=0, count=0;
|
||||
check += fread(&lo, sizeof(float), 3, rf);
|
||||
check += fread(&hi, sizeof(float), 3, rf);
|
||||
bounds = G3D::AABox(lo, hi);
|
||||
check += fread(&treeSize, sizeof(uint32), 1, rf);
|
||||
tree.resize(treeSize);
|
||||
check += fread(&tree[0], sizeof(uint32), treeSize, rf);
|
||||
check += fread(&count, sizeof(uint32), 1, rf);
|
||||
objects.resize(count); // = new uint32[nObjects];
|
||||
check += fread(&objects[0], sizeof(uint32), count, rf);
|
||||
return uint64(check) == uint64(3 + 3 + 1 + 1 + uint64(treeSize) + uint64(count));
|
||||
}
|
||||
|
||||
void BIH::BuildStats::updateLeaf(int depth, int n)
|
||||
{
|
||||
numLeaves++;
|
||||
minDepth = std::min(depth, minDepth);
|
||||
maxDepth = std::max(depth, maxDepth);
|
||||
sumDepth += depth;
|
||||
minObjects = std::min(n, minObjects);
|
||||
maxObjects = std::max(n, maxObjects);
|
||||
sumObjects += n;
|
||||
int nl = std::min(n, 5);
|
||||
++numLeavesN[nl];
|
||||
}
|
||||
|
||||
void BIH::BuildStats::printStats()
|
||||
{
|
||||
printf("Tree stats:\n");
|
||||
printf(" * Nodes: %d\n", numNodes);
|
||||
printf(" * Leaves: %d\n", numLeaves);
|
||||
printf(" * Objects: min %d\n", minObjects);
|
||||
printf(" avg %.2f\n", (float) sumObjects / numLeaves);
|
||||
printf(" avg(n>0) %.2f\n", (float) sumObjects / (numLeaves - numLeavesN[0]));
|
||||
printf(" max %d\n", maxObjects);
|
||||
printf(" * Depth: min %d\n", minDepth);
|
||||
printf(" avg %.2f\n", (float) sumDepth / numLeaves);
|
||||
printf(" max %d\n", maxDepth);
|
||||
printf(" * Leaves w/: N=0 %3d%%\n", 100 * numLeavesN[0] / numLeaves);
|
||||
printf(" N=1 %3d%%\n", 100 * numLeavesN[1] / numLeaves);
|
||||
printf(" N=2 %3d%%\n", 100 * numLeavesN[2] / numLeaves);
|
||||
printf(" N=3 %3d%%\n", 100 * numLeavesN[3] / numLeaves);
|
||||
printf(" N=4 %3d%%\n", 100 * numLeavesN[4] / numLeaves);
|
||||
printf(" N>4 %3d%%\n", 100 * numLeavesN[5] / numLeaves);
|
||||
printf(" * BVH2 nodes: %d (%3d%%)\n", numBVH2, 100 * numBVH2 / (numNodes + numLeaves - 2 * numBVH2));
|
||||
}
|
||||
@@ -1,400 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _BIH_H
|
||||
#define _BIH_H
|
||||
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/Ray.h"
|
||||
#include "G3D/AABox.h"
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
#define MAX_STACK_SIZE 64
|
||||
|
||||
static inline uint32 floatToRawIntBits(float f)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32 ival;
|
||||
float fval;
|
||||
} temp;
|
||||
temp.fval=f;
|
||||
return temp.ival;
|
||||
}
|
||||
|
||||
static inline float intBitsToFloat(uint32 i)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32 ival;
|
||||
float fval;
|
||||
} temp;
|
||||
temp.ival=i;
|
||||
return temp.fval;
|
||||
}
|
||||
|
||||
struct AABound
|
||||
{
|
||||
G3D::Vector3 lo, hi;
|
||||
};
|
||||
|
||||
/** Bounding Interval Hierarchy Class.
|
||||
Building and Ray-Intersection functions based on BIH from
|
||||
Sunflow, a Java Raytracer, released under MIT/X11 License
|
||||
http://sunflow.sourceforge.net/
|
||||
Copyright (c) 2003-2007 Christopher Kulla
|
||||
*/
|
||||
|
||||
class BIH
|
||||
{
|
||||
private:
|
||||
void init_empty()
|
||||
{
|
||||
tree.clear();
|
||||
objects.clear();
|
||||
// create space for the first node
|
||||
tree.push_back(3u << 30u); // dummy leaf
|
||||
tree.insert(tree.end(), 2, 0);
|
||||
}
|
||||
public:
|
||||
BIH() { init_empty(); }
|
||||
template< class BoundsFunc, class PrimArray >
|
||||
void build(const PrimArray &primitives, BoundsFunc &getBounds, uint32 leafSize = 3, bool printStats=false)
|
||||
{
|
||||
if (primitives.size() == 0)
|
||||
{
|
||||
init_empty();
|
||||
return;
|
||||
}
|
||||
|
||||
buildData dat;
|
||||
dat.maxPrims = leafSize;
|
||||
dat.numPrims = primitives.size();
|
||||
dat.indices = new uint32[dat.numPrims];
|
||||
dat.primBound = new G3D::AABox[dat.numPrims];
|
||||
getBounds(primitives[0], bounds);
|
||||
for (uint32 i=0; i<dat.numPrims; ++i)
|
||||
{
|
||||
dat.indices[i] = i;
|
||||
getBounds(primitives[i], dat.primBound[i]);
|
||||
bounds.merge(dat.primBound[i]);
|
||||
}
|
||||
std::vector<uint32> tempTree;
|
||||
BuildStats stats;
|
||||
buildHierarchy(tempTree, dat, stats);
|
||||
if (printStats)
|
||||
stats.printStats();
|
||||
|
||||
objects.resize(dat.numPrims);
|
||||
for (uint32 i=0; i<dat.numPrims; ++i)
|
||||
objects[i] = dat.indices[i];
|
||||
//nObjects = dat.numPrims;
|
||||
tree = tempTree;
|
||||
delete[] dat.primBound;
|
||||
delete[] dat.indices;
|
||||
}
|
||||
uint32 primCount() const { return objects.size(); }
|
||||
|
||||
template<typename RayCallback>
|
||||
void intersectRay(const G3D::Ray &r, RayCallback& intersectCallback, float &maxDist, bool stopAtFirstHit) const
|
||||
{
|
||||
float intervalMin = -1.f;
|
||||
float intervalMax = -1.f;
|
||||
G3D::Vector3 org = r.origin();
|
||||
G3D::Vector3 dir = r.direction();
|
||||
G3D::Vector3 invDir;
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
invDir[i] = 1.f / dir[i];
|
||||
if (G3D::fuzzyNe(dir[i], 0.0f))
|
||||
{
|
||||
float t1 = (bounds.low()[i] - org[i]) * invDir[i];
|
||||
float t2 = (bounds.high()[i] - org[i]) * invDir[i];
|
||||
if (t1 > t2)
|
||||
std::swap(t1, t2);
|
||||
if (t1 > intervalMin)
|
||||
intervalMin = t1;
|
||||
if (t2 < intervalMax || intervalMax < 0.f)
|
||||
intervalMax = t2;
|
||||
// intervalMax can only become smaller for other axis,
|
||||
// and intervalMin only larger respectively, so stop early
|
||||
if (intervalMax <= 0 || intervalMin >= maxDist)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (intervalMin > intervalMax)
|
||||
return;
|
||||
intervalMin = std::max(intervalMin, 0.f);
|
||||
intervalMax = std::min(intervalMax, maxDist);
|
||||
|
||||
uint32 offsetFront[3];
|
||||
uint32 offsetBack[3];
|
||||
uint32 offsetFront3[3];
|
||||
uint32 offsetBack3[3];
|
||||
// compute custom offsets from direction sign bit
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
offsetFront[i] = floatToRawIntBits(dir[i]) >> 31;
|
||||
offsetBack[i] = offsetFront[i] ^ 1;
|
||||
offsetFront3[i] = offsetFront[i] * 3;
|
||||
offsetBack3[i] = offsetBack[i] * 3;
|
||||
|
||||
// avoid always adding 1 during the inner loop
|
||||
++offsetFront[i];
|
||||
++offsetBack[i];
|
||||
}
|
||||
|
||||
StackNode stack[MAX_STACK_SIZE];
|
||||
int stackPos = 0;
|
||||
int node = 0;
|
||||
|
||||
while (true) {
|
||||
while (true)
|
||||
{
|
||||
uint32 tn = tree[node];
|
||||
uint32 axis = (tn & (3 << 30)) >> 30;
|
||||
bool BVH2 = tn & (1 << 29);
|
||||
int offset = tn & ~(7 << 29);
|
||||
if (!BVH2)
|
||||
{
|
||||
if (axis < 3)
|
||||
{
|
||||
// "normal" interior node
|
||||
float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
|
||||
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
|
||||
// ray passes between clip zones
|
||||
if (tf < intervalMin && tb > intervalMax)
|
||||
break;
|
||||
int back = offset + offsetBack3[axis];
|
||||
node = back;
|
||||
// ray passes through far node only
|
||||
if (tf < intervalMin) {
|
||||
intervalMin = (tb >= intervalMin) ? tb : intervalMin;
|
||||
continue;
|
||||
}
|
||||
node = offset + offsetFront3[axis]; // front
|
||||
// ray passes through near node only
|
||||
if (tb > intervalMax) {
|
||||
intervalMax = (tf <= intervalMax) ? tf : intervalMax;
|
||||
continue;
|
||||
}
|
||||
// ray passes through both nodes
|
||||
// push back node
|
||||
stack[stackPos].node = back;
|
||||
stack[stackPos].tnear = (tb >= intervalMin) ? tb : intervalMin;
|
||||
stack[stackPos].tfar = intervalMax;
|
||||
stackPos++;
|
||||
// update ray interval for front node
|
||||
intervalMax = (tf <= intervalMax) ? tf : intervalMax;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// leaf - test some objects
|
||||
int n = tree[node + 1];
|
||||
while (n > 0) {
|
||||
bool hit = intersectCallback(r, objects[offset], maxDist, stopAtFirstHit);
|
||||
if (stopAtFirstHit && hit) return;
|
||||
--n;
|
||||
++offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (axis>2)
|
||||
return; // should not happen
|
||||
float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
|
||||
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
|
||||
node = offset;
|
||||
intervalMin = (tf >= intervalMin) ? tf : intervalMin;
|
||||
intervalMax = (tb <= intervalMax) ? tb : intervalMax;
|
||||
if (intervalMin > intervalMax)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
} // traversal loop
|
||||
do
|
||||
{
|
||||
// stack is empty?
|
||||
if (stackPos == 0)
|
||||
return;
|
||||
// move back up the stack
|
||||
stackPos--;
|
||||
intervalMin = stack[stackPos].tnear;
|
||||
if (maxDist < intervalMin)
|
||||
continue;
|
||||
node = stack[stackPos].node;
|
||||
intervalMax = stack[stackPos].tfar;
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename IsectCallback>
|
||||
void intersectPoint(const G3D::Vector3 &p, IsectCallback& intersectCallback) const
|
||||
{
|
||||
if (!bounds.contains(p))
|
||||
return;
|
||||
|
||||
StackNode stack[MAX_STACK_SIZE];
|
||||
int stackPos = 0;
|
||||
int node = 0;
|
||||
|
||||
while (true) {
|
||||
while (true)
|
||||
{
|
||||
uint32 tn = tree[node];
|
||||
uint32 axis = (tn & (3 << 30)) >> 30;
|
||||
bool BVH2 = tn & (1 << 29);
|
||||
int offset = tn & ~(7 << 29);
|
||||
if (!BVH2)
|
||||
{
|
||||
if (axis < 3)
|
||||
{
|
||||
// "normal" interior node
|
||||
float tl = intBitsToFloat(tree[node + 1]);
|
||||
float tr = intBitsToFloat(tree[node + 2]);
|
||||
// point is between clip zones
|
||||
if (tl < p[axis] && tr > p[axis])
|
||||
break;
|
||||
int right = offset + 3;
|
||||
node = right;
|
||||
// point is in right node only
|
||||
if (tl < p[axis]) {
|
||||
continue;
|
||||
}
|
||||
node = offset; // left
|
||||
// point is in left node only
|
||||
if (tr > p[axis]) {
|
||||
continue;
|
||||
}
|
||||
// point is in both nodes
|
||||
// push back right node
|
||||
stack[stackPos].node = right;
|
||||
stackPos++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// leaf - test some objects
|
||||
int n = tree[node + 1];
|
||||
while (n > 0) {
|
||||
intersectCallback(p, objects[offset]); // !!!
|
||||
--n;
|
||||
++offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // BVH2 node (empty space cut off left and right)
|
||||
{
|
||||
if (axis>2)
|
||||
return; // should not happen
|
||||
float tl = intBitsToFloat(tree[node + 1]);
|
||||
float tr = intBitsToFloat(tree[node + 2]);
|
||||
node = offset;
|
||||
if (tl > p[axis] || tr < p[axis])
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
} // traversal loop
|
||||
|
||||
// stack is empty?
|
||||
if (stackPos == 0)
|
||||
return;
|
||||
// move back up the stack
|
||||
stackPos--;
|
||||
node = stack[stackPos].node;
|
||||
}
|
||||
}
|
||||
|
||||
bool writeToFile(FILE* wf) const;
|
||||
bool readFromFile(FILE* rf);
|
||||
|
||||
protected:
|
||||
std::vector<uint32> tree;
|
||||
std::vector<uint32> objects;
|
||||
G3D::AABox bounds;
|
||||
|
||||
struct buildData
|
||||
{
|
||||
uint32 *indices;
|
||||
G3D::AABox *primBound;
|
||||
uint32 numPrims;
|
||||
int maxPrims;
|
||||
};
|
||||
struct StackNode
|
||||
{
|
||||
uint32 node;
|
||||
float tnear;
|
||||
float tfar;
|
||||
};
|
||||
|
||||
class BuildStats
|
||||
{
|
||||
private:
|
||||
int numNodes;
|
||||
int numLeaves;
|
||||
int sumObjects;
|
||||
int minObjects;
|
||||
int maxObjects;
|
||||
int sumDepth;
|
||||
int minDepth;
|
||||
int maxDepth;
|
||||
int numLeavesN[6];
|
||||
int numBVH2;
|
||||
|
||||
public:
|
||||
BuildStats():
|
||||
numNodes(0), numLeaves(0), sumObjects(0), minObjects(0x0FFFFFFF),
|
||||
maxObjects(0xFFFFFFFF), sumDepth(0), minDepth(0x0FFFFFFF),
|
||||
maxDepth(0xFFFFFFFF), numBVH2(0)
|
||||
{
|
||||
for (int i=0; i<6; ++i) numLeavesN[i] = 0;
|
||||
}
|
||||
|
||||
void updateInner() { numNodes++; }
|
||||
void updateBVH2() { numBVH2++; }
|
||||
void updateLeaf(int depth, int n);
|
||||
void printStats();
|
||||
};
|
||||
|
||||
void buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats);
|
||||
|
||||
void createNode(std::vector<uint32> &tempTree, int nodeIndex, uint32 left, uint32 right) const
|
||||
{
|
||||
// write leaf node
|
||||
tempTree[nodeIndex + 0] = (3 << 30) | left;
|
||||
tempTree[nodeIndex + 1] = right - left + 1;
|
||||
}
|
||||
|
||||
void subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats);
|
||||
};
|
||||
|
||||
#endif // _BIH_H
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _BIH_WRAP
|
||||
#define _BIH_WRAP
|
||||
|
||||
#include "G3D/Table.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/Set.h"
|
||||
#include "BoundingIntervalHierarchy.h"
|
||||
|
||||
|
||||
template<class T, class BoundsFunc = BoundsTrait<T> >
|
||||
class BIHWrap
|
||||
{
|
||||
template<class RayCallback>
|
||||
struct MDLCallback
|
||||
{
|
||||
const T* const* objects;
|
||||
RayCallback& _callback;
|
||||
uint32 objects_size;
|
||||
|
||||
MDLCallback(RayCallback& callback, const T* const* objects_array, uint32 objects_size ) : objects(objects_array), _callback(callback), objects_size(objects_size) { }
|
||||
|
||||
/// Intersect ray
|
||||
bool operator() (const G3D::Ray& ray, uint32 idx, float& maxDist, bool stopAtFirstHit)
|
||||
{
|
||||
if (idx >= objects_size)
|
||||
return false;
|
||||
if (const T* obj = objects[idx])
|
||||
return _callback(ray, *obj, maxDist, stopAtFirstHit);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Intersect point
|
||||
void operator() (const G3D::Vector3& p, uint32 idx)
|
||||
{
|
||||
if (idx >= objects_size)
|
||||
return;
|
||||
if (const T* obj = objects[idx])
|
||||
_callback(p, *obj);
|
||||
}
|
||||
};
|
||||
|
||||
typedef G3D::Array<const T*> ObjArray;
|
||||
|
||||
BIH m_tree;
|
||||
ObjArray m_objects;
|
||||
G3D::Table<const T*, uint32> m_obj2Idx;
|
||||
G3D::Set<const T*> m_objects_to_push;
|
||||
int unbalanced_times;
|
||||
|
||||
public:
|
||||
BIHWrap() : unbalanced_times(0) { }
|
||||
|
||||
void insert(const T& obj)
|
||||
{
|
||||
++unbalanced_times;
|
||||
m_objects_to_push.insert(&obj);
|
||||
}
|
||||
|
||||
void remove(const T& obj)
|
||||
{
|
||||
++unbalanced_times;
|
||||
uint32 Idx = 0;
|
||||
const T * temp;
|
||||
if (m_obj2Idx.getRemove(&obj, temp, Idx))
|
||||
m_objects[Idx] = NULL;
|
||||
else
|
||||
m_objects_to_push.remove(&obj);
|
||||
}
|
||||
|
||||
void balance()
|
||||
{
|
||||
if (unbalanced_times == 0)
|
||||
return;
|
||||
|
||||
unbalanced_times = 0;
|
||||
m_objects.fastClear();
|
||||
m_obj2Idx.getKeys(m_objects);
|
||||
m_objects_to_push.getMembers(m_objects);
|
||||
//assert that m_obj2Idx has all the keys
|
||||
|
||||
m_tree.build(m_objects, BoundsFunc::getBounds2);
|
||||
}
|
||||
|
||||
template<typename RayCallback>
|
||||
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& maxDist, bool stopAtFirstHit)
|
||||
{
|
||||
balance();
|
||||
MDLCallback<RayCallback> temp_cb(intersectCallback, m_objects.getCArray(), m_objects.size());
|
||||
m_tree.intersectRay(ray, temp_cb, maxDist, stopAtFirstHit);
|
||||
}
|
||||
|
||||
template<typename IsectCallback>
|
||||
void intersectPoint(const G3D::Vector3& point, IsectCallback& intersectCallback)
|
||||
{
|
||||
balance();
|
||||
MDLCallback<IsectCallback> callback(intersectCallback, m_objects.getCArray(), m_objects.size());
|
||||
m_tree.intersectPoint(point, callback);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _BIH_WRAP
|
||||
@@ -1,93 +0,0 @@
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
if( USE_COREPCH )
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE sources_Management Management/*.cpp Management/*.h)
|
||||
file(GLOB_RECURSE sources_Maps Maps/*.cpp Maps/*.h)
|
||||
file(GLOB_RECURSE sources_Models Models/*.cpp Models/*.h)
|
||||
file(GLOB sources_localdir *.cpp *.h)
|
||||
|
||||
if (USE_COREPCH)
|
||||
set(collision_STAT_PCH_HDR PrecompiledHeaders/collisionPCH.h)
|
||||
set(collision_STAT_PCH_SRC PrecompiledHeaders/collisionPCH.cpp)
|
||||
endif ()
|
||||
|
||||
set(collision_STAT_SRCS
|
||||
${collision_STAT_SRCS}
|
||||
${sources_Management}
|
||||
${sources_Maps}
|
||||
${sources_Models}
|
||||
${sources_localdir}
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/modules/dep/g3dlite/include
|
||||
${CMAKE_SOURCE_DIR}/modules/dep/recastnavigation/Detour
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Database
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/DataStores
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Addons
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Conditions
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/GameObject
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Creature
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Unit
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Combat
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Loot
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Miscellaneous
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Grids
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Grids/Cells
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Grids/Notifiers
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Maps
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/DataStores
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Movement/Waypoints
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Movement/Spline
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Movement
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Server
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/World
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Spells
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Management
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Maps
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Models
|
||||
${ACE_INCLUDE_DIR}
|
||||
${MYSQL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_library(collision STATIC
|
||||
${collision_STAT_SRCS}
|
||||
${collision_STAT_PCH_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(collision
|
||||
shared
|
||||
)
|
||||
|
||||
# Generate precompiled header
|
||||
if (USE_COREPCH)
|
||||
add_cxx_pch(collision ${collision_STAT_PCH_HDR} ${collision_STAT_PCH_SRC})
|
||||
endif ()
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DynamicTree.h"
|
||||
//#include "QuadTree.h"
|
||||
//#include "RegularGrid.h"
|
||||
#include "BoundingIntervalHierarchyWrapper.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "RegularGrid.h"
|
||||
#include "Timer.h"
|
||||
#include "GameObjectModel.h"
|
||||
#include "ModelInstance.h"
|
||||
|
||||
#include <G3D/AABox.h>
|
||||
#include <G3D/Ray.h>
|
||||
#include <G3D/Vector3.h>
|
||||
|
||||
using VMAP::ModelInstance;
|
||||
|
||||
namespace {
|
||||
|
||||
int CHECK_TREE_PERIOD = 200;
|
||||
|
||||
} // namespace
|
||||
|
||||
template<> struct HashTrait< GameObjectModel>{
|
||||
static size_t hashCode(const GameObjectModel& g) { return (size_t)(void*)&g; }
|
||||
};
|
||||
|
||||
template<> struct PositionTrait< GameObjectModel> {
|
||||
static void getPosition(const GameObjectModel& g, G3D::Vector3& p) { p = g.getPosition(); }
|
||||
};
|
||||
|
||||
template<> struct BoundsTrait< GameObjectModel> {
|
||||
static void getBounds(const GameObjectModel& g, G3D::AABox& out) { out = g.getBounds();}
|
||||
static void getBounds2(const GameObjectModel* g, G3D::AABox& out) { out = g->getBounds();}
|
||||
};
|
||||
|
||||
/*
|
||||
static bool operator == (const GameObjectModel& mdl, const GameObjectModel& mdl2){
|
||||
return &mdl == &mdl2;
|
||||
}
|
||||
*/
|
||||
|
||||
typedef RegularGrid2D<GameObjectModel, BIHWrap<GameObjectModel> > ParentTree;
|
||||
|
||||
struct DynTreeImpl : public ParentTree/*, public Intersectable*/
|
||||
{
|
||||
typedef GameObjectModel Model;
|
||||
typedef ParentTree base;
|
||||
|
||||
DynTreeImpl() :
|
||||
rebalance_timer(CHECK_TREE_PERIOD),
|
||||
unbalanced_times(0)
|
||||
{
|
||||
}
|
||||
|
||||
void insert(const Model& mdl)
|
||||
{
|
||||
base::insert(mdl);
|
||||
++unbalanced_times;
|
||||
}
|
||||
|
||||
void remove(const Model& mdl)
|
||||
{
|
||||
base::remove(mdl);
|
||||
++unbalanced_times;
|
||||
}
|
||||
|
||||
void balance()
|
||||
{
|
||||
base::balance();
|
||||
unbalanced_times = 0;
|
||||
}
|
||||
|
||||
void update(uint32 difftime)
|
||||
{
|
||||
if (!size())
|
||||
return;
|
||||
|
||||
rebalance_timer.Update(difftime);
|
||||
if (rebalance_timer.Passed())
|
||||
{
|
||||
rebalance_timer.Reset(CHECK_TREE_PERIOD);
|
||||
if (unbalanced_times > 0)
|
||||
balance();
|
||||
}
|
||||
}
|
||||
|
||||
TimeTrackerSmall rebalance_timer;
|
||||
int unbalanced_times;
|
||||
};
|
||||
|
||||
DynamicMapTree::DynamicMapTree() : impl(new DynTreeImpl()) { }
|
||||
|
||||
DynamicMapTree::~DynamicMapTree()
|
||||
{
|
||||
delete impl;
|
||||
}
|
||||
|
||||
void DynamicMapTree::insert(const GameObjectModel& mdl)
|
||||
{
|
||||
impl->insert(mdl);
|
||||
}
|
||||
|
||||
void DynamicMapTree::remove(const GameObjectModel& mdl)
|
||||
{
|
||||
impl->remove(mdl);
|
||||
}
|
||||
|
||||
bool DynamicMapTree::contains(const GameObjectModel& mdl) const
|
||||
{
|
||||
return impl->contains(mdl);
|
||||
}
|
||||
|
||||
void DynamicMapTree::balance()
|
||||
{
|
||||
impl->balance();
|
||||
}
|
||||
|
||||
int DynamicMapTree::size() const
|
||||
{
|
||||
return impl->size();
|
||||
}
|
||||
|
||||
void DynamicMapTree::update(uint32 t_diff)
|
||||
{
|
||||
impl->update(t_diff);
|
||||
}
|
||||
|
||||
struct DynamicTreeIntersectionCallback
|
||||
{
|
||||
bool did_hit;
|
||||
uint32 phase_mask;
|
||||
DynamicTreeIntersectionCallback(uint32 phasemask) : did_hit(false), phase_mask(phasemask) { }
|
||||
bool operator()(const G3D::Ray& r, const GameObjectModel& obj, float& distance, bool stopAtFirstHit)
|
||||
{
|
||||
bool result = obj.intersectRay(r, distance, stopAtFirstHit, phase_mask);
|
||||
if (result)
|
||||
did_hit = result;
|
||||
return result;
|
||||
}
|
||||
bool didHit() const { return did_hit;}
|
||||
};
|
||||
|
||||
bool DynamicMapTree::getIntersectionTime(const uint32 phasemask, const G3D::Ray& ray,
|
||||
const G3D::Vector3& endPos, float& maxDist) const
|
||||
{
|
||||
float distance = maxDist;
|
||||
DynamicTreeIntersectionCallback callback(phasemask);
|
||||
impl->intersectRay(ray, callback, distance, endPos, false);
|
||||
if (callback.didHit())
|
||||
maxDist = distance;
|
||||
return callback.didHit();
|
||||
}
|
||||
|
||||
bool DynamicMapTree::getObjectHitPos(const uint32 phasemask, const G3D::Vector3& startPos,
|
||||
const G3D::Vector3& endPos, G3D::Vector3& resultHit,
|
||||
float modifyDist) const
|
||||
{
|
||||
bool result = false;
|
||||
float maxDist = (endPos - startPos).magnitude();
|
||||
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too
|
||||
ASSERT(maxDist < std::numeric_limits<float>::max());
|
||||
// prevent NaN values which can cause BIH intersection to enter infinite loop
|
||||
if (maxDist < 1e-10f)
|
||||
{
|
||||
resultHit = endPos;
|
||||
return false;
|
||||
}
|
||||
G3D::Vector3 dir = (endPos - startPos)/maxDist; // direction with length of 1
|
||||
G3D::Ray ray(startPos, dir);
|
||||
float dist = maxDist;
|
||||
if (getIntersectionTime(phasemask, ray, endPos, dist))
|
||||
{
|
||||
resultHit = startPos + dir * dist;
|
||||
if (modifyDist < 0)
|
||||
{
|
||||
if ((resultHit - startPos).magnitude() > -modifyDist)
|
||||
resultHit = resultHit + dir*modifyDist;
|
||||
else
|
||||
resultHit = startPos;
|
||||
}
|
||||
else
|
||||
resultHit = resultHit + dir*modifyDist;
|
||||
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultHit = endPos;
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DynamicMapTree::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const
|
||||
{
|
||||
G3D::Vector3 v1(x1, y1, z1), v2(x2, y2, z2);
|
||||
|
||||
float maxDist = (v2 - v1).magnitude();
|
||||
|
||||
if (!G3D::fuzzyGt(maxDist, 0) )
|
||||
return true;
|
||||
|
||||
G3D::Ray r(v1, (v2-v1) / maxDist);
|
||||
DynamicTreeIntersectionCallback callback(phasemask);
|
||||
impl->intersectRay(r, callback, maxDist, v2, true);
|
||||
|
||||
return !callback.did_hit;
|
||||
}
|
||||
|
||||
float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const
|
||||
{
|
||||
G3D::Vector3 v(x, y, z + 2.0f);
|
||||
G3D::Ray r(v, G3D::Vector3(0, 0, -1));
|
||||
DynamicTreeIntersectionCallback callback(phasemask);
|
||||
impl->intersectZAllignedRay(r, callback, maxSearchDist);
|
||||
|
||||
if (callback.didHit())
|
||||
return v.z - maxSearchDist;
|
||||
else
|
||||
return -G3D::inf();
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) MaNGOS, TrinityCore, SunwellCore and AzerothCore
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _DYNTREE_H
|
||||
#define _DYNTREE_H
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
namespace G3D
|
||||
{
|
||||
class Ray;
|
||||
class Vector3;
|
||||
}
|
||||
|
||||
class GameObjectModel;
|
||||
struct DynTreeImpl;
|
||||
|
||||
class DynamicMapTree
|
||||
{
|
||||
DynTreeImpl *impl;
|
||||
|
||||
public:
|
||||
|
||||
DynamicMapTree();
|
||||
~DynamicMapTree();
|
||||
|
||||
bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2,
|
||||
float z2, uint32 phasemask) const;
|
||||
|
||||
bool getIntersectionTime(uint32 phasemask, const G3D::Ray& ray,
|
||||
const G3D::Vector3& endPos, float& maxDist) const;
|
||||
|
||||
bool getObjectHitPos(uint32 phasemask, const G3D::Vector3& pPos1,
|
||||
const G3D::Vector3& pPos2, G3D::Vector3& pResultHitPos,
|
||||
float pModifyDist) const;
|
||||
|
||||
float getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const;
|
||||
|
||||
void insert(const GameObjectModel&);
|
||||
void remove(const GameObjectModel&);
|
||||
bool contains(const GameObjectModel&) const;
|
||||
int size() const;
|
||||
|
||||
void balance();
|
||||
void update(uint32 diff);
|
||||
};
|
||||
|
||||
#endif // _DYNTREE_H
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _IMMAPMANAGER_H
|
||||
#define _IMMAPMANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include "Define.h"
|
||||
|
||||
// Interface for IMMapManger
|
||||
namespace MMAP
|
||||
{
|
||||
enum MMAP_LOAD_RESULT
|
||||
{
|
||||
MMAP_LOAD_RESULT_ERROR,
|
||||
MMAP_LOAD_RESULT_OK,
|
||||
MMAP_LOAD_RESULT_IGNORED,
|
||||
};
|
||||
|
||||
class IMMapManager
|
||||
{
|
||||
private:
|
||||
bool iEnablePathFinding;
|
||||
|
||||
public:
|
||||
IMMapManager() : iEnablePathFinding(true) {}
|
||||
virtual ~IMMapManager(void) {}
|
||||
|
||||
//Enabled/Disabled Pathfinding
|
||||
void setEnablePathFinding(bool value) { iEnablePathFinding = value; }
|
||||
bool isEnablePathFinding() const { return (iEnablePathFinding); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _IVMAPMANAGER_H
|
||||
#define _IVMAPMANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include "Define.h"
|
||||
|
||||
//===========================================================
|
||||
|
||||
/**
|
||||
This is the minimum interface to the VMapMamager.
|
||||
*/
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
|
||||
enum VMAP_LOAD_RESULT
|
||||
{
|
||||
VMAP_LOAD_RESULT_ERROR,
|
||||
VMAP_LOAD_RESULT_OK,
|
||||
VMAP_LOAD_RESULT_IGNORED
|
||||
};
|
||||
|
||||
#define VMAP_INVALID_HEIGHT -100000.0f // for check
|
||||
#define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case
|
||||
|
||||
//===========================================================
|
||||
class IVMapManager
|
||||
{
|
||||
private:
|
||||
bool iEnableLineOfSightCalc;
|
||||
bool iEnableHeightCalc;
|
||||
|
||||
public:
|
||||
IVMapManager() : iEnableLineOfSightCalc(true), iEnableHeightCalc(true) { }
|
||||
|
||||
virtual ~IVMapManager(void) { }
|
||||
|
||||
virtual int loadMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
|
||||
|
||||
virtual bool existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
|
||||
|
||||
virtual void unloadMap(unsigned int pMapId, int x, int y) = 0;
|
||||
virtual void unloadMap(unsigned int pMapId) = 0;
|
||||
|
||||
virtual bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) = 0;
|
||||
virtual float getHeight(unsigned int pMapId, float x, float y, float z, float maxSearchDist) = 0;
|
||||
/**
|
||||
test if we hit an object. return true if we hit one. rx, ry, rz will hold the hit position or the dest position, if no intersection was found
|
||||
return a position, that is pReduceDist closer to the origin
|
||||
*/
|
||||
virtual bool getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist) = 0;
|
||||
/**
|
||||
send debug commands
|
||||
*/
|
||||
virtual bool processCommand(char *pCommand)= 0;
|
||||
|
||||
/**
|
||||
Enable/disable LOS calculation
|
||||
It is enabled by default. If it is enabled in mid game the maps have to loaded manualy
|
||||
*/
|
||||
void setEnableLineOfSightCalc(bool pVal) { iEnableLineOfSightCalc = pVal; }
|
||||
/**
|
||||
Enable/disable model height calculation
|
||||
It is enabled by default. If it is enabled in mid game the maps have to loaded manualy
|
||||
*/
|
||||
void setEnableHeightCalc(bool pVal) { iEnableHeightCalc = pVal; }
|
||||
|
||||
bool isLineOfSightCalcEnabled() const { return(iEnableLineOfSightCalc); }
|
||||
bool isHeightCalcEnabled() const { return(iEnableHeightCalc); }
|
||||
bool isMapLoadingEnabled() const { return(iEnableLineOfSightCalc || iEnableHeightCalc ); }
|
||||
|
||||
virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const =0;
|
||||
/**
|
||||
Query world model area info.
|
||||
\param z gets adjusted to the ground height for which this are info is valid
|
||||
*/
|
||||
virtual bool getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const=0;
|
||||
virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const=0;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MMapFactory.h"
|
||||
#include "World.h"
|
||||
#include <set>
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
// ######################## MMapFactory ########################
|
||||
// our global singleton copy
|
||||
MMapManager *g_MMapManager = NULL;
|
||||
bool MMapFactory::forbiddenMaps[1000] = {0};
|
||||
|
||||
MMapManager* MMapFactory::createOrGetMMapManager()
|
||||
{
|
||||
if (g_MMapManager == NULL)
|
||||
g_MMapManager = new MMapManager();
|
||||
|
||||
return g_MMapManager;
|
||||
}
|
||||
|
||||
bool MMapFactory::IsPathfindingEnabled(const Map* map, bool force)
|
||||
{
|
||||
if (!map) return false;
|
||||
return !forbiddenMaps[map->GetId()] && (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena());
|
||||
}
|
||||
|
||||
void MMapFactory::InitializeDisabledMaps()
|
||||
{
|
||||
memset(&forbiddenMaps, 0, sizeof(forbiddenMaps));
|
||||
int32 f[] = {616 /*EoE*/, 649 /*ToC25*/, 650 /*ToC5*/, -1};
|
||||
uint32 i = 0;
|
||||
while (f[i] >= 0)
|
||||
forbiddenMaps[f[i++]] = true;
|
||||
}
|
||||
|
||||
void MMapFactory::clear()
|
||||
{
|
||||
if (g_MMapManager)
|
||||
{
|
||||
delete g_MMapManager;
|
||||
g_MMapManager = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MMAP_FACTORY_H
|
||||
#define _MMAP_FACTORY_H
|
||||
|
||||
#include "MMapManager.h"
|
||||
#include "UnorderedMap.h"
|
||||
#include "DetourAlloc.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourNavMeshQuery.h"
|
||||
#include "Map.h"
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
enum MMAP_LOAD_RESULT
|
||||
{
|
||||
MMAP_LOAD_RESULT_ERROR,
|
||||
MMAP_LOAD_RESULT_OK,
|
||||
MMAP_LOAD_RESULT_IGNORED,
|
||||
};
|
||||
|
||||
// static class
|
||||
// holds all mmap global data
|
||||
// access point to MMapManager singleton
|
||||
class MMapFactory
|
||||
{
|
||||
public:
|
||||
static MMapManager* createOrGetMMapManager();
|
||||
static void clear();
|
||||
static bool IsPathfindingEnabled(const Map* map, bool force = false);
|
||||
static void InitializeDisabledMaps();
|
||||
static bool forbiddenMaps[1000];
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,356 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MapManager.h"
|
||||
#include "MMapManager.h"
|
||||
#include "Log.h"
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
// ######################## MMapManager ########################
|
||||
MMapManager::~MMapManager()
|
||||
{
|
||||
for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i)
|
||||
delete i->second;
|
||||
|
||||
// by now we should not have maps loaded
|
||||
// if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
|
||||
}
|
||||
|
||||
bool MMapManager::loadMapData(uint32 mapId)
|
||||
{
|
||||
// we already have this map loaded?
|
||||
if (loadedMMaps.find(mapId) != loadedMMaps.end())
|
||||
return true;
|
||||
|
||||
// load and init dtNavMesh - read parameters from file
|
||||
uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap")+1;
|
||||
char *fileName = new char[pathLen];
|
||||
snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i.mmap").c_str(), mapId);
|
||||
|
||||
FILE* file = fopen(fileName, "rb");
|
||||
if (!file)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName);
|
||||
delete [] fileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
dtNavMeshParams params;
|
||||
int count = fread(¶ms, sizeof(dtNavMeshParams), 1, file);
|
||||
fclose(file);
|
||||
if (count != 1)
|
||||
{
|
||||
;//TC_LOG_DEBUG(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName);
|
||||
delete [] fileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
dtNavMesh* mesh = dtAllocNavMesh();
|
||||
ASSERT(mesh);
|
||||
if (DT_SUCCESS != mesh->init(¶ms))
|
||||
{
|
||||
dtFreeNavMesh(mesh);
|
||||
sLog->outError("MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName);
|
||||
delete [] fileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete [] fileName;
|
||||
|
||||
;//sLog->outDetail("MMAP:loadMapData: Loaded %03i.mmap", mapId);
|
||||
|
||||
// store inside our map list
|
||||
MMapData* mmap_data = new MMapData(mesh);
|
||||
mmap_data->mmapLoadedTiles.clear();
|
||||
|
||||
loadedMMaps.insert(std::pair<uint32, MMapData*>(mapId, mmap_data));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 MMapManager::packTileID(int32 x, int32 y)
|
||||
{
|
||||
return uint32(x << 16 | y);
|
||||
}
|
||||
|
||||
ACE_RW_Thread_Mutex& MMapManager::GetMMapLock(uint32 mapId)
|
||||
{
|
||||
Map* map = sMapMgr->FindBaseMap(mapId);
|
||||
if (!map)
|
||||
{
|
||||
sLog->outMisc("ZOMG! MoveMaps: BaseMap not found!");
|
||||
return this->MMapLock;
|
||||
}
|
||||
return map->GetMMapLock();
|
||||
}
|
||||
|
||||
bool MMapManager::loadMap(uint32 mapId, int32 x, int32 y)
|
||||
{
|
||||
TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, MMapManagerLock);
|
||||
|
||||
// make sure the mmap is loaded and ready to load tiles
|
||||
if(!loadMapData(mapId))
|
||||
return false;
|
||||
|
||||
// get this mmap data
|
||||
MMapData* mmap = loadedMMaps[mapId];
|
||||
ASSERT(mmap->navMesh);
|
||||
|
||||
// check if we already have this tile loaded
|
||||
uint32 packedGridPos = packTileID(x, y);
|
||||
if (mmap->mmapLoadedTiles.find(packedGridPos) != mmap->mmapLoadedTiles.end())
|
||||
{
|
||||
sLog->outError("MMAP:loadMap: Asked to load already loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
|
||||
return false;
|
||||
}
|
||||
|
||||
// load this tile :: mmaps/MMMXXYY.mmtile
|
||||
uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile")+1;
|
||||
char *fileName = new char[pathLen];
|
||||
snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y);
|
||||
|
||||
FILE *file = fopen(fileName, "rb");
|
||||
if (!file)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMap: Could not open mmtile file '%s'", fileName);
|
||||
delete [] fileName;
|
||||
return false;
|
||||
}
|
||||
delete [] fileName;
|
||||
|
||||
// read header
|
||||
MmapTileHeader fileHeader;
|
||||
if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC)
|
||||
{
|
||||
sLog->outError("MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y);
|
||||
fclose(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileHeader.mmapVersion != MMAP_VERSION)
|
||||
{
|
||||
sLog->outError("MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i",
|
||||
mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION);
|
||||
fclose(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char* data = (unsigned char*)dtAlloc(fileHeader.size, DT_ALLOC_PERM);
|
||||
ASSERT(data);
|
||||
|
||||
size_t result = fread(data, fileHeader.size, 1, file);
|
||||
if(!result)
|
||||
{
|
||||
sLog->outError("MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y);
|
||||
fclose(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
dtMeshHeader* header = (dtMeshHeader*)data;
|
||||
dtTileRef tileRef = 0;
|
||||
|
||||
dtStatus stat;
|
||||
{
|
||||
TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetMMapLock(mapId));
|
||||
stat = mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef);
|
||||
}
|
||||
|
||||
// memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
|
||||
if (stat == DT_SUCCESS)
|
||||
{
|
||||
mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
|
||||
++loadedTiles;
|
||||
;//sLog->outDetail("MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog->outError("MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y);
|
||||
dtFree(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y)
|
||||
{
|
||||
TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, MMapManagerLock);
|
||||
|
||||
// check if we have this map loaded
|
||||
if (loadedMMaps.find(mapId) == loadedMMaps.end())
|
||||
{
|
||||
// file may not exist, therefore not loaded
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y);
|
||||
return false;
|
||||
}
|
||||
|
||||
MMapData* mmap = loadedMMaps[mapId];
|
||||
|
||||
// check if we have this tile loaded
|
||||
uint32 packedGridPos = packTileID(x, y);
|
||||
if (mmap->mmapLoadedTiles.find(packedGridPos) == mmap->mmapLoadedTiles.end())
|
||||
{
|
||||
// file may not exist, therefore not loaded
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
|
||||
return false;
|
||||
}
|
||||
|
||||
dtTileRef tileRef = mmap->mmapLoadedTiles[packedGridPos];
|
||||
|
||||
dtStatus status;
|
||||
{
|
||||
TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetMMapLock(mapId));
|
||||
status = mmap->navMesh->removeTile(tileRef, NULL, NULL);
|
||||
}
|
||||
|
||||
// unload, and mark as non loaded
|
||||
if (status != DT_SUCCESS)
|
||||
{
|
||||
// this is technically a memory leak
|
||||
// if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
|
||||
// we cannot recover from this error - assert out
|
||||
sLog->outError("MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
|
||||
ASSERT(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mmap->mmapLoadedTiles.erase(packedGridPos);
|
||||
--loadedTiles;
|
||||
;//sLog->outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MMapManager::unloadMap(uint32 mapId)
|
||||
{
|
||||
TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, MMapManagerLock);
|
||||
|
||||
if (loadedMMaps.find(mapId) == loadedMMaps.end())
|
||||
{
|
||||
// file may not exist, therefore not loaded
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// unload all tiles from given map
|
||||
MMapData* mmap = loadedMMaps[mapId];
|
||||
for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i)
|
||||
{
|
||||
uint32 x = (i->first >> 16);
|
||||
uint32 y = (i->first & 0x0000FFFF);
|
||||
|
||||
dtStatus status;
|
||||
{
|
||||
TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetMMapLock(mapId));
|
||||
status = mmap->navMesh->removeTile(i->second, NULL, NULL);
|
||||
}
|
||||
|
||||
if (status != DT_SUCCESS)
|
||||
sLog->outError("MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
|
||||
else
|
||||
{
|
||||
--loadedTiles;
|
||||
;//sLog->outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
|
||||
}
|
||||
}
|
||||
|
||||
delete mmap;
|
||||
loadedMMaps.erase(mapId);
|
||||
;//sLog->outDetail("MMAP:unloadMap: Unloaded %03i.mmap", mapId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId)
|
||||
{
|
||||
TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, MMapManagerLock);
|
||||
|
||||
// check if we have this map loaded
|
||||
if (loadedMMaps.find(mapId) == loadedMMaps.end())
|
||||
{
|
||||
// file may not exist, therefore not loaded
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId);
|
||||
return false;
|
||||
}
|
||||
|
||||
MMapData* mmap = loadedMMaps[mapId];
|
||||
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId);
|
||||
return false;
|
||||
}
|
||||
|
||||
dtNavMeshQuery* query = mmap->navMeshQueries[instanceId];
|
||||
|
||||
dtFreeNavMeshQuery(query);
|
||||
mmap->navMeshQueries.erase(instanceId);
|
||||
;//sLog->outDetail("MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
|
||||
{
|
||||
// pussywizard: moved to calling function
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, MMapManagerLock);
|
||||
|
||||
if (loadedMMaps.find(mapId) == loadedMMaps.end())
|
||||
return NULL;
|
||||
|
||||
return loadedMMaps[mapId]->navMesh;
|
||||
}
|
||||
|
||||
dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId)
|
||||
{
|
||||
// pussywizard: moved to calling function
|
||||
//TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, MMapManagerLock);
|
||||
|
||||
if (loadedMMaps.find(mapId) == loadedMMaps.end())
|
||||
return NULL;
|
||||
|
||||
MMapData* mmap = loadedMMaps[mapId];
|
||||
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
|
||||
{
|
||||
// pussywizard: different instances of the same map shouldn't access this simultaneously
|
||||
TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetMMapLock(mapId));
|
||||
// check again after acquiring mutex
|
||||
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
|
||||
{
|
||||
// allocate mesh query
|
||||
dtNavMeshQuery* query = dtAllocNavMeshQuery();
|
||||
ASSERT(query);
|
||||
if (DT_SUCCESS != query->init(mmap->navMesh, 1024))
|
||||
{
|
||||
dtFreeNavMeshQuery(query);
|
||||
sLog->outError("MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
;//sLog->outDetail("MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
|
||||
mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
|
||||
}
|
||||
}
|
||||
|
||||
return mmap->navMeshQueries[instanceId];
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MMAP_MANAGER_H
|
||||
#define _MMAP_MANAGER_H
|
||||
|
||||
#include "UnorderedMap.h"
|
||||
#include "DetourAlloc.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourNavMeshQuery.h"
|
||||
#include "World.h"
|
||||
|
||||
// memory management
|
||||
inline void* dtCustomAlloc(int size, dtAllocHint /*hint*/)
|
||||
{
|
||||
return (void*)new unsigned char[size];
|
||||
}
|
||||
|
||||
inline void dtCustomFree(void* ptr)
|
||||
{
|
||||
delete [] (unsigned char*)ptr;
|
||||
}
|
||||
|
||||
// move map related classes
|
||||
namespace MMAP
|
||||
{
|
||||
typedef UNORDERED_MAP<uint32, dtTileRef> MMapTileSet;
|
||||
typedef UNORDERED_MAP<uint32, dtNavMeshQuery*> NavMeshQuerySet;
|
||||
|
||||
// dummy struct to hold map's mmap data
|
||||
struct MMapData
|
||||
{
|
||||
MMapData(dtNavMesh* mesh) : navMesh(mesh) {}
|
||||
~MMapData()
|
||||
{
|
||||
for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i)
|
||||
dtFreeNavMeshQuery(i->second);
|
||||
|
||||
if (navMesh)
|
||||
dtFreeNavMesh(navMesh);
|
||||
}
|
||||
|
||||
dtNavMesh* navMesh;
|
||||
|
||||
// we have to use single dtNavMeshQuery for every instance, since those are not thread safe
|
||||
NavMeshQuerySet navMeshQueries; // instanceId to query
|
||||
MMapTileSet mmapLoadedTiles; // maps [map grid coords] to [dtTile]
|
||||
};
|
||||
|
||||
|
||||
typedef UNORDERED_MAP<uint32, MMapData*> MMapDataSet;
|
||||
|
||||
// singleton class
|
||||
// holds all all access to mmap loading unloading and meshes
|
||||
class MMapManager
|
||||
{
|
||||
public:
|
||||
MMapManager() : loadedTiles(0) {}
|
||||
~MMapManager();
|
||||
|
||||
bool loadMap(uint32 mapId, int32 x, int32 y);
|
||||
bool unloadMap(uint32 mapId, int32 x, int32 y);
|
||||
bool unloadMap(uint32 mapId);
|
||||
bool unloadMapInstance(uint32 mapId, uint32 instanceId);
|
||||
|
||||
// the returned [dtNavMeshQuery const*] is NOT threadsafe
|
||||
dtNavMeshQuery const* GetNavMeshQuery(uint32 mapId, uint32 instanceId);
|
||||
dtNavMesh const* GetNavMesh(uint32 mapId);
|
||||
|
||||
uint32 getLoadedTilesCount() const { return loadedTiles; }
|
||||
uint32 getLoadedMapsCount() const { return loadedMMaps.size(); }
|
||||
|
||||
ACE_RW_Thread_Mutex& GetMMapLock(uint32 mapId);
|
||||
ACE_RW_Thread_Mutex& GetMMapGeneralLock() { return MMapLock; } // pussywizard: in case a per-map mutex can't be found, should never happen
|
||||
ACE_RW_Thread_Mutex& GetManagerLock() { return MMapManagerLock; }
|
||||
private:
|
||||
bool loadMapData(uint32 mapId);
|
||||
uint32 packTileID(int32 x, int32 y);
|
||||
|
||||
MMapDataSet loadedMMaps;
|
||||
uint32 loadedTiles;
|
||||
|
||||
ACE_RW_Thread_Mutex MMapManagerLock;
|
||||
ACE_RW_Thread_Mutex MMapLock; // pussywizard: in case a per-map mutex can't be found, should never happen
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VMapFactory.h"
|
||||
#include "VMapManager2.h"
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
IVMapManager* gVMapManager = NULL;
|
||||
|
||||
//===============================================
|
||||
// just return the instance
|
||||
IVMapManager* VMapFactory::createOrGetVMapManager()
|
||||
{
|
||||
if (gVMapManager == 0)
|
||||
gVMapManager= new VMapManager2(); // should be taken from config ... Please change if you like :-)
|
||||
return gVMapManager;
|
||||
}
|
||||
|
||||
//===============================================
|
||||
// delete all internal data structures
|
||||
void VMapFactory::clear()
|
||||
{
|
||||
delete gVMapManager;
|
||||
gVMapManager = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _VMAPFACTORY_H
|
||||
#define _VMAPFACTORY_H
|
||||
|
||||
#include "IVMapManager.h"
|
||||
|
||||
/**
|
||||
This is the access point to the VMapManager.
|
||||
*/
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
//===========================================================
|
||||
|
||||
class VMapFactory
|
||||
{
|
||||
public:
|
||||
static IVMapManager* createOrGetVMapManager();
|
||||
static void clear();
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "VMapManager2.h"
|
||||
#include "MapTree.h"
|
||||
#include "ModelInstance.h"
|
||||
#include "WorldModel.h"
|
||||
#include <G3D/Vector3.h>
|
||||
#include <ace/Null_Mutex.h>
|
||||
#include <ace/Singleton.h>
|
||||
#include "DisableMgr.h"
|
||||
#include "DBCStores.h"
|
||||
#include "Log.h"
|
||||
#include "VMapDefinitions.h"
|
||||
|
||||
using G3D::Vector3;
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
VMapManager2::VMapManager2()
|
||||
{
|
||||
}
|
||||
|
||||
VMapManager2::~VMapManager2(void)
|
||||
{
|
||||
for (InstanceTreeMap::iterator i = iInstanceMapTrees.begin(); i != iInstanceMapTrees.end(); ++i)
|
||||
{
|
||||
delete i->second;
|
||||
}
|
||||
for (ModelFileMap::iterator i = iLoadedModelFiles.begin(); i != iLoadedModelFiles.end(); ++i)
|
||||
{
|
||||
delete i->second.getModel();
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 VMapManager2::convertPositionToInternalRep(float x, float y, float z) const
|
||||
{
|
||||
Vector3 pos;
|
||||
const float mid = 0.5f * 64.0f * 533.33333333f;
|
||||
pos.x = mid - x;
|
||||
pos.y = mid - y;
|
||||
pos.z = z;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
// move to MapTree too?
|
||||
std::string VMapManager2::getMapFileName(unsigned int mapId)
|
||||
{
|
||||
std::stringstream fname;
|
||||
fname.width(3);
|
||||
fname << std::setfill('0') << mapId << std::string(MAP_FILENAME_EXTENSION2);
|
||||
|
||||
return fname.str();
|
||||
}
|
||||
|
||||
int VMapManager2::loadMap(const char* basePath, unsigned int mapId, int x, int y)
|
||||
{
|
||||
int result = VMAP_LOAD_RESULT_IGNORED;
|
||||
if (isMapLoadingEnabled())
|
||||
{
|
||||
if (_loadMap(mapId, basePath, x, y))
|
||||
result = VMAP_LOAD_RESULT_OK;
|
||||
else
|
||||
result = VMAP_LOAD_RESULT_ERROR;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// load one tile (internal use only)
|
||||
bool VMapManager2::_loadMap(unsigned int mapId, const std::string& basePath, uint32 tileX, uint32 tileY)
|
||||
{
|
||||
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
|
||||
if (instanceTree == iInstanceMapTrees.end())
|
||||
{
|
||||
std::string mapFileName = getMapFileName(mapId);
|
||||
StaticMapTree* newTree = new StaticMapTree(mapId, basePath);
|
||||
if (!newTree->InitMap(mapFileName, this))
|
||||
{
|
||||
delete newTree;
|
||||
return false;
|
||||
}
|
||||
instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, newTree)).first;
|
||||
}
|
||||
|
||||
return instanceTree->second->LoadMapTile(tileX, tileY, this);
|
||||
}
|
||||
|
||||
void VMapManager2::unloadMap(unsigned int mapId)
|
||||
{
|
||||
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
|
||||
if (instanceTree != iInstanceMapTrees.end())
|
||||
{
|
||||
instanceTree->second->UnloadMap(this);
|
||||
if (instanceTree->second->numLoadedTiles() == 0)
|
||||
{
|
||||
delete instanceTree->second;
|
||||
iInstanceMapTrees.erase(mapId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VMapManager2::unloadMap(unsigned int mapId, int x, int y)
|
||||
{
|
||||
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
|
||||
if (instanceTree != iInstanceMapTrees.end())
|
||||
{
|
||||
instanceTree->second->UnloadMapTile(x, y, this);
|
||||
if (instanceTree->second->numLoadedTiles() == 0)
|
||||
{
|
||||
delete instanceTree->second;
|
||||
iInstanceMapTrees.erase(mapId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VMapManager2::isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2)
|
||||
{
|
||||
//if (!isLineOfSightCalcEnabled() || DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, NULL, VMAP_DISABLE_LOS)) // pussywizard: optimization
|
||||
// return true;
|
||||
|
||||
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
|
||||
if (instanceTree != iInstanceMapTrees.end())
|
||||
{
|
||||
Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1);
|
||||
Vector3 pos2 = convertPositionToInternalRep(x2, y2, z2);
|
||||
if (pos1 != pos2)
|
||||
{
|
||||
return instanceTree->second->isInLineOfSight(pos1, pos2);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
get the hit position and return true if we hit something
|
||||
otherwise the result pos will be the dest pos
|
||||
*/
|
||||
bool VMapManager2::getObjectHitPos(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist)
|
||||
{
|
||||
//if (isLineOfSightCalcEnabled() && !DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, NULL, VMAP_DISABLE_LOS)) // pussywizard: optimization
|
||||
{
|
||||
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
|
||||
if (instanceTree != iInstanceMapTrees.end())
|
||||
{
|
||||
Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1);
|
||||
Vector3 pos2 = convertPositionToInternalRep(x2, y2, z2);
|
||||
Vector3 resultPos;
|
||||
bool result = instanceTree->second->getObjectHitPos(pos1, pos2, resultPos, modifyDist);
|
||||
resultPos = convertPositionToInternalRep(resultPos.x, resultPos.y, resultPos.z);
|
||||
rx = resultPos.x;
|
||||
ry = resultPos.y;
|
||||
rz = resultPos.z;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
rx = x2;
|
||||
ry = y2;
|
||||
rz = z2;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
get height or INVALID_HEIGHT if no height available
|
||||
*/
|
||||
|
||||
float VMapManager2::getHeight(unsigned int mapId, float x, float y, float z, float maxSearchDist)
|
||||
{
|
||||
//if (isHeightCalcEnabled() && !DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, NULL, VMAP_DISABLE_HEIGHT)) // pussywizard: optimization
|
||||
{
|
||||
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
|
||||
if (instanceTree != iInstanceMapTrees.end())
|
||||
{
|
||||
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
||||
float height = instanceTree->second->getHeight(pos, maxSearchDist);
|
||||
if (!(height < G3D::inf()))
|
||||
return height = VMAP_INVALID_HEIGHT_VALUE; // No height
|
||||
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
return VMAP_INVALID_HEIGHT_VALUE;
|
||||
}
|
||||
|
||||
bool VMapManager2::getAreaInfo(unsigned int mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||
{
|
||||
//if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, NULL, VMAP_DISABLE_AREAFLAG)) // pussywizard: optimization
|
||||
{
|
||||
InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(mapId);
|
||||
if (instanceTree != iInstanceMapTrees.end())
|
||||
{
|
||||
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
||||
bool result = instanceTree->second->getAreaInfo(pos, flags, adtId, rootId, groupId);
|
||||
// z is not touched by convertPositionToInternalRep(), so just copy
|
||||
z = pos.z;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VMapManager2::GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const
|
||||
{
|
||||
//if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, NULL, VMAP_DISABLE_LIQUIDSTATUS)) // pussywizard: optimization
|
||||
{
|
||||
InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(mapId);
|
||||
if (instanceTree != iInstanceMapTrees.end())
|
||||
{
|
||||
LocationInfo info;
|
||||
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
||||
if (instanceTree->second->GetLocationInfo(pos, info))
|
||||
{
|
||||
floor = info.ground_Z;
|
||||
ASSERT(floor < std::numeric_limits<float>::max());
|
||||
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
|
||||
if (reqLiquidType && !(GetLiquidFlags(type) & reqLiquidType))
|
||||
return false;
|
||||
if (info.hitInstance->GetLiquidLevel(pos, info, level))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename)
|
||||
{
|
||||
//! Critical section, thread safe access to iLoadedModelFiles
|
||||
TRINITY_GUARD(ACE_Thread_Mutex, LoadedModelFilesLock);
|
||||
|
||||
ModelFileMap::iterator model = iLoadedModelFiles.find(filename);
|
||||
if (model == iLoadedModelFiles.end())
|
||||
{
|
||||
WorldModel* worldmodel = new WorldModel();
|
||||
if (!worldmodel->readFile(basepath + filename + ".vmo"))
|
||||
{
|
||||
sLog->outError("VMapManager2: could not load '%s%s.vmo'", basepath.c_str(), filename.c_str());
|
||||
delete worldmodel;
|
||||
return NULL;
|
||||
}
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str());
|
||||
model = iLoadedModelFiles.insert(std::pair<std::string, ManagedModel>(filename, ManagedModel())).first;
|
||||
model->second.setModel(worldmodel);
|
||||
}
|
||||
//model->second.incRefCount();
|
||||
return model->second.getModel();
|
||||
}
|
||||
|
||||
void VMapManager2::releaseModelInstance(const std::string &filename)
|
||||
{
|
||||
/*//! Critical section, thread safe access to iLoadedModelFiles
|
||||
TRINITY_GUARD(ACE_Thread_Mutex, LoadedModelFilesLock);
|
||||
|
||||
ModelFileMap::iterator model = iLoadedModelFiles.find(filename);
|
||||
if (model == iLoadedModelFiles.end())
|
||||
{
|
||||
sLog->outError("VMapManager2: trying to unload non-loaded file '%s'", filename.c_str());
|
||||
return;
|
||||
}
|
||||
if (model->second.decRefCount() == 0)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "VMapManager2: unloading file '%s'", filename.c_str());
|
||||
delete model->second.getModel();
|
||||
iLoadedModelFiles.erase(model);
|
||||
}*/
|
||||
}
|
||||
|
||||
bool VMapManager2::existsMap(const char* basePath, unsigned int mapId, int x, int y)
|
||||
{
|
||||
return StaticMapTree::CanLoadMap(std::string(basePath), mapId, x, y);
|
||||
}
|
||||
|
||||
} // namespace VMAP
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _VMAPMANAGER2_H
|
||||
#define _VMAPMANAGER2_H
|
||||
|
||||
#include "IVMapManager.h"
|
||||
#include "Dynamic/UnorderedMap.h"
|
||||
#include "Define.h"
|
||||
#include <ace/Thread_Mutex.h>
|
||||
|
||||
//===========================================================
|
||||
|
||||
#define MAP_FILENAME_EXTENSION2 ".vmtree"
|
||||
|
||||
#define FILENAMEBUFFER_SIZE 500
|
||||
|
||||
/**
|
||||
This is the main Class to manage loading and unloading of maps, line of sight, height calculation and so on.
|
||||
For each map or map tile to load it reads a directory file that contains the ModelContainer files used by this map or map tile.
|
||||
Each global map or instance has its own dynamic BSP-Tree.
|
||||
The loaded ModelContainers are included in one of these BSP-Trees.
|
||||
Additionally a table to match map ids and map names is used.
|
||||
*/
|
||||
|
||||
//===========================================================
|
||||
|
||||
namespace G3D
|
||||
{
|
||||
class Vector3;
|
||||
}
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
class StaticMapTree;
|
||||
class WorldModel;
|
||||
|
||||
class ManagedModel
|
||||
{
|
||||
public:
|
||||
ManagedModel() : iModel(0), iRefCount(0) { }
|
||||
void setModel(WorldModel* model) { iModel = model; }
|
||||
WorldModel* getModel() { return iModel; }
|
||||
void incRefCount() { ++iRefCount; }
|
||||
int decRefCount() { return --iRefCount; }
|
||||
protected:
|
||||
WorldModel* iModel;
|
||||
int iRefCount;
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32, StaticMapTree*> InstanceTreeMap;
|
||||
typedef UNORDERED_MAP<std::string, ManagedModel> ModelFileMap;
|
||||
|
||||
class VMapManager2 : public IVMapManager
|
||||
{
|
||||
protected:
|
||||
// Tree to check collision
|
||||
ModelFileMap iLoadedModelFiles;
|
||||
InstanceTreeMap iInstanceMapTrees;
|
||||
// Mutex for iLoadedModelFiles
|
||||
ACE_Thread_Mutex LoadedModelFilesLock;
|
||||
|
||||
bool _loadMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY);
|
||||
/* void _unloadMap(uint32 pMapId, uint32 x, uint32 y); */
|
||||
|
||||
public:
|
||||
// public for debug
|
||||
G3D::Vector3 convertPositionToInternalRep(float x, float y, float z) const;
|
||||
static std::string getMapFileName(unsigned int mapId);
|
||||
|
||||
VMapManager2();
|
||||
~VMapManager2(void);
|
||||
|
||||
int loadMap(const char* pBasePath, unsigned int mapId, int x, int y);
|
||||
|
||||
void unloadMap(unsigned int mapId, int x, int y);
|
||||
void unloadMap(unsigned int mapId);
|
||||
|
||||
bool isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2) ;
|
||||
/**
|
||||
fill the hit pos and return true, if an object was hit
|
||||
*/
|
||||
bool getObjectHitPos(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist);
|
||||
float getHeight(unsigned int mapId, float x, float y, float z, float maxSearchDist);
|
||||
|
||||
bool processCommand(char* /*command*/) { return false; } // for debug and extensions
|
||||
|
||||
bool getAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const;
|
||||
bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const;
|
||||
|
||||
WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename);
|
||||
void releaseModelInstance(const std::string& filename);
|
||||
|
||||
// what's the use of this? o.O
|
||||
virtual std::string getDirFileName(unsigned int mapId, int /*x*/, int /*y*/) const
|
||||
{
|
||||
return getMapFileName(mapId);
|
||||
}
|
||||
virtual bool existsMap(const char* basePath, unsigned int mapId, int x, int y);
|
||||
public:
|
||||
void getInstanceMapTree(InstanceTreeMap &instanceMapTree);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,477 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MapTree.h"
|
||||
#include "ModelInstance.h"
|
||||
#include "VMapManager2.h"
|
||||
#include "VMapDefinitions.h"
|
||||
#include "Log.h"
|
||||
#include "Errors.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
|
||||
using G3D::Vector3;
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
|
||||
class MapRayCallback
|
||||
{
|
||||
public:
|
||||
MapRayCallback(ModelInstance* val): prims(val), hit(false) {}
|
||||
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool StopAtFirstHit)
|
||||
{
|
||||
bool result = prims[entry].intersectRay(ray, distance, StopAtFirstHit);
|
||||
if (result)
|
||||
hit = true;
|
||||
return result;
|
||||
}
|
||||
bool didHit() { return hit; }
|
||||
protected:
|
||||
ModelInstance* prims;
|
||||
bool hit;
|
||||
};
|
||||
|
||||
class AreaInfoCallback
|
||||
{
|
||||
public:
|
||||
AreaInfoCallback(ModelInstance* val): prims(val) {}
|
||||
void operator()(const Vector3& point, uint32 entry)
|
||||
{
|
||||
#ifdef VMAP_DEBUG
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "AreaInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
|
||||
#endif
|
||||
prims[entry].intersectPoint(point, aInfo);
|
||||
}
|
||||
|
||||
ModelInstance* prims;
|
||||
AreaInfo aInfo;
|
||||
};
|
||||
|
||||
class LocationInfoCallback
|
||||
{
|
||||
public:
|
||||
LocationInfoCallback(ModelInstance* val, LocationInfo &info): prims(val), locInfo(info), result(false) {}
|
||||
void operator()(const Vector3& point, uint32 entry)
|
||||
{
|
||||
#ifdef VMAP_DEBUG
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "LocationInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
|
||||
#endif
|
||||
if (prims[entry].GetLocationInfo(point, locInfo))
|
||||
result = true;
|
||||
}
|
||||
|
||||
ModelInstance* prims;
|
||||
LocationInfo &locInfo;
|
||||
bool result;
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
|
||||
std::string StaticMapTree::getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY)
|
||||
{
|
||||
std::stringstream tilefilename;
|
||||
tilefilename.fill('0');
|
||||
tilefilename << std::setw(3) << mapID << '_';
|
||||
//tilefilename << std::setw(2) << tileX << '_' << std::setw(2) << tileY << ".vmtile";
|
||||
tilefilename << std::setw(2) << tileY << '_' << std::setw(2) << tileX << ".vmtile";
|
||||
return tilefilename.str();
|
||||
}
|
||||
|
||||
bool StaticMapTree::getAreaInfo(Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const
|
||||
{
|
||||
AreaInfoCallback intersectionCallBack(iTreeValues);
|
||||
iTree.intersectPoint(pos, intersectionCallBack);
|
||||
if (intersectionCallBack.aInfo.result)
|
||||
{
|
||||
flags = intersectionCallBack.aInfo.flags;
|
||||
adtId = intersectionCallBack.aInfo.adtId;
|
||||
rootId = intersectionCallBack.aInfo.rootId;
|
||||
groupId = intersectionCallBack.aInfo.groupId;
|
||||
pos.z = intersectionCallBack.aInfo.ground_Z;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StaticMapTree::GetLocationInfo(const Vector3 &pos, LocationInfo &info) const
|
||||
{
|
||||
LocationInfoCallback intersectionCallBack(iTreeValues, info);
|
||||
iTree.intersectPoint(pos, intersectionCallBack);
|
||||
return intersectionCallBack.result;
|
||||
}
|
||||
|
||||
StaticMapTree::StaticMapTree(uint32 mapID, const std::string &basePath)
|
||||
: iMapID(mapID), iIsTiled(false), iTreeValues(0), iBasePath(basePath)
|
||||
{
|
||||
if (iBasePath.length() > 0 && iBasePath[iBasePath.length()-1] != '/' && iBasePath[iBasePath.length()-1] != '\\')
|
||||
{
|
||||
iBasePath.push_back('/');
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//! Make sure to call unloadMap() to unregister acquired model references before destroying
|
||||
StaticMapTree::~StaticMapTree()
|
||||
{
|
||||
delete[] iTreeValues;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
/**
|
||||
If intersection is found within pMaxDist, sets pMaxDist to intersection distance and returns true.
|
||||
Else, pMaxDist is not modified and returns false;
|
||||
*/
|
||||
|
||||
bool StaticMapTree::getIntersectionTime(const G3D::Ray& pRay, float &pMaxDist, bool StopAtFirstHit) const
|
||||
{
|
||||
float distance = pMaxDist;
|
||||
MapRayCallback intersectionCallBack(iTreeValues);
|
||||
iTree.intersectRay(pRay, intersectionCallBack, distance, StopAtFirstHit);
|
||||
if (intersectionCallBack.didHit())
|
||||
pMaxDist = distance;
|
||||
return intersectionCallBack.didHit();
|
||||
}
|
||||
//=========================================================
|
||||
|
||||
bool StaticMapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2) const
|
||||
{
|
||||
float maxDist = (pos2 - pos1).magnitude();
|
||||
// return false if distance is over max float, in case of cheater teleporting to the end of the universe
|
||||
if (maxDist == std::numeric_limits<float>::max() || !myisfinite(maxDist))
|
||||
return false;
|
||||
|
||||
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too
|
||||
ASSERT(maxDist < std::numeric_limits<float>::max());
|
||||
// prevent NaN values which can cause BIH intersection to enter infinite loop
|
||||
if (maxDist < 1e-10f)
|
||||
return true;
|
||||
// direction with length of 1
|
||||
G3D::Ray ray = G3D::Ray::fromOriginAndDirection(pos1, (pos2 - pos1)/maxDist);
|
||||
if (getIntersectionTime(ray, maxDist, true))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//=========================================================
|
||||
/**
|
||||
When moving from pos1 to pos2 check if we hit an object. Return true and the position if we hit one
|
||||
Return the hit pos or the original dest pos
|
||||
*/
|
||||
|
||||
bool StaticMapTree::getObjectHitPos(const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist) const
|
||||
{
|
||||
bool result=false;
|
||||
float maxDist = (pPos2 - pPos1).magnitude();
|
||||
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too
|
||||
ASSERT(maxDist < std::numeric_limits<float>::max());
|
||||
// prevent NaN values which can cause BIH intersection to enter infinite loop
|
||||
if (maxDist < 1e-10f)
|
||||
{
|
||||
pResultHitPos = pPos2;
|
||||
return false;
|
||||
}
|
||||
Vector3 dir = (pPos2 - pPos1)/maxDist; // direction with length of 1
|
||||
G3D::Ray ray(pPos1, dir);
|
||||
float dist = maxDist;
|
||||
if (getIntersectionTime(ray, dist, false))
|
||||
{
|
||||
pResultHitPos = pPos1 + dir * dist;
|
||||
if (pModifyDist < 0)
|
||||
{
|
||||
if ((pResultHitPos - pPos1).magnitude() > -pModifyDist)
|
||||
{
|
||||
pResultHitPos = pResultHitPos + dir*pModifyDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
pResultHitPos = pPos1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pResultHitPos = pResultHitPos + dir*pModifyDist;
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pResultHitPos = pPos2;
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
float StaticMapTree::getHeight(const Vector3& pPos, float maxSearchDist) const
|
||||
{
|
||||
float height = G3D::inf();
|
||||
Vector3 dir = Vector3(0, 0, -1);
|
||||
G3D::Ray ray(pPos, dir); // direction with length of 1
|
||||
float maxDist = maxSearchDist;
|
||||
if (getIntersectionTime(ray, maxDist, false))
|
||||
{
|
||||
height = pPos.z - maxDist;
|
||||
}
|
||||
return(height);
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
bool StaticMapTree::CanLoadMap(const std::string &vmapPath, uint32 mapID, uint32 tileX, uint32 tileY)
|
||||
{
|
||||
std::string basePath = vmapPath;
|
||||
if (basePath.length() > 0 && basePath[basePath.length()-1] != '/' && basePath[basePath.length()-1] != '\\')
|
||||
basePath.push_back('/');
|
||||
std::string fullname = basePath + VMapManager2::getMapFileName(mapID);
|
||||
bool success = true;
|
||||
FILE* rf = fopen(fullname.c_str(), "rb");
|
||||
if (!rf)
|
||||
return false;
|
||||
// TODO: check magic number when implemented...
|
||||
char tiled;
|
||||
char chunk[8];
|
||||
if (!readChunk(rf, chunk, VMAP_MAGIC, 8) || fread(&tiled, sizeof(char), 1, rf) != 1)
|
||||
{
|
||||
fclose(rf);
|
||||
return false;
|
||||
}
|
||||
if (tiled)
|
||||
{
|
||||
std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY);
|
||||
FILE* tf = fopen(tilefile.c_str(), "rb");
|
||||
if (!tf)
|
||||
success = false;
|
||||
else
|
||||
{
|
||||
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||
success = false;
|
||||
fclose(tf);
|
||||
}
|
||||
}
|
||||
fclose(rf);
|
||||
return success;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
bool StaticMapTree::InitMap(const std::string &fname, VMapManager2* vm)
|
||||
{
|
||||
//VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : initializing StaticMapTree '%s'", fname.c_str());
|
||||
bool success = false;
|
||||
std::string fullname = iBasePath + fname;
|
||||
FILE* rf = fopen(fullname.c_str(), "rb");
|
||||
if (!rf)
|
||||
return false;
|
||||
|
||||
char chunk[8];
|
||||
char tiled = '\0';
|
||||
|
||||
if (readChunk(rf, chunk, VMAP_MAGIC, 8) && fread(&tiled, sizeof(char), 1, rf) == 1 &&
|
||||
readChunk(rf, chunk, "NODE", 4) && iTree.readFromFile(rf))
|
||||
{
|
||||
iNTreeValues = iTree.primCount();
|
||||
iTreeValues = new ModelInstance[iNTreeValues];
|
||||
success = readChunk(rf, chunk, "GOBJ", 4);
|
||||
}
|
||||
|
||||
iIsTiled = bool(tiled);
|
||||
|
||||
// global model spawns
|
||||
// only non-tiled maps have them, and if so exactly one (so far at least...)
|
||||
ModelSpawn spawn;
|
||||
#ifdef VMAP_DEBUG
|
||||
//TC_LOG_DEBUG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : map isTiled: %u", static_cast<uint32>(iIsTiled));
|
||||
#endif
|
||||
if (!iIsTiled && ModelSpawn::readFromFile(rf, spawn))
|
||||
{
|
||||
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
|
||||
//VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : loading %s", spawn.name.c_str());
|
||||
if (model)
|
||||
{
|
||||
// assume that global model always is the first and only tree value (could be improved...)
|
||||
iTreeValues[0] = ModelInstance(spawn, model);
|
||||
iLoadedSpawns[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
//VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::InitMap() : could not acquire WorldModel pointer for '%s'", spawn.name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
fclose(rf);
|
||||
return success;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
void StaticMapTree::UnloadMap(VMapManager2* vm)
|
||||
{
|
||||
for (loadedSpawnMap::iterator i = iLoadedSpawns.begin(); i != iLoadedSpawns.end(); ++i)
|
||||
{
|
||||
iTreeValues[i->first].setUnloaded();
|
||||
for (uint32 refCount = 0; refCount < i->second; ++refCount)
|
||||
vm->releaseModelInstance(iTreeValues[i->first].name);
|
||||
}
|
||||
iLoadedSpawns.clear();
|
||||
iLoadedTiles.clear();
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
bool StaticMapTree::LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm)
|
||||
{
|
||||
if (!iIsTiled)
|
||||
{
|
||||
// currently, core creates grids for all maps, whether it has terrain tiles or not
|
||||
// so we need "fake" tile loads to know when we can unload map geometry
|
||||
iLoadedTiles[packTileID(tileX, tileY)] = false;
|
||||
return true;
|
||||
}
|
||||
if (!iTreeValues)
|
||||
{
|
||||
sLog->outError("StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY);
|
||||
return false;
|
||||
}
|
||||
bool result = true;
|
||||
|
||||
std::string tilefile = iBasePath + getTileFileName(iMapID, tileX, tileY);
|
||||
FILE* tf = fopen(tilefile.c_str(), "rb");
|
||||
if (tf)
|
||||
{
|
||||
char chunk[8];
|
||||
|
||||
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||
result = false;
|
||||
uint32 numSpawns = 0;
|
||||
if (result && fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
|
||||
result = false;
|
||||
for (uint32 i=0; i<numSpawns && result; ++i)
|
||||
{
|
||||
// read model spawns
|
||||
ModelSpawn spawn;
|
||||
result = ModelSpawn::readFromFile(tf, spawn);
|
||||
if (result)
|
||||
{
|
||||
// acquire model instance
|
||||
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
|
||||
if (!model)
|
||||
sLog->outError("StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
|
||||
|
||||
// update tree
|
||||
uint32 referencedVal;
|
||||
|
||||
if (fread(&referencedVal, sizeof(uint32), 1, tf) == 1)
|
||||
{
|
||||
if (!iLoadedSpawns.count(referencedVal))
|
||||
{
|
||||
#ifdef VMAP_DEBUG
|
||||
if (referencedVal > iNTreeValues)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::LoadMapTile() : invalid tree element (%u/%u)", referencedVal, iNTreeValues);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
iTreeValues[referencedVal] = ModelInstance(spawn, model);
|
||||
iLoadedSpawns[referencedVal] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++iLoadedSpawns[referencedVal];
|
||||
#ifdef VMAP_DEBUG
|
||||
if (iTreeValues[referencedVal].ID != spawn.ID)
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::LoadMapTile() : trying to load wrong spawn in node");
|
||||
else if (iTreeValues[referencedVal].name != spawn.name)
|
||||
;//sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::LoadMapTile() : name collision on GUID=%u", spawn.ID);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
iLoadedTiles[packTileID(tileX, tileY)] = true;
|
||||
fclose(tf);
|
||||
}
|
||||
else
|
||||
iLoadedTiles[packTileID(tileX, tileY)] = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
void StaticMapTree::UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm)
|
||||
{
|
||||
uint32 tileID = packTileID(tileX, tileY);
|
||||
loadedTileMap::iterator tile = iLoadedTiles.find(tileID);
|
||||
if (tile == iLoadedTiles.end())
|
||||
{
|
||||
sLog->outError("StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:%u X:%u Y:%u", iMapID, tileX, tileY);
|
||||
return;
|
||||
}
|
||||
if (tile->second) // file associated with tile
|
||||
{
|
||||
std::string tilefile = iBasePath + getTileFileName(iMapID, tileX, tileY);
|
||||
FILE* tf = fopen(tilefile.c_str(), "rb");
|
||||
if (tf)
|
||||
{
|
||||
bool result=true;
|
||||
char chunk[8];
|
||||
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||
result = false;
|
||||
uint32 numSpawns;
|
||||
if (fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
|
||||
result = false;
|
||||
for (uint32 i=0; i<numSpawns && result; ++i)
|
||||
{
|
||||
// read model spawns
|
||||
ModelSpawn spawn;
|
||||
result = ModelSpawn::readFromFile(tf, spawn);
|
||||
if (result)
|
||||
{
|
||||
// release model instance
|
||||
vm->releaseModelInstance(spawn.name);
|
||||
|
||||
// update tree
|
||||
uint32 referencedNode;
|
||||
|
||||
if (fread(&referencedNode, sizeof(uint32), 1, tf) != 1)
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
if (!iLoadedSpawns.count(referencedNode))
|
||||
sLog->outError("StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID);
|
||||
else if (--iLoadedSpawns[referencedNode] == 0)
|
||||
{
|
||||
iTreeValues[referencedNode].setUnloaded();
|
||||
iLoadedSpawns.erase(referencedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(tf);
|
||||
}
|
||||
}
|
||||
iLoadedTiles.erase(tile);
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MAPTREE_H
|
||||
#define _MAPTREE_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "Dynamic/UnorderedMap.h"
|
||||
#include "BoundingIntervalHierarchy.h"
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
class ModelInstance;
|
||||
class GroupModel;
|
||||
class VMapManager2;
|
||||
|
||||
struct LocationInfo
|
||||
{
|
||||
LocationInfo(): hitInstance(0), hitModel(0), ground_Z(-G3D::inf()) { }
|
||||
const ModelInstance* hitInstance;
|
||||
const GroupModel* hitModel;
|
||||
float ground_Z;
|
||||
};
|
||||
|
||||
class StaticMapTree
|
||||
{
|
||||
typedef UNORDERED_MAP<uint32, bool> loadedTileMap;
|
||||
typedef UNORDERED_MAP<uint32, uint32> loadedSpawnMap;
|
||||
private:
|
||||
uint32 iMapID;
|
||||
bool iIsTiled;
|
||||
BIH iTree;
|
||||
ModelInstance* iTreeValues; // the tree entries
|
||||
uint32 iNTreeValues;
|
||||
|
||||
// Store all the map tile idents that are loaded for that map
|
||||
// some maps are not splitted into tiles and we have to make sure, not removing the map before all tiles are removed
|
||||
// empty tiles have no tile file, hence map with bool instead of just a set (consistency check)
|
||||
loadedTileMap iLoadedTiles;
|
||||
// stores <tree_index, reference_count> to invalidate tree values, unload map, and to be able to report errors
|
||||
loadedSpawnMap iLoadedSpawns;
|
||||
std::string iBasePath;
|
||||
|
||||
private:
|
||||
bool getIntersectionTime(const G3D::Ray& pRay, float &pMaxDist, bool StopAtFirstHit) const;
|
||||
//bool containsLoadedMapTile(unsigned int pTileIdent) const { return(iLoadedMapTiles.containsKey(pTileIdent)); }
|
||||
public:
|
||||
static std::string getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY);
|
||||
static uint32 packTileID(uint32 tileX, uint32 tileY) { return tileX<<16 | tileY; }
|
||||
static void unpackTileID(uint32 ID, uint32 &tileX, uint32 &tileY) { tileX = ID>>16; tileY = ID&0xFF; }
|
||||
static bool CanLoadMap(const std::string &basePath, uint32 mapID, uint32 tileX, uint32 tileY);
|
||||
|
||||
StaticMapTree(uint32 mapID, const std::string &basePath);
|
||||
~StaticMapTree();
|
||||
|
||||
bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2) const;
|
||||
bool getObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const;
|
||||
float getHeight(const G3D::Vector3& pPos, float maxSearchDist) const;
|
||||
bool getAreaInfo(G3D::Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const;
|
||||
bool GetLocationInfo(const G3D::Vector3 &pos, LocationInfo &info) const;
|
||||
|
||||
bool InitMap(const std::string &fname, VMapManager2* vm);
|
||||
void UnloadMap(VMapManager2* vm);
|
||||
bool LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm);
|
||||
void UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm);
|
||||
bool isTiled() const { return iIsTiled; }
|
||||
uint32 numLoadedTiles() const { return iLoadedTiles.size(); }
|
||||
void getModelInstances(ModelInstance* &models, uint32 &count);
|
||||
};
|
||||
|
||||
struct AreaInfo
|
||||
{
|
||||
AreaInfo(): result(false), ground_Z(-G3D::inf()), flags(0), adtId(0),
|
||||
rootId(0), groupId(0) { }
|
||||
bool result;
|
||||
float ground_Z;
|
||||
uint32 flags;
|
||||
int32 adtId;
|
||||
int32 rootId;
|
||||
int32 groupId;
|
||||
};
|
||||
} // VMAP
|
||||
|
||||
#endif // _MAPTREE_H
|
||||
@@ -1,540 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TileAssembler.h"
|
||||
#include "MapTree.h"
|
||||
#include "BoundingIntervalHierarchy.h"
|
||||
#include "VMapDefinitions.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
#include <set>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
using G3D::Vector3;
|
||||
using G3D::AABox;
|
||||
using G3D::inf;
|
||||
using std::pair;
|
||||
|
||||
template<> struct BoundsTrait<VMAP::ModelSpawn*>
|
||||
{
|
||||
static void getBounds(const VMAP::ModelSpawn* const &obj, G3D::AABox& out) { out = obj->getBounds(); }
|
||||
};
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
bool readChunk(FILE* rf, char *dest, const char *compare, uint32 len)
|
||||
{
|
||||
if (fread(dest, sizeof(char), len, rf) != len) return false;
|
||||
return memcmp(dest, compare, len) == 0;
|
||||
}
|
||||
|
||||
Vector3 ModelPosition::transform(const Vector3& pIn) const
|
||||
{
|
||||
Vector3 out = pIn * iScale;
|
||||
out = iRotation * out;
|
||||
return(out);
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
|
||||
TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName)
|
||||
: iDestDir(pDestDirName), iSrcDir(pSrcDirName), iFilterMethod(NULL), iCurrentUniqueNameId(0)
|
||||
{
|
||||
//mkdir(iDestDir);
|
||||
//init();
|
||||
}
|
||||
|
||||
TileAssembler::~TileAssembler()
|
||||
{
|
||||
//delete iCoordModelMapping;
|
||||
}
|
||||
|
||||
bool TileAssembler::convertWorld2()
|
||||
{
|
||||
bool success = readMapSpawns();
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
// export Map data
|
||||
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end() && success; ++map_iter)
|
||||
{
|
||||
// build global map tree
|
||||
std::vector<ModelSpawn*> mapSpawns;
|
||||
UniqueEntryMap::iterator entry;
|
||||
printf("Calculating model bounds for map %u...\n", map_iter->first);
|
||||
for (entry = map_iter->second->UniqueEntries.begin(); entry != map_iter->second->UniqueEntries.end(); ++entry)
|
||||
{
|
||||
// M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail
|
||||
if (entry->second.flags & MOD_M2)
|
||||
{
|
||||
if (!calculateTransformedBound(entry->second))
|
||||
break;
|
||||
}
|
||||
else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/
|
||||
{
|
||||
/// @todo remove extractor hack and uncomment below line:
|
||||
//entry->second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f);
|
||||
entry->second.iBound = entry->second.iBound + Vector3(533.33333f*32, 533.33333f*32, 0.f);
|
||||
}
|
||||
mapSpawns.push_back(&(entry->second));
|
||||
spawnedModelFiles.insert(entry->second.name);
|
||||
}
|
||||
|
||||
printf("Creating map tree for map %u...\n", map_iter->first);
|
||||
BIH pTree;
|
||||
|
||||
try
|
||||
{
|
||||
pTree.build(mapSpawns, BoundsTrait<ModelSpawn*>::getBounds);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
printf("Exception ""%s"" when calling pTree.build", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
// ===> possibly move this code to StaticMapTree class
|
||||
std::map<uint32, uint32> modelNodeIdx;
|
||||
for (uint32 i=0; i<mapSpawns.size(); ++i)
|
||||
modelNodeIdx.insert(pair<uint32, uint32>(mapSpawns[i]->ID, i));
|
||||
|
||||
// write map tree file
|
||||
std::stringstream mapfilename;
|
||||
mapfilename << iDestDir << '/' << std::setfill('0') << std::setw(3) << map_iter->first << ".vmtree";
|
||||
FILE* mapfile = fopen(mapfilename.str().c_str(), "wb");
|
||||
if (!mapfile)
|
||||
{
|
||||
success = false;
|
||||
printf("Cannot open %s\n", mapfilename.str().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
//general info
|
||||
if (success && fwrite(VMAP_MAGIC, 1, 8, mapfile) != 8) success = false;
|
||||
uint32 globalTileID = StaticMapTree::packTileID(65, 65);
|
||||
pair<TileMap::iterator, TileMap::iterator> globalRange = map_iter->second->TileEntries.equal_range(globalTileID);
|
||||
char isTiled = globalRange.first == globalRange.second; // only maps without terrain (tiles) have global WMO
|
||||
if (success && fwrite(&isTiled, sizeof(char), 1, mapfile) != 1) success = false;
|
||||
// Nodes
|
||||
if (success && fwrite("NODE", 4, 1, mapfile) != 1) success = false;
|
||||
if (success) success = pTree.writeToFile(mapfile);
|
||||
// global map spawns (WDT), if any (most instances)
|
||||
if (success && fwrite("GOBJ", 4, 1, mapfile) != 1) success = false;
|
||||
|
||||
for (TileMap::iterator glob=globalRange.first; glob != globalRange.second && success; ++glob)
|
||||
{
|
||||
success = ModelSpawn::writeToFile(mapfile, map_iter->second->UniqueEntries[glob->second]);
|
||||
}
|
||||
|
||||
fclose(mapfile);
|
||||
|
||||
// <====
|
||||
|
||||
// write map tile files, similar to ADT files, only with extra BSP tree node info
|
||||
TileMap &tileEntries = map_iter->second->TileEntries;
|
||||
TileMap::iterator tile;
|
||||
for (tile = tileEntries.begin(); tile != tileEntries.end(); ++tile)
|
||||
{
|
||||
const ModelSpawn &spawn = map_iter->second->UniqueEntries[tile->second];
|
||||
if (spawn.flags & MOD_WORLDSPAWN) // WDT spawn, saved as tile 65/65 currently...
|
||||
continue;
|
||||
uint32 nSpawns = tileEntries.count(tile->first);
|
||||
std::stringstream tilefilename;
|
||||
tilefilename.fill('0');
|
||||
tilefilename << iDestDir << '/' << std::setw(3) << map_iter->first << '_';
|
||||
uint32 x, y;
|
||||
StaticMapTree::unpackTileID(tile->first, x, y);
|
||||
tilefilename << std::setw(2) << x << '_' << std::setw(2) << y << ".vmtile";
|
||||
if (FILE* tilefile = fopen(tilefilename.str().c_str(), "wb"))
|
||||
{
|
||||
// file header
|
||||
if (success && fwrite(VMAP_MAGIC, 1, 8, tilefile) != 8) success = false;
|
||||
// write number of tile spawns
|
||||
if (success && fwrite(&nSpawns, sizeof(uint32), 1, tilefile) != 1) success = false;
|
||||
// write tile spawns
|
||||
for (uint32 s=0; s<nSpawns; ++s)
|
||||
{
|
||||
if (s)
|
||||
++tile;
|
||||
const ModelSpawn &spawn2 = map_iter->second->UniqueEntries[tile->second];
|
||||
success = success && ModelSpawn::writeToFile(tilefile, spawn2);
|
||||
// MapTree nodes to update when loading tile:
|
||||
std::map<uint32, uint32>::iterator nIdx = modelNodeIdx.find(spawn2.ID);
|
||||
if (success && fwrite(&nIdx->second, sizeof(uint32), 1, tilefile) != 1) success = false;
|
||||
}
|
||||
fclose(tilefile);
|
||||
}
|
||||
}
|
||||
// break; //test, extract only first map; TODO: remvoe this line
|
||||
}
|
||||
|
||||
// add an object models, listed in temp_gameobject_models file
|
||||
exportGameobjectModels();
|
||||
// export objects
|
||||
std::cout << "\nConverting Model Files" << std::endl;
|
||||
for (std::set<std::string>::iterator mfile = spawnedModelFiles.begin(); mfile != spawnedModelFiles.end(); ++mfile)
|
||||
{
|
||||
std::cout << "Converting " << *mfile << std::endl;
|
||||
if (!convertRawFile(*mfile))
|
||||
{
|
||||
std::cout << "error converting " << *mfile << std::endl;
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//cleanup:
|
||||
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end(); ++map_iter)
|
||||
{
|
||||
delete map_iter->second;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool TileAssembler::readMapSpawns()
|
||||
{
|
||||
std::string fname = iSrcDir + "/dir_bin";
|
||||
FILE* dirf = fopen(fname.c_str(), "rb");
|
||||
if (!dirf)
|
||||
{
|
||||
printf("Could not read dir_bin file!\n");
|
||||
return false;
|
||||
}
|
||||
printf("Read coordinate mapping...\n");
|
||||
uint32 mapID, tileX, tileY, check=0;
|
||||
G3D::Vector3 v1, v2;
|
||||
ModelSpawn spawn;
|
||||
while (!feof(dirf))
|
||||
{
|
||||
check = 0;
|
||||
// read mapID, tileX, tileY, Flags, adtID, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||
check += fread(&mapID, sizeof(uint32), 1, dirf);
|
||||
if (check == 0) // EoF...
|
||||
break;
|
||||
check += fread(&tileX, sizeof(uint32), 1, dirf);
|
||||
check += fread(&tileY, sizeof(uint32), 1, dirf);
|
||||
if (!ModelSpawn::readFromFile(dirf, spawn))
|
||||
break;
|
||||
|
||||
MapSpawns *current;
|
||||
MapData::iterator map_iter = mapData.find(mapID);
|
||||
if (map_iter == mapData.end())
|
||||
{
|
||||
printf("spawning Map %d\n", mapID);
|
||||
mapData[mapID] = current = new MapSpawns();
|
||||
}
|
||||
else current = (*map_iter).second;
|
||||
current->UniqueEntries.insert(pair<uint32, ModelSpawn>(spawn.ID, spawn));
|
||||
current->TileEntries.insert(pair<uint32, uint32>(StaticMapTree::packTileID(tileX, tileY), spawn.ID));
|
||||
}
|
||||
bool success = (ferror(dirf) == 0);
|
||||
fclose(dirf);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool TileAssembler::calculateTransformedBound(ModelSpawn &spawn)
|
||||
{
|
||||
std::string modelFilename(iSrcDir);
|
||||
modelFilename.push_back('/');
|
||||
modelFilename.append(spawn.name);
|
||||
|
||||
ModelPosition modelPosition;
|
||||
modelPosition.iDir = spawn.iRot;
|
||||
modelPosition.iScale = spawn.iScale;
|
||||
modelPosition.init();
|
||||
|
||||
WorldModel_Raw raw_model;
|
||||
if (!raw_model.Read(modelFilename.c_str()))
|
||||
return false;
|
||||
|
||||
uint32 groups = raw_model.groupsArray.size();
|
||||
if (groups != 1)
|
||||
printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str());
|
||||
|
||||
AABox modelBound;
|
||||
bool boundEmpty=true;
|
||||
|
||||
for (uint32 g=0; g<groups; ++g) // should be only one for M2 files...
|
||||
{
|
||||
std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray;
|
||||
|
||||
if (vertices.empty())
|
||||
{
|
||||
std::cout << "error: model '" << spawn.name << "' has no geometry!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 nvectors = vertices.size();
|
||||
for (uint32 i = 0; i < nvectors; ++i)
|
||||
{
|
||||
Vector3 v = modelPosition.transform(vertices[i]);
|
||||
|
||||
if (boundEmpty)
|
||||
modelBound = AABox(v, v), boundEmpty=false;
|
||||
else
|
||||
modelBound.merge(v);
|
||||
}
|
||||
}
|
||||
spawn.iBound = modelBound + spawn.iPos;
|
||||
spawn.flags |= MOD_HAS_BOUND;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct WMOLiquidHeader
|
||||
{
|
||||
int xverts, yverts, xtiles, ytiles;
|
||||
float pos_x;
|
||||
float pos_y;
|
||||
float pos_z;
|
||||
short type;
|
||||
};
|
||||
//=================================================================
|
||||
bool TileAssembler::convertRawFile(const std::string& pModelFilename)
|
||||
{
|
||||
bool success = true;
|
||||
std::string filename = iSrcDir;
|
||||
if (filename.length() >0)
|
||||
filename.push_back('/');
|
||||
filename.append(pModelFilename);
|
||||
|
||||
WorldModel_Raw raw_model;
|
||||
if (!raw_model.Read(filename.c_str()))
|
||||
return false;
|
||||
|
||||
// write WorldModel
|
||||
WorldModel model;
|
||||
model.setRootWmoID(raw_model.RootWMOID);
|
||||
if (!raw_model.groupsArray.empty())
|
||||
{
|
||||
std::vector<GroupModel> groupsArray;
|
||||
|
||||
uint32 groups = raw_model.groupsArray.size();
|
||||
for (uint32 g = 0; g < groups; ++g)
|
||||
{
|
||||
GroupModel_Raw& raw_group = raw_model.groupsArray[g];
|
||||
groupsArray.push_back(GroupModel(raw_group.mogpflags, raw_group.GroupWMOID, raw_group.bounds ));
|
||||
groupsArray.back().setMeshData(raw_group.vertexArray, raw_group.triangles);
|
||||
groupsArray.back().setLiquidData(raw_group.liquid);
|
||||
}
|
||||
|
||||
model.setGroupModels(groupsArray);
|
||||
}
|
||||
|
||||
success = model.writeFile(iDestDir + "/" + pModelFilename + ".vmo");
|
||||
//std::cout << "readRawFile2: '" << pModelFilename << "' tris: " << nElements << " nodes: " << nNodes << std::endl;
|
||||
return success;
|
||||
}
|
||||
|
||||
void TileAssembler::exportGameobjectModels()
|
||||
{
|
||||
FILE* model_list = fopen((iSrcDir + "/" + "temp_gameobject_models").c_str(), "rb");
|
||||
if (!model_list)
|
||||
return;
|
||||
|
||||
FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb");
|
||||
if (!model_list_copy)
|
||||
{
|
||||
fclose(model_list);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 name_length, displayId;
|
||||
char buff[500];
|
||||
while (!feof(model_list))
|
||||
{
|
||||
if (fread(&displayId, sizeof(uint32), 1, model_list) != 1
|
||||
|| fread(&name_length, sizeof(uint32), 1, model_list) != 1
|
||||
|| name_length >= sizeof(buff)
|
||||
|| fread(&buff, sizeof(char), name_length, model_list) != name_length)
|
||||
{
|
||||
std::cout << "\nFile 'temp_gameobject_models' seems to be corrupted" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
std::string model_name(buff, name_length);
|
||||
|
||||
WorldModel_Raw raw_model;
|
||||
if ( !raw_model.Read((iSrcDir + "/" + model_name).c_str()) )
|
||||
continue;
|
||||
|
||||
spawnedModelFiles.insert(model_name);
|
||||
AABox bounds;
|
||||
bool boundEmpty = true;
|
||||
for (uint32 g = 0; g < raw_model.groupsArray.size(); ++g)
|
||||
{
|
||||
std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray;
|
||||
|
||||
uint32 nvectors = vertices.size();
|
||||
for (uint32 i = 0; i < nvectors; ++i)
|
||||
{
|
||||
Vector3& v = vertices[i];
|
||||
if (boundEmpty)
|
||||
bounds = AABox(v, v), boundEmpty = false;
|
||||
else
|
||||
bounds.merge(v);
|
||||
}
|
||||
}
|
||||
|
||||
fwrite(&displayId, sizeof(uint32), 1, model_list_copy);
|
||||
fwrite(&name_length, sizeof(uint32), 1, model_list_copy);
|
||||
fwrite(&buff, sizeof(char), name_length, model_list_copy);
|
||||
fwrite(&bounds.low(), sizeof(Vector3), 1, model_list_copy);
|
||||
fwrite(&bounds.high(), sizeof(Vector3), 1, model_list_copy);
|
||||
}
|
||||
|
||||
fclose(model_list);
|
||||
fclose(model_list_copy);
|
||||
}
|
||||
// temporary use defines to simplify read/check code (close file and return at fail)
|
||||
#define READ_OR_RETURN(V, S) if (fread((V), (S), 1, rf) != 1) { \
|
||||
fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); }
|
||||
#define READ_OR_RETURN_WITH_DELETE(V, S) if (fread((V), (S), 1, rf) != 1) { \
|
||||
fclose(rf); printf("readfail, op = %i\n", readOperation); delete[] V; return(false); };
|
||||
#define CMP_OR_RETURN(V, S) if (strcmp((V), (S)) != 0) { \
|
||||
fclose(rf); printf("cmpfail, %s!=%s\n", V, S);return(false); }
|
||||
|
||||
bool GroupModel_Raw::Read(FILE* rf)
|
||||
{
|
||||
char blockId[5];
|
||||
blockId[4] = 0;
|
||||
int blocksize;
|
||||
int readOperation = 0;
|
||||
|
||||
READ_OR_RETURN(&mogpflags, sizeof(uint32));
|
||||
READ_OR_RETURN(&GroupWMOID, sizeof(uint32));
|
||||
|
||||
|
||||
Vector3 vec1, vec2;
|
||||
READ_OR_RETURN(&vec1, sizeof(Vector3));
|
||||
|
||||
READ_OR_RETURN(&vec2, sizeof(Vector3));
|
||||
bounds.set(vec1, vec2);
|
||||
|
||||
READ_OR_RETURN(&liquidflags, sizeof(uint32));
|
||||
|
||||
// will this ever be used? what is it good for anyway??
|
||||
uint32 branches;
|
||||
READ_OR_RETURN(&blockId, 4);
|
||||
CMP_OR_RETURN(blockId, "GRP ");
|
||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||
READ_OR_RETURN(&branches, sizeof(uint32));
|
||||
for (uint32 b=0; b<branches; ++b)
|
||||
{
|
||||
uint32 indexes;
|
||||
// indexes for each branch (not used jet)
|
||||
READ_OR_RETURN(&indexes, sizeof(uint32));
|
||||
}
|
||||
|
||||
// ---- indexes
|
||||
READ_OR_RETURN(&blockId, 4);
|
||||
CMP_OR_RETURN(blockId, "INDX");
|
||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||
uint32 nindexes;
|
||||
READ_OR_RETURN(&nindexes, sizeof(uint32));
|
||||
if (nindexes >0)
|
||||
{
|
||||
uint16 *indexarray = new uint16[nindexes];
|
||||
READ_OR_RETURN_WITH_DELETE(indexarray, nindexes*sizeof(uint16));
|
||||
triangles.reserve(nindexes / 3);
|
||||
for (uint32 i=0; i<nindexes; i+=3)
|
||||
triangles.push_back(MeshTriangle(indexarray[i], indexarray[i+1], indexarray[i+2]));
|
||||
|
||||
delete[] indexarray;
|
||||
}
|
||||
|
||||
// ---- vectors
|
||||
READ_OR_RETURN(&blockId, 4);
|
||||
CMP_OR_RETURN(blockId, "VERT");
|
||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||
uint32 nvectors;
|
||||
READ_OR_RETURN(&nvectors, sizeof(uint32));
|
||||
|
||||
if (nvectors >0)
|
||||
{
|
||||
float *vectorarray = new float[nvectors*3];
|
||||
READ_OR_RETURN_WITH_DELETE(vectorarray, nvectors*sizeof(float)*3);
|
||||
for (uint32 i=0; i<nvectors; ++i)
|
||||
vertexArray.push_back( Vector3(vectorarray + 3*i) );
|
||||
|
||||
delete[] vectorarray;
|
||||
}
|
||||
// ----- liquid
|
||||
liquid = 0;
|
||||
if (liquidflags& 1)
|
||||
{
|
||||
WMOLiquidHeader hlq;
|
||||
READ_OR_RETURN(&blockId, 4);
|
||||
CMP_OR_RETURN(blockId, "LIQU");
|
||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||
READ_OR_RETURN(&hlq, sizeof(WMOLiquidHeader));
|
||||
liquid = new WmoLiquid(hlq.xtiles, hlq.ytiles, Vector3(hlq.pos_x, hlq.pos_y, hlq.pos_z), hlq.type);
|
||||
uint32 size = hlq.xverts*hlq.yverts;
|
||||
READ_OR_RETURN(liquid->GetHeightStorage(), size*sizeof(float));
|
||||
size = hlq.xtiles*hlq.ytiles;
|
||||
READ_OR_RETURN(liquid->GetFlagsStorage(), size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
GroupModel_Raw::~GroupModel_Raw()
|
||||
{
|
||||
delete liquid;
|
||||
}
|
||||
|
||||
bool WorldModel_Raw::Read(const char * path)
|
||||
{
|
||||
FILE* rf = fopen(path, "rb");
|
||||
if (!rf)
|
||||
{
|
||||
printf("ERROR: Can't open raw model file: %s\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
char ident[9];
|
||||
ident[8] = '\0';
|
||||
int readOperation = 0;
|
||||
|
||||
READ_OR_RETURN(&ident, 8);
|
||||
CMP_OR_RETURN(ident, RAW_VMAP_MAGIC);
|
||||
|
||||
// we have to read one int. This is needed during the export and we have to skip it here
|
||||
uint32 tempNVectors;
|
||||
READ_OR_RETURN(&tempNVectors, sizeof(tempNVectors));
|
||||
|
||||
uint32 groups;
|
||||
READ_OR_RETURN(&groups, sizeof(uint32));
|
||||
READ_OR_RETURN(&RootWMOID, sizeof(uint32));
|
||||
|
||||
groupsArray.resize(groups);
|
||||
bool succeed = true;
|
||||
for (uint32 g = 0; g < groups && succeed; ++g)
|
||||
succeed = groupsArray[g].Read(rf);
|
||||
|
||||
if (succeed) /// rf will be freed inside Read if the function had any errors.
|
||||
fclose(rf);
|
||||
return succeed;
|
||||
}
|
||||
|
||||
// drop of temporary use defines
|
||||
#undef READ_OR_RETURN
|
||||
#undef CMP_OR_RETURN
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TILEASSEMBLER_H_
|
||||
#define _TILEASSEMBLER_H_
|
||||
|
||||
#include <G3D/Vector3.h>
|
||||
#include <G3D/Matrix3.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "ModelInstance.h"
|
||||
#include "WorldModel.h"
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
/**
|
||||
This Class is used to convert raw vector data into balanced BSP-Trees.
|
||||
To start the conversion call convertWorld().
|
||||
*/
|
||||
//===============================================
|
||||
|
||||
class ModelPosition
|
||||
{
|
||||
private:
|
||||
G3D::Matrix3 iRotation;
|
||||
public:
|
||||
ModelPosition(): iScale(0.0f) { }
|
||||
G3D::Vector3 iPos;
|
||||
G3D::Vector3 iDir;
|
||||
float iScale;
|
||||
void init()
|
||||
{
|
||||
iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iDir.y/180.f, G3D::pi()*iDir.x/180.f, G3D::pi()*iDir.z/180.f);
|
||||
}
|
||||
G3D::Vector3 transform(const G3D::Vector3& pIn) const;
|
||||
void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; }
|
||||
};
|
||||
|
||||
typedef std::map<uint32, ModelSpawn> UniqueEntryMap;
|
||||
typedef std::multimap<uint32, uint32> TileMap;
|
||||
|
||||
struct MapSpawns
|
||||
{
|
||||
UniqueEntryMap UniqueEntries;
|
||||
TileMap TileEntries;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, MapSpawns*> MapData;
|
||||
//===============================================
|
||||
|
||||
struct GroupModel_Raw
|
||||
{
|
||||
uint32 mogpflags;
|
||||
uint32 GroupWMOID;
|
||||
|
||||
G3D::AABox bounds;
|
||||
uint32 liquidflags;
|
||||
std::vector<MeshTriangle> triangles;
|
||||
std::vector<G3D::Vector3> vertexArray;
|
||||
class WmoLiquid* liquid;
|
||||
|
||||
GroupModel_Raw() : mogpflags(0), GroupWMOID(0), liquidflags(0),
|
||||
liquid(NULL) { }
|
||||
~GroupModel_Raw();
|
||||
|
||||
bool Read(FILE* f);
|
||||
};
|
||||
|
||||
struct WorldModel_Raw
|
||||
{
|
||||
uint32 RootWMOID;
|
||||
std::vector<GroupModel_Raw> groupsArray;
|
||||
|
||||
bool Read(const char * path);
|
||||
};
|
||||
|
||||
class TileAssembler
|
||||
{
|
||||
private:
|
||||
std::string iDestDir;
|
||||
std::string iSrcDir;
|
||||
bool (*iFilterMethod)(char *pName);
|
||||
G3D::Table<std::string, unsigned int > iUniqueNameIds;
|
||||
unsigned int iCurrentUniqueNameId;
|
||||
MapData mapData;
|
||||
std::set<std::string> spawnedModelFiles;
|
||||
|
||||
public:
|
||||
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
|
||||
virtual ~TileAssembler();
|
||||
|
||||
bool convertWorld2();
|
||||
bool readMapSpawns();
|
||||
bool calculateTransformedBound(ModelSpawn &spawn);
|
||||
void exportGameobjectModels();
|
||||
|
||||
bool convertRawFile(const std::string& pModelFilename);
|
||||
void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; }
|
||||
std::string getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName);
|
||||
};
|
||||
|
||||
} // VMAP
|
||||
#endif /*_TILEASSEMBLER_H_*/
|
||||
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VMapFactory.h"
|
||||
#include "VMapManager2.h"
|
||||
#include "VMapDefinitions.h"
|
||||
#include "WorldModel.h"
|
||||
|
||||
#include "GameObjectModel.h"
|
||||
#include "Log.h"
|
||||
#include "GameObject.h"
|
||||
#include "Creature.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Object.h"
|
||||
#include "DBCStores.h"
|
||||
#include "World.h"
|
||||
|
||||
using G3D::Vector3;
|
||||
using G3D::Ray;
|
||||
using G3D::AABox;
|
||||
|
||||
struct GameobjectModelData
|
||||
{
|
||||
GameobjectModelData(const std::string& name_, const AABox& box) :
|
||||
bound(box), name(name_) {}
|
||||
|
||||
AABox bound;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32, GameobjectModelData> ModelList;
|
||||
ModelList model_list;
|
||||
|
||||
void LoadGameObjectModelList()
|
||||
{
|
||||
//#ifndef NO_CORE_FUNCS
|
||||
uint32 oldMSTime = getMSTime();
|
||||
//#endif
|
||||
|
||||
FILE* model_list_file = fopen((sWorld->GetDataPath() + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb");
|
||||
if (!model_list_file)
|
||||
{
|
||||
sLog->outError("Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 name_length, displayId;
|
||||
char buff[500];
|
||||
while (true)
|
||||
{
|
||||
Vector3 v1, v2;
|
||||
if (fread(&displayId, sizeof(uint32), 1, model_list_file) != 1)
|
||||
if (feof(model_list_file)) // EOF flag is only set after failed reading attempt
|
||||
break;
|
||||
|
||||
if (fread(&name_length, sizeof(uint32), 1, model_list_file) != 1
|
||||
|| name_length >= sizeof(buff)
|
||||
|| fread(&buff, sizeof(char), name_length, model_list_file) != name_length
|
||||
|| fread(&v1, sizeof(Vector3), 1, model_list_file) != 1
|
||||
|| fread(&v2, sizeof(Vector3), 1, model_list_file) != 1)
|
||||
{
|
||||
sLog->outError("File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS);
|
||||
break;
|
||||
}
|
||||
|
||||
model_list.insert
|
||||
(
|
||||
ModelList::value_type( displayId, GameobjectModelData(std::string(buff, name_length), AABox(v1, v2)) )
|
||||
);
|
||||
}
|
||||
|
||||
fclose(model_list_file);
|
||||
sLog->outString(">> Loaded %u GameObject models in %u ms", uint32(model_list.size()), GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
|
||||
GameObjectModel::~GameObjectModel()
|
||||
{
|
||||
if (iModel)
|
||||
((VMAP::VMapManager2*)VMAP::VMapFactory::createOrGetVMapManager())->releaseModelInstance(name);
|
||||
}
|
||||
|
||||
bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayInfoEntry& info)
|
||||
{
|
||||
ModelList::const_iterator it = model_list.find(info.Displayid);
|
||||
if (it == model_list.end())
|
||||
return false;
|
||||
|
||||
G3D::AABox mdl_box(it->second.bound);
|
||||
// ignore models with no bounds
|
||||
if (mdl_box == G3D::AABox::zero())
|
||||
{
|
||||
sLog->outError("GameObject model %s has zero bounds, loading skipped", it->second.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
iModel = ((VMAP::VMapManager2*)VMAP::VMapFactory::createOrGetVMapManager())->acquireModelInstance(sWorld->GetDataPath() + "vmaps/", it->second.name);
|
||||
|
||||
if (!iModel)
|
||||
return false;
|
||||
|
||||
name = it->second.name;
|
||||
//flags = VMAP::MOD_M2;
|
||||
//adtId = 0;
|
||||
//ID = 0;
|
||||
iPos = Vector3(go.GetPositionX(), go.GetPositionY(), go.GetPositionZ());
|
||||
|
||||
// pussywizard:
|
||||
phasemask = (go.GetGoState() == GO_STATE_READY || go.IsTransport()) ? go.GetPhaseMask() : 0;
|
||||
|
||||
iScale = go.GetFloatValue(OBJECT_FIELD_SCALE_X);
|
||||
iInvScale = 1.f / iScale;
|
||||
|
||||
G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(go.GetOrientation(), 0, 0);
|
||||
iInvRot = iRotation.inverse();
|
||||
// transform bounding box:
|
||||
mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale);
|
||||
AABox rotated_bounds;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
rotated_bounds.merge(iRotation * mdl_box.corner(i));
|
||||
|
||||
iBound = rotated_bounds + iPos;
|
||||
#ifdef SPAWN_CORNERS
|
||||
// test:
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
Vector3 pos(iBound.corner(i));
|
||||
const_cast<GameObject&>(go).SummonCreature(1, pos.x, pos.y, pos.z, 0, TEMPSUMMON_MANUAL_DESPAWN);
|
||||
}
|
||||
#endif
|
||||
|
||||
owner = &go;
|
||||
return true;
|
||||
}
|
||||
|
||||
GameObjectModel* GameObjectModel::Create(const GameObject& go)
|
||||
{
|
||||
const GameObjectDisplayInfoEntry* info = sGameObjectDisplayInfoStore.LookupEntry(go.GetDisplayId());
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
GameObjectModel* mdl = new GameObjectModel();
|
||||
if (!mdl->initialize(go, *info))
|
||||
{
|
||||
delete mdl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mdl;
|
||||
}
|
||||
|
||||
bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const
|
||||
{
|
||||
if (!(phasemask & ph_mask) || !owner->isSpawned())
|
||||
return false;
|
||||
|
||||
float time = ray.intersectionTime(iBound);
|
||||
if (time == G3D::inf())
|
||||
return false;
|
||||
|
||||
// child bounds are defined in object space:
|
||||
Vector3 p = iInvRot * (ray.origin() - iPos) * iInvScale;
|
||||
Ray modRay(p, iInvRot * ray.direction());
|
||||
float distance = MaxDist * iInvScale;
|
||||
bool hit = iModel->IntersectRay(modRay, distance, StopAtFirstHit);
|
||||
if (hit)
|
||||
{
|
||||
distance *= iScale;
|
||||
MaxDist = distance;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool GameObjectModel::UpdatePosition()
|
||||
{
|
||||
if (!iModel)
|
||||
return false;
|
||||
|
||||
ModelList::const_iterator it = model_list.find(owner->GetDisplayId());
|
||||
if (it == model_list.end())
|
||||
return false;
|
||||
|
||||
G3D::AABox mdl_box(it->second.bound);
|
||||
// ignore models with no bounds
|
||||
if (mdl_box == G3D::AABox::zero())
|
||||
{
|
||||
//VMAP_ERROR_LOG("misc", "GameObject model %s has zero bounds, loading skipped", it->second.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
iPos = Vector3(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ());
|
||||
G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(owner->GetOrientation(), 0, 0);
|
||||
iInvRot = iRotation.inverse();
|
||||
// transform bounding box:
|
||||
mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale);
|
||||
AABox rotated_bounds;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
rotated_bounds.merge(iRotation * mdl_box.corner(i));
|
||||
|
||||
iBound = rotated_bounds + iPos;
|
||||
#ifdef SPAWN_CORNERS
|
||||
// test:
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
Vector3 pos(iBound.corner(i));
|
||||
owner->SummonCreature(1, pos.x, pos.y, pos.z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 10000);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _GAMEOBJECT_MODEL_H
|
||||
#define _GAMEOBJECT_MODEL_H
|
||||
|
||||
#include <G3D/Matrix3.h>
|
||||
#include <G3D/Vector3.h>
|
||||
#include <G3D/AABox.h>
|
||||
#include <G3D/Ray.h>
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
class WorldModel;
|
||||
}
|
||||
|
||||
class GameObject;
|
||||
struct GameObjectDisplayInfoEntry;
|
||||
|
||||
class GameObjectModel /*, public Intersectable*/
|
||||
{
|
||||
uint32 phasemask;
|
||||
G3D::AABox iBound;
|
||||
G3D::Matrix3 iInvRot;
|
||||
G3D::Vector3 iPos;
|
||||
//G3D::Vector3 iRot;
|
||||
float iInvScale;
|
||||
float iScale;
|
||||
VMAP::WorldModel* iModel;
|
||||
GameObject const* owner;
|
||||
|
||||
GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(NULL), owner(NULL) { }
|
||||
bool initialize(const GameObject& go, const GameObjectDisplayInfoEntry& info);
|
||||
|
||||
public:
|
||||
std::string name;
|
||||
|
||||
const G3D::AABox& getBounds() const { return iBound; }
|
||||
|
||||
~GameObjectModel();
|
||||
|
||||
const G3D::Vector3& getPosition() const { return iPos;}
|
||||
|
||||
/** Enables\disables collision. */
|
||||
void disable() { phasemask = 0;}
|
||||
void enable(uint32 ph_mask) { phasemask = ph_mask;}
|
||||
|
||||
bool isEnabled() const {return phasemask != 0;}
|
||||
|
||||
bool intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const;
|
||||
|
||||
static GameObjectModel* Create(const GameObject& go);
|
||||
|
||||
bool UpdatePosition();
|
||||
};
|
||||
|
||||
#endif // _GAMEOBJECT_MODEL_H
|
||||
@@ -1,223 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ModelInstance.h"
|
||||
#include "WorldModel.h"
|
||||
#include "MapTree.h"
|
||||
#include "VMapDefinitions.h"
|
||||
|
||||
using G3D::Vector3;
|
||||
using G3D::Ray;
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
ModelInstance::ModelInstance(const ModelSpawn &spawn, WorldModel* model): ModelSpawn(spawn), iModel(model)
|
||||
{
|
||||
iInvRot = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iRot.y/180.f, G3D::pi()*iRot.x/180.f, G3D::pi()*iRot.z/180.f).inverse();
|
||||
iInvScale = 1.f/iScale;
|
||||
}
|
||||
|
||||
bool ModelInstance::intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool StopAtFirstHit) const
|
||||
{
|
||||
if (!iModel)
|
||||
{
|
||||
//std::cout << "<object not loaded>\n";
|
||||
return false;
|
||||
}
|
||||
float time = pRay.intersectionTime(iBound);
|
||||
if (time == G3D::inf())
|
||||
{
|
||||
// std::cout << "Ray does not hit '" << name << "'\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
// std::cout << "Ray crosses bound of '" << name << "'\n";
|
||||
/* std::cout << "ray from:" << pRay.origin().x << ", " << pRay.origin().y << ", " << pRay.origin().z
|
||||
<< " dir:" << pRay.direction().x << ", " << pRay.direction().y << ", " << pRay.direction().z
|
||||
<< " t/tmax:" << time << '/' << pMaxDist;
|
||||
std::cout << "\nBound lo:" << iBound.low().x << ", " << iBound.low().y << ", " << iBound.low().z << " hi: "
|
||||
<< iBound.high().x << ", " << iBound.high().y << ", " << iBound.high().z << std::endl; */
|
||||
// child bounds are defined in object space:
|
||||
Vector3 p = iInvRot * (pRay.origin() - iPos) * iInvScale;
|
||||
Ray modRay(p, iInvRot * pRay.direction());
|
||||
float distance = pMaxDist * iInvScale;
|
||||
bool hit = iModel->IntersectRay(modRay, distance, StopAtFirstHit);
|
||||
if (hit)
|
||||
{
|
||||
distance *= iScale;
|
||||
pMaxDist = distance;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
void ModelInstance::intersectPoint(const G3D::Vector3& p, AreaInfo &info) const
|
||||
{
|
||||
if (!iModel)
|
||||
{
|
||||
#ifdef VMAP_DEBUG
|
||||
std::cout << "<object not loaded>\n";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// M2 files don't contain area info, only WMO files
|
||||
if (flags & MOD_M2)
|
||||
return;
|
||||
if (!iBound.contains(p))
|
||||
return;
|
||||
// child bounds are defined in object space:
|
||||
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
||||
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||
float zDist;
|
||||
if (iModel->IntersectPoint(pModel, zDirModel, zDist, info))
|
||||
{
|
||||
Vector3 modelGround = pModel + zDist * zDirModel;
|
||||
// Transform back to world space. Note that:
|
||||
// Mat * vec == vec * Mat.transpose()
|
||||
// and for rotation matrices: Mat.inverse() == Mat.transpose()
|
||||
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
|
||||
if (info.ground_Z < world_Z)
|
||||
{
|
||||
info.ground_Z = world_Z;
|
||||
info.adtId = adtId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelInstance::GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const
|
||||
{
|
||||
if (!iModel)
|
||||
{
|
||||
#ifdef VMAP_DEBUG
|
||||
std::cout << "<object not loaded>\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// M2 files don't contain area info, only WMO files
|
||||
if (flags & MOD_M2)
|
||||
return false;
|
||||
if (!iBound.contains(p))
|
||||
return false;
|
||||
// child bounds are defined in object space:
|
||||
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
||||
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||
float zDist;
|
||||
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info))
|
||||
{
|
||||
Vector3 modelGround = pModel + zDist * zDirModel;
|
||||
// Transform back to world space. Note that:
|
||||
// Mat * vec == vec * Mat.transpose()
|
||||
// and for rotation matrices: Mat.inverse() == Mat.transpose()
|
||||
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
|
||||
if (info.ground_Z < world_Z) // hm...could it be handled automatically with zDist at intersection?
|
||||
{
|
||||
info.ground_Z = world_Z;
|
||||
info.hitInstance = this;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModelInstance::GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const
|
||||
{
|
||||
// child bounds are defined in object space:
|
||||
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
||||
//Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||
float zDist;
|
||||
if (info.hitModel->GetLiquidLevel(pModel, zDist))
|
||||
{
|
||||
// calculate world height (zDist in model coords):
|
||||
// assume WMO not tilted (wouldn't make much sense anyway)
|
||||
liqHeight = zDist * iScale + iPos.z;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModelSpawn::readFromFile(FILE* rf, ModelSpawn &spawn)
|
||||
{
|
||||
uint32 check = 0, nameLen;
|
||||
check += fread(&spawn.flags, sizeof(uint32), 1, rf);
|
||||
// EoF?
|
||||
if (!check)
|
||||
{
|
||||
if (ferror(rf))
|
||||
std::cout << "Error reading ModelSpawn!\n";
|
||||
return false;
|
||||
}
|
||||
check += fread(&spawn.adtId, sizeof(uint16), 1, rf);
|
||||
check += fread(&spawn.ID, sizeof(uint32), 1, rf);
|
||||
check += fread(&spawn.iPos, sizeof(float), 3, rf);
|
||||
check += fread(&spawn.iRot, sizeof(float), 3, rf);
|
||||
check += fread(&spawn.iScale, sizeof(float), 1, rf);
|
||||
bool has_bound = (spawn.flags & MOD_HAS_BOUND);
|
||||
if (has_bound) // only WMOs have bound in MPQ, only available after computation
|
||||
{
|
||||
Vector3 bLow, bHigh;
|
||||
check += fread(&bLow, sizeof(float), 3, rf);
|
||||
check += fread(&bHigh, sizeof(float), 3, rf);
|
||||
spawn.iBound = G3D::AABox(bLow, bHigh);
|
||||
}
|
||||
check += fread(&nameLen, sizeof(uint32), 1, rf);
|
||||
if (check != uint32(has_bound ? 17 : 11))
|
||||
{
|
||||
std::cout << "Error reading ModelSpawn!\n";
|
||||
return false;
|
||||
}
|
||||
char nameBuff[500];
|
||||
if (nameLen > 500) // file names should never be that long, must be file error
|
||||
{
|
||||
std::cout << "Error reading ModelSpawn, file name too long!\n";
|
||||
return false;
|
||||
}
|
||||
check = fread(nameBuff, sizeof(char), nameLen, rf);
|
||||
if (check != nameLen)
|
||||
{
|
||||
std::cout << "Error reading ModelSpawn!\n";
|
||||
return false;
|
||||
}
|
||||
spawn.name = std::string(nameBuff, nameLen);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModelSpawn::writeToFile(FILE* wf, const ModelSpawn &spawn)
|
||||
{
|
||||
uint32 check=0;
|
||||
check += fwrite(&spawn.flags, sizeof(uint32), 1, wf);
|
||||
check += fwrite(&spawn.adtId, sizeof(uint16), 1, wf);
|
||||
check += fwrite(&spawn.ID, sizeof(uint32), 1, wf);
|
||||
check += fwrite(&spawn.iPos, sizeof(float), 3, wf);
|
||||
check += fwrite(&spawn.iRot, sizeof(float), 3, wf);
|
||||
check += fwrite(&spawn.iScale, sizeof(float), 1, wf);
|
||||
bool has_bound = (spawn.flags & MOD_HAS_BOUND);
|
||||
if (has_bound) // only WMOs have bound in MPQ, only available after computation
|
||||
{
|
||||
check += fwrite(&spawn.iBound.low(), sizeof(float), 3, wf);
|
||||
check += fwrite(&spawn.iBound.high(), sizeof(float), 3, wf);
|
||||
}
|
||||
uint32 nameLen = spawn.name.length();
|
||||
check += fwrite(&nameLen, sizeof(uint32), 1, wf);
|
||||
if (check != uint32(has_bound ? 17 : 11)) return false;
|
||||
check = fwrite(spawn.name.c_str(), sizeof(char), nameLen, wf);
|
||||
if (check != nameLen) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MODELINSTANCE_H_
|
||||
#define _MODELINSTANCE_H_
|
||||
|
||||
#include <G3D/Matrix3.h>
|
||||
#include <G3D/Vector3.h>
|
||||
#include <G3D/AABox.h>
|
||||
#include <G3D/Ray.h>
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
class WorldModel;
|
||||
struct AreaInfo;
|
||||
struct LocationInfo;
|
||||
|
||||
enum ModelFlags
|
||||
{
|
||||
MOD_M2 = 1,
|
||||
MOD_WORLDSPAWN = 1<<1,
|
||||
MOD_HAS_BOUND = 1<<2
|
||||
};
|
||||
|
||||
class ModelSpawn
|
||||
{
|
||||
public:
|
||||
//mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||
uint32 flags;
|
||||
uint16 adtId;
|
||||
uint32 ID;
|
||||
G3D::Vector3 iPos;
|
||||
G3D::Vector3 iRot;
|
||||
float iScale;
|
||||
G3D::AABox iBound;
|
||||
std::string name;
|
||||
bool operator==(const ModelSpawn &other) const { return ID == other.ID; }
|
||||
//uint32 hashCode() const { return ID; }
|
||||
// temp?
|
||||
const G3D::AABox& getBounds() const { return iBound; }
|
||||
|
||||
static bool readFromFile(FILE* rf, ModelSpawn &spawn);
|
||||
static bool writeToFile(FILE* rw, const ModelSpawn &spawn);
|
||||
};
|
||||
|
||||
class ModelInstance: public ModelSpawn
|
||||
{
|
||||
public:
|
||||
ModelInstance(): iInvScale(0.0f), iModel(0) { }
|
||||
ModelInstance(const ModelSpawn &spawn, WorldModel* model);
|
||||
void setUnloaded() { iModel = 0; }
|
||||
bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool StopAtFirstHit) const;
|
||||
void intersectPoint(const G3D::Vector3& p, AreaInfo &info) const;
|
||||
bool GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const;
|
||||
bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const;
|
||||
protected:
|
||||
G3D::Matrix3 iInvRot;
|
||||
float iInvScale;
|
||||
WorldModel* iModel;
|
||||
public:
|
||||
WorldModel* getWorldModel();
|
||||
};
|
||||
} // namespace VMAP
|
||||
|
||||
#endif // _MODELINSTANCE
|
||||
@@ -1,586 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "WorldModel.h"
|
||||
#include "ModelInstance.h"
|
||||
#include "VMapDefinitions.h"
|
||||
#include "MapTree.h"
|
||||
|
||||
using G3D::Vector3;
|
||||
using G3D::Ray;
|
||||
|
||||
template<> struct BoundsTrait<VMAP::GroupModel>
|
||||
{
|
||||
static void getBounds(const VMAP::GroupModel& obj, G3D::AABox& out) { out = obj.GetBound(); }
|
||||
};
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
bool IntersectTriangle(const MeshTriangle &tri, std::vector<Vector3>::const_iterator points, const G3D::Ray &ray, float &distance)
|
||||
{
|
||||
static const float EPS = 1e-5f;
|
||||
|
||||
// See RTR2 ch. 13.7 for the algorithm.
|
||||
|
||||
const Vector3 e1 = points[tri.idx1] - points[tri.idx0];
|
||||
const Vector3 e2 = points[tri.idx2] - points[tri.idx0];
|
||||
const Vector3 p(ray.direction().cross(e2));
|
||||
const float a = e1.dot(p);
|
||||
|
||||
if (fabs(a) < EPS) {
|
||||
// Determinant is ill-conditioned; abort early
|
||||
return false;
|
||||
}
|
||||
|
||||
const float f = 1.0f / a;
|
||||
const Vector3 s(ray.origin() - points[tri.idx0]);
|
||||
const float u = f * s.dot(p);
|
||||
|
||||
if ((u < 0.0f) || (u > 1.0f)) {
|
||||
// We hit the plane of the m_geometry, but outside the m_geometry
|
||||
return false;
|
||||
}
|
||||
|
||||
const Vector3 q(s.cross(e1));
|
||||
const float v = f * ray.direction().dot(q);
|
||||
|
||||
if ((v < 0.0f) || ((u + v) > 1.0f)) {
|
||||
// We hit the plane of the triangle, but outside the triangle
|
||||
return false;
|
||||
}
|
||||
|
||||
const float t = f * e2.dot(q);
|
||||
|
||||
if ((t > 0.0f) && (t < distance))
|
||||
{
|
||||
// This is a new hit, closer than the previous one
|
||||
distance = t;
|
||||
|
||||
/* baryCoord[0] = 1.0 - u - v;
|
||||
baryCoord[1] = u;
|
||||
baryCoord[2] = v; */
|
||||
|
||||
return true;
|
||||
}
|
||||
// This hit is after the previous hit, so ignore it
|
||||
return false;
|
||||
}
|
||||
|
||||
class TriBoundFunc
|
||||
{
|
||||
public:
|
||||
TriBoundFunc(std::vector<Vector3> &vert): vertices(vert.begin()) { }
|
||||
void operator()(const MeshTriangle &tri, G3D::AABox &out) const
|
||||
{
|
||||
G3D::Vector3 lo = vertices[tri.idx0];
|
||||
G3D::Vector3 hi = lo;
|
||||
|
||||
lo = (lo.min(vertices[tri.idx1])).min(vertices[tri.idx2]);
|
||||
hi = (hi.max(vertices[tri.idx1])).max(vertices[tri.idx2]);
|
||||
|
||||
out = G3D::AABox(lo, hi);
|
||||
}
|
||||
protected:
|
||||
const std::vector<Vector3>::const_iterator vertices;
|
||||
};
|
||||
|
||||
// ===================== WmoLiquid ==================================
|
||||
|
||||
WmoLiquid::WmoLiquid(uint32 width, uint32 height, const Vector3 &corner, uint32 type):
|
||||
iTilesX(width), iTilesY(height), iCorner(corner), iType(type)
|
||||
{
|
||||
iHeight = new float[(width+1)*(height+1)];
|
||||
iFlags = new uint8[width*height];
|
||||
}
|
||||
|
||||
WmoLiquid::WmoLiquid(const WmoLiquid &other): iHeight(0), iFlags(0)
|
||||
{
|
||||
*this = other; // use assignment operator...
|
||||
}
|
||||
|
||||
WmoLiquid::~WmoLiquid()
|
||||
{
|
||||
delete[] iHeight;
|
||||
delete[] iFlags;
|
||||
}
|
||||
|
||||
WmoLiquid& WmoLiquid::operator=(const WmoLiquid &other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
iTilesX = other.iTilesX;
|
||||
iTilesY = other.iTilesY;
|
||||
iCorner = other.iCorner;
|
||||
iType = other.iType;
|
||||
delete iHeight;
|
||||
delete iFlags;
|
||||
if (other.iHeight)
|
||||
{
|
||||
iHeight = new float[(iTilesX+1)*(iTilesY+1)];
|
||||
memcpy(iHeight, other.iHeight, (iTilesX+1)*(iTilesY+1)*sizeof(float));
|
||||
}
|
||||
else
|
||||
iHeight = 0;
|
||||
if (other.iFlags)
|
||||
{
|
||||
iFlags = new uint8[iTilesX * iTilesY];
|
||||
memcpy(iFlags, other.iFlags, iTilesX * iTilesY);
|
||||
}
|
||||
else
|
||||
iFlags = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool WmoLiquid::GetLiquidHeight(const Vector3 &pos, float &liqHeight) const
|
||||
{
|
||||
float tx_f = (pos.x - iCorner.x)/LIQUID_TILE_SIZE;
|
||||
uint32 tx = uint32(tx_f);
|
||||
if (tx_f < 0.0f || tx >= iTilesX)
|
||||
return false;
|
||||
float ty_f = (pos.y - iCorner.y)/LIQUID_TILE_SIZE;
|
||||
uint32 ty = uint32(ty_f);
|
||||
if (ty_f < 0.0f || ty >= iTilesY)
|
||||
return false;
|
||||
|
||||
// check if tile shall be used for liquid level
|
||||
// checking for 0x08 *might* be enough, but disabled tiles always are 0x?F:
|
||||
if ((iFlags[tx + ty*iTilesX] & 0x0F) == 0x0F)
|
||||
return false;
|
||||
|
||||
// (dx, dy) coordinates inside tile, in [0, 1]^2
|
||||
float dx = tx_f - (float)tx;
|
||||
float dy = ty_f - (float)ty;
|
||||
|
||||
/* Tesselate tile to two triangles (not sure if client does it exactly like this)
|
||||
|
||||
^ dy
|
||||
|
|
||||
1 x---------x (1, 1)
|
||||
| (b) / |
|
||||
| / |
|
||||
| / |
|
||||
| / (a) |
|
||||
x---------x---> dx
|
||||
0 1
|
||||
*/
|
||||
|
||||
const uint32 rowOffset = iTilesX + 1;
|
||||
if (dx > dy) // case (a)
|
||||
{
|
||||
float sx = iHeight[tx+1 + ty * rowOffset] - iHeight[tx + ty * rowOffset];
|
||||
float sy = iHeight[tx+1 + (ty+1) * rowOffset] - iHeight[tx+1 + ty * rowOffset];
|
||||
liqHeight = iHeight[tx + ty * rowOffset] + dx * sx + dy * sy;
|
||||
}
|
||||
else // case (b)
|
||||
{
|
||||
float sx = iHeight[tx+1 + (ty+1) * rowOffset] - iHeight[tx + (ty+1) * rowOffset];
|
||||
float sy = iHeight[tx + (ty+1) * rowOffset] - iHeight[tx + ty * rowOffset];
|
||||
liqHeight = iHeight[tx + ty * rowOffset] + dx * sx + dy * sy;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 WmoLiquid::GetFileSize()
|
||||
{
|
||||
return 2 * sizeof(uint32) +
|
||||
sizeof(Vector3) +
|
||||
(iTilesX + 1)*(iTilesY + 1) * sizeof(float) +
|
||||
iTilesX * iTilesY;
|
||||
}
|
||||
|
||||
bool WmoLiquid::writeToFile(FILE* wf)
|
||||
{
|
||||
bool result = false;
|
||||
if (fwrite(&iTilesX, sizeof(uint32), 1, wf) == 1 &&
|
||||
fwrite(&iTilesY, sizeof(uint32), 1, wf) == 1 &&
|
||||
fwrite(&iCorner, sizeof(Vector3), 1, wf) == 1 &&
|
||||
fwrite(&iType, sizeof(uint32), 1, wf) == 1)
|
||||
{
|
||||
uint32 size = (iTilesX + 1) * (iTilesY + 1);
|
||||
if (fwrite(iHeight, sizeof(float), size, wf) == size)
|
||||
{
|
||||
size = iTilesX*iTilesY;
|
||||
result = fwrite(iFlags, sizeof(uint8), size, wf) == size;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WmoLiquid::readFromFile(FILE* rf, WmoLiquid* &out)
|
||||
{
|
||||
bool result = false;
|
||||
WmoLiquid* liquid = new WmoLiquid();
|
||||
|
||||
if (fread(&liquid->iTilesX, sizeof(uint32), 1, rf) == 1 &&
|
||||
fread(&liquid->iTilesY, sizeof(uint32), 1, rf) == 1 &&
|
||||
fread(&liquid->iCorner, sizeof(Vector3), 1, rf) == 1 &&
|
||||
fread(&liquid->iType, sizeof(uint32), 1, rf) == 1)
|
||||
{
|
||||
uint32 size = (liquid->iTilesX + 1) * (liquid->iTilesY + 1);
|
||||
liquid->iHeight = new float[size];
|
||||
if (fread(liquid->iHeight, sizeof(float), size, rf) == size)
|
||||
{
|
||||
size = liquid->iTilesX * liquid->iTilesY;
|
||||
liquid->iFlags = new uint8[size];
|
||||
result = fread(liquid->iFlags, sizeof(uint8), size, rf) == size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
delete liquid;
|
||||
else
|
||||
out = liquid;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===================== GroupModel ==================================
|
||||
|
||||
GroupModel::GroupModel(const GroupModel &other):
|
||||
iBound(other.iBound), iMogpFlags(other.iMogpFlags), iGroupWMOID(other.iGroupWMOID),
|
||||
vertices(other.vertices), triangles(other.triangles), meshTree(other.meshTree), iLiquid(0)
|
||||
{
|
||||
if (other.iLiquid)
|
||||
iLiquid = new WmoLiquid(*other.iLiquid);
|
||||
}
|
||||
|
||||
void GroupModel::setMeshData(std::vector<Vector3> &vert, std::vector<MeshTriangle> &tri)
|
||||
{
|
||||
vertices.swap(vert);
|
||||
triangles.swap(tri);
|
||||
TriBoundFunc bFunc(vertices);
|
||||
meshTree.build(triangles, bFunc);
|
||||
}
|
||||
|
||||
bool GroupModel::writeToFile(FILE* wf)
|
||||
{
|
||||
bool result = true;
|
||||
uint32 chunkSize, count;
|
||||
|
||||
if (result && fwrite(&iBound, sizeof(G3D::AABox), 1, wf) != 1) result = false;
|
||||
if (result && fwrite(&iMogpFlags, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
if (result && fwrite(&iGroupWMOID, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
|
||||
// write vertices
|
||||
if (result && fwrite("VERT", 1, 4, wf) != 4) result = false;
|
||||
count = vertices.size();
|
||||
chunkSize = sizeof(uint32)+ sizeof(Vector3)*count;
|
||||
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
if (!count) // models without (collision) geometry end here, unsure if they are useful
|
||||
return result;
|
||||
if (result && fwrite(&vertices[0], sizeof(Vector3), count, wf) != count) result = false;
|
||||
|
||||
// write triangle mesh
|
||||
if (result && fwrite("TRIM", 1, 4, wf) != 4) result = false;
|
||||
count = triangles.size();
|
||||
chunkSize = sizeof(uint32)+ sizeof(MeshTriangle)*count;
|
||||
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
if (result && fwrite(&triangles[0], sizeof(MeshTriangle), count, wf) != count) result = false;
|
||||
|
||||
// write mesh BIH
|
||||
if (result && fwrite("MBIH", 1, 4, wf) != 4) result = false;
|
||||
if (result) result = meshTree.writeToFile(wf);
|
||||
|
||||
// write liquid data
|
||||
if (result && fwrite("LIQU", 1, 4, wf) != 4) result = false;
|
||||
if (!iLiquid)
|
||||
{
|
||||
chunkSize = 0;
|
||||
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
return result;
|
||||
}
|
||||
chunkSize = iLiquid->GetFileSize();
|
||||
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
if (result) result = iLiquid->writeToFile(wf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GroupModel::readFromFile(FILE* rf)
|
||||
{
|
||||
char chunk[8];
|
||||
bool result = true;
|
||||
uint32 chunkSize = 0;
|
||||
uint32 count = 0;
|
||||
triangles.clear();
|
||||
vertices.clear();
|
||||
delete iLiquid;
|
||||
iLiquid = NULL;
|
||||
|
||||
if (result && fread(&iBound, sizeof(G3D::AABox), 1, rf) != 1) result = false;
|
||||
if (result && fread(&iMogpFlags, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
if (result && fread(&iGroupWMOID, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
|
||||
// read vertices
|
||||
if (result && !readChunk(rf, chunk, "VERT", 4)) result = false;
|
||||
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
if (!count) // models without (collision) geometry end here, unsure if they are useful
|
||||
return result;
|
||||
if (result) vertices.resize(count);
|
||||
if (result && fread(&vertices[0], sizeof(Vector3), count, rf) != count) result = false;
|
||||
|
||||
// read triangle mesh
|
||||
if (result && !readChunk(rf, chunk, "TRIM", 4)) result = false;
|
||||
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
if (result) triangles.resize(count);
|
||||
if (result && fread(&triangles[0], sizeof(MeshTriangle), count, rf) != count) result = false;
|
||||
|
||||
// read mesh BIH
|
||||
if (result && !readChunk(rf, chunk, "MBIH", 4)) result = false;
|
||||
if (result) result = meshTree.readFromFile(rf);
|
||||
|
||||
// write liquid data
|
||||
if (result && !readChunk(rf, chunk, "LIQU", 4)) result = false;
|
||||
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
if (result && chunkSize > 0)
|
||||
result = WmoLiquid::readFromFile(rf, iLiquid);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct GModelRayCallback
|
||||
{
|
||||
GModelRayCallback(const std::vector<MeshTriangle> &tris, const std::vector<Vector3> &vert):
|
||||
vertices(vert.begin()), triangles(tris.begin()), hit(false) { }
|
||||
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool /*StopAtFirstHit*/)
|
||||
{
|
||||
bool result = IntersectTriangle(triangles[entry], vertices, ray, distance);
|
||||
if (result) hit=true;
|
||||
return hit;
|
||||
}
|
||||
std::vector<Vector3>::const_iterator vertices;
|
||||
std::vector<MeshTriangle>::const_iterator triangles;
|
||||
bool hit;
|
||||
};
|
||||
|
||||
bool GroupModel::IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const
|
||||
{
|
||||
if (triangles.empty())
|
||||
return false;
|
||||
|
||||
GModelRayCallback callback(triangles, vertices);
|
||||
meshTree.intersectRay(ray, callback, distance, stopAtFirstHit);
|
||||
return callback.hit;
|
||||
}
|
||||
|
||||
bool GroupModel::IsInsideObject(const Vector3 &pos, const Vector3 &down, float &z_dist) const
|
||||
{
|
||||
if (triangles.empty() || !iBound.contains(pos))
|
||||
return false;
|
||||
GModelRayCallback callback(triangles, vertices);
|
||||
Vector3 rPos = pos - 0.1f * down;
|
||||
float dist = G3D::inf();
|
||||
G3D::Ray ray(rPos, down);
|
||||
bool hit = IntersectRay(ray, dist, false);
|
||||
if (hit)
|
||||
z_dist = dist - 0.1f;
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool GroupModel::GetLiquidLevel(const Vector3 &pos, float &liqHeight) const
|
||||
{
|
||||
if (iLiquid)
|
||||
return iLiquid->GetLiquidHeight(pos, liqHeight);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 GroupModel::GetLiquidType() const
|
||||
{
|
||||
if (iLiquid)
|
||||
return iLiquid->GetType();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ===================== WorldModel ==================================
|
||||
|
||||
void WorldModel::setGroupModels(std::vector<GroupModel> &models)
|
||||
{
|
||||
groupModels.swap(models);
|
||||
groupTree.build(groupModels, BoundsTrait<GroupModel>::getBounds, 1);
|
||||
}
|
||||
|
||||
struct WModelRayCallBack
|
||||
{
|
||||
WModelRayCallBack(const std::vector<GroupModel> &mod): models(mod.begin()), hit(false) { }
|
||||
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool StopAtFirstHit)
|
||||
{
|
||||
bool result = models[entry].IntersectRay(ray, distance, StopAtFirstHit);
|
||||
if (result) hit=true;
|
||||
return hit;
|
||||
}
|
||||
std::vector<GroupModel>::const_iterator models;
|
||||
bool hit;
|
||||
};
|
||||
|
||||
bool WorldModel::IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const
|
||||
{
|
||||
// small M2 workaround, maybe better make separate class with virtual intersection funcs
|
||||
// in any case, there's no need to use a bound tree if we only have one submodel
|
||||
if (groupModels.size() == 1)
|
||||
return groupModels[0].IntersectRay(ray, distance, stopAtFirstHit);
|
||||
|
||||
WModelRayCallBack isc(groupModels);
|
||||
groupTree.intersectRay(ray, isc, distance, stopAtFirstHit);
|
||||
return isc.hit;
|
||||
}
|
||||
|
||||
class WModelAreaCallback {
|
||||
public:
|
||||
WModelAreaCallback(const std::vector<GroupModel> &vals, const Vector3 &down):
|
||||
prims(vals.begin()), hit(vals.end()), minVol(G3D::inf()), zDist(G3D::inf()), zVec(down) { }
|
||||
std::vector<GroupModel>::const_iterator prims;
|
||||
std::vector<GroupModel>::const_iterator hit;
|
||||
float minVol;
|
||||
float zDist;
|
||||
Vector3 zVec;
|
||||
void operator()(const Vector3& point, uint32 entry)
|
||||
{
|
||||
float group_Z;
|
||||
//float pVol = prims[entry].GetBound().volume();
|
||||
//if (pVol < minVol)
|
||||
//{
|
||||
/* if (prims[entry].iBound.contains(point)) */
|
||||
if (prims[entry].IsInsideObject(point, zVec, group_Z))
|
||||
{
|
||||
//minVol = pVol;
|
||||
//hit = prims + entry;
|
||||
if (group_Z < zDist)
|
||||
{
|
||||
zDist = group_Z;
|
||||
hit = prims + entry;
|
||||
}
|
||||
#ifdef VMAP_DEBUG
|
||||
const GroupModel &gm = prims[entry];
|
||||
printf("%10u %8X %7.3f, %7.3f, %7.3f | %7.3f, %7.3f, %7.3f | z=%f, p_z=%f\n", gm.GetWmoID(), gm.GetMogpFlags(),
|
||||
gm.GetBound().low().x, gm.GetBound().low().y, gm.GetBound().low().z,
|
||||
gm.GetBound().high().x, gm.GetBound().high().y, gm.GetBound().high().z, group_Z, point.z);
|
||||
#endif
|
||||
}
|
||||
//}
|
||||
//std::cout << "trying to intersect '" << prims[entry].name << "'\n";
|
||||
}
|
||||
};
|
||||
|
||||
bool WorldModel::IntersectPoint(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, AreaInfo &info) const
|
||||
{
|
||||
if (groupModels.empty())
|
||||
return false;
|
||||
|
||||
WModelAreaCallback callback(groupModels, down);
|
||||
groupTree.intersectPoint(p, callback);
|
||||
if (callback.hit != groupModels.end())
|
||||
{
|
||||
info.rootId = RootWMOID;
|
||||
info.groupId = callback.hit->GetWmoID();
|
||||
info.flags = callback.hit->GetMogpFlags();
|
||||
info.result = true;
|
||||
dist = callback.zDist;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WorldModel::GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, LocationInfo &info) const
|
||||
{
|
||||
if (groupModels.empty())
|
||||
return false;
|
||||
|
||||
WModelAreaCallback callback(groupModels, down);
|
||||
groupTree.intersectPoint(p, callback);
|
||||
if (callback.hit != groupModels.end())
|
||||
{
|
||||
info.hitModel = &(*callback.hit);
|
||||
dist = callback.zDist;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WorldModel::writeFile(const std::string &filename)
|
||||
{
|
||||
FILE* wf = fopen(filename.c_str(), "wb");
|
||||
if (!wf)
|
||||
return false;
|
||||
|
||||
uint32 chunkSize, count;
|
||||
bool result = fwrite(VMAP_MAGIC, 1, 8, wf) == 8;
|
||||
if (result && fwrite("WMOD", 1, 4, wf) != 4) result = false;
|
||||
chunkSize = sizeof(uint32) + sizeof(uint32);
|
||||
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
if (result && fwrite(&RootWMOID, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
|
||||
// write group models
|
||||
count=groupModels.size();
|
||||
if (count)
|
||||
{
|
||||
if (result && fwrite("GMOD", 1, 4, wf) != 4) result = false;
|
||||
//chunkSize = sizeof(uint32)+ sizeof(GroupModel)*count;
|
||||
//if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
|
||||
for (uint32 i=0; i<groupModels.size() && result; ++i)
|
||||
result = groupModels[i].writeToFile(wf);
|
||||
|
||||
// write group BIH
|
||||
if (result && fwrite("GBIH", 1, 4, wf) != 4) result = false;
|
||||
if (result) result = groupTree.writeToFile(wf);
|
||||
}
|
||||
|
||||
fclose(wf);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WorldModel::readFile(const std::string &filename)
|
||||
{
|
||||
FILE* rf = fopen(filename.c_str(), "rb");
|
||||
if (!rf)
|
||||
return false;
|
||||
|
||||
bool result = true;
|
||||
uint32 chunkSize = 0;
|
||||
uint32 count = 0;
|
||||
char chunk[8]; // Ignore the added magic header
|
||||
if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) result = false;
|
||||
|
||||
if (result && !readChunk(rf, chunk, "WMOD", 4)) result = false;
|
||||
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
if (result && fread(&RootWMOID, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
|
||||
// read group models
|
||||
if (result && readChunk(rf, chunk, "GMOD", 4))
|
||||
{
|
||||
//if (fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
|
||||
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
|
||||
if (result) groupModels.resize(count);
|
||||
//if (result && fread(&groupModels[0], sizeof(GroupModel), count, rf) != count) result = false;
|
||||
for (uint32 i=0; i<count && result; ++i)
|
||||
result = groupModels[i].readFromFile(rf);
|
||||
|
||||
// read group BIH
|
||||
if (result && !readChunk(rf, chunk, "GBIH", 4)) result = false;
|
||||
if (result) result = groupTree.readFromFile(rf);
|
||||
}
|
||||
|
||||
fclose(rf);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _WORLDMODEL_H
|
||||
#define _WORLDMODEL_H
|
||||
|
||||
#include <G3D/HashTrait.h>
|
||||
#include <G3D/Vector3.h>
|
||||
#include <G3D/AABox.h>
|
||||
#include <G3D/Ray.h>
|
||||
#include "BoundingIntervalHierarchy.h"
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
class TreeNode;
|
||||
struct AreaInfo;
|
||||
struct LocationInfo;
|
||||
|
||||
class MeshTriangle
|
||||
{
|
||||
public:
|
||||
MeshTriangle() : idx0(0), idx1(0), idx2(0) { }
|
||||
MeshTriangle(uint32 na, uint32 nb, uint32 nc): idx0(na), idx1(nb), idx2(nc) { }
|
||||
|
||||
uint32 idx0;
|
||||
uint32 idx1;
|
||||
uint32 idx2;
|
||||
};
|
||||
|
||||
class WmoLiquid
|
||||
{
|
||||
public:
|
||||
WmoLiquid(uint32 width, uint32 height, const G3D::Vector3 &corner, uint32 type);
|
||||
WmoLiquid(const WmoLiquid &other);
|
||||
~WmoLiquid();
|
||||
WmoLiquid& operator=(const WmoLiquid &other);
|
||||
bool GetLiquidHeight(const G3D::Vector3 &pos, float &liqHeight) const;
|
||||
uint32 GetType() const { return iType; }
|
||||
float *GetHeightStorage() { return iHeight; }
|
||||
uint8 *GetFlagsStorage() { return iFlags; }
|
||||
uint32 GetFileSize();
|
||||
bool writeToFile(FILE* wf);
|
||||
static bool readFromFile(FILE* rf, WmoLiquid* &liquid);
|
||||
private:
|
||||
WmoLiquid(): iTilesX(0), iTilesY(0), iType(0), iHeight(0), iFlags(0) { }
|
||||
uint32 iTilesX; //!< number of tiles in x direction, each
|
||||
uint32 iTilesY;
|
||||
G3D::Vector3 iCorner; //!< the lower corner
|
||||
uint32 iType; //!< liquid type
|
||||
float *iHeight; //!< (tilesX + 1)*(tilesY + 1) height values
|
||||
uint8 *iFlags; //!< info if liquid tile is used
|
||||
public:
|
||||
void getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const;
|
||||
};
|
||||
|
||||
/*! holding additional info for WMO group files */
|
||||
class GroupModel
|
||||
{
|
||||
public:
|
||||
GroupModel(): iMogpFlags(0), iGroupWMOID(0), iLiquid(0) { }
|
||||
GroupModel(const GroupModel &other);
|
||||
GroupModel(uint32 mogpFlags, uint32 groupWMOID, const G3D::AABox &bound):
|
||||
iBound(bound), iMogpFlags(mogpFlags), iGroupWMOID(groupWMOID), iLiquid(0) { }
|
||||
~GroupModel() { delete iLiquid; }
|
||||
|
||||
//! pass mesh data to object and create BIH. Passed vectors get get swapped with old geometry!
|
||||
void setMeshData(std::vector<G3D::Vector3> &vert, std::vector<MeshTriangle> &tri);
|
||||
void setLiquidData(WmoLiquid*& liquid) { iLiquid = liquid; liquid = NULL; }
|
||||
bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const;
|
||||
bool IsInsideObject(const G3D::Vector3 &pos, const G3D::Vector3 &down, float &z_dist) const;
|
||||
bool GetLiquidLevel(const G3D::Vector3 &pos, float &liqHeight) const;
|
||||
uint32 GetLiquidType() const;
|
||||
bool writeToFile(FILE* wf);
|
||||
bool readFromFile(FILE* rf);
|
||||
const G3D::AABox& GetBound() const { return iBound; }
|
||||
uint32 GetMogpFlags() const { return iMogpFlags; }
|
||||
uint32 GetWmoID() const { return iGroupWMOID; }
|
||||
protected:
|
||||
G3D::AABox iBound;
|
||||
uint32 iMogpFlags;// 0x8 outdor; 0x2000 indoor
|
||||
uint32 iGroupWMOID;
|
||||
std::vector<G3D::Vector3> vertices;
|
||||
std::vector<MeshTriangle> triangles;
|
||||
BIH meshTree;
|
||||
WmoLiquid* iLiquid;
|
||||
public:
|
||||
void getMeshData(std::vector<G3D::Vector3> &vertices, std::vector<MeshTriangle> &triangles, WmoLiquid* &liquid);
|
||||
};
|
||||
/*! Holds a model (converted M2 or WMO) in its original coordinate space */
|
||||
class WorldModel
|
||||
{
|
||||
public:
|
||||
WorldModel(): RootWMOID(0) { }
|
||||
|
||||
//! pass group models to WorldModel and create BIH. Passed vector is swapped with old geometry!
|
||||
void setGroupModels(std::vector<GroupModel> &models);
|
||||
void setRootWmoID(uint32 id) { RootWMOID = id; }
|
||||
bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const;
|
||||
bool IntersectPoint(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, AreaInfo &info) const;
|
||||
bool GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, LocationInfo &info) const;
|
||||
bool writeFile(const std::string &filename);
|
||||
bool readFile(const std::string &filename);
|
||||
protected:
|
||||
uint32 RootWMOID;
|
||||
std::vector<GroupModel> groupModels;
|
||||
BIH groupTree;
|
||||
public:
|
||||
void getGroupModels(std::vector<GroupModel> &groupModels);
|
||||
};
|
||||
} // namespace VMAP
|
||||
|
||||
#endif // _WORLDMODEL_H
|
||||
@@ -1 +0,0 @@
|
||||
#include "collisionPCH.h"
|
||||
@@ -1,9 +0,0 @@
|
||||
#include "Define.h"
|
||||
#include "VMapDefinitions.h"
|
||||
#include "MapTree.h"
|
||||
#include "WorldModel.h"
|
||||
#include "ModelInstance.h"
|
||||
#include "BoundingIntervalHierarchy.h"
|
||||
#include "RegularGrid.h"
|
||||
#include "BoundingIntervalHierarchyWrapper.h"
|
||||
#include "GameObjectModel.h"
|
||||
@@ -1,264 +0,0 @@
|
||||
#ifndef _REGULAR_GRID_H
|
||||
#define _REGULAR_GRID_H
|
||||
|
||||
|
||||
#include <G3D/Ray.h>
|
||||
#include <G3D/Table.h>
|
||||
#include <G3D/BoundsTrait.h>
|
||||
#include <G3D/PositionTrait.h>
|
||||
|
||||
#include "Errors.h"
|
||||
|
||||
template <class Node>
|
||||
class NodeArray
|
||||
{
|
||||
public:
|
||||
explicit NodeArray() { memset(&_nodes, 0, sizeof(_nodes)); }
|
||||
void AddNode(Node* n)
|
||||
{
|
||||
for (uint8 i=0; i<9; ++i)
|
||||
if (_nodes[i] == 0)
|
||||
{
|
||||
_nodes[i] = n;
|
||||
return;
|
||||
}
|
||||
else if (_nodes[i] == n)
|
||||
return;
|
||||
}
|
||||
Node* _nodes[9];
|
||||
};
|
||||
|
||||
template<class Node>
|
||||
struct NodeCreator{
|
||||
static Node * makeNode(int /*x*/, int /*y*/) { return new Node();}
|
||||
};
|
||||
|
||||
template<class T,
|
||||
class Node,
|
||||
class NodeCreatorFunc = NodeCreator<Node>,
|
||||
/*class BoundsFunc = BoundsTrait<T>,*/
|
||||
class PositionFunc = PositionTrait<T>
|
||||
>
|
||||
class RegularGrid2D
|
||||
{
|
||||
public:
|
||||
|
||||
enum{
|
||||
CELL_NUMBER = 64,
|
||||
};
|
||||
|
||||
#define HGRID_MAP_SIZE (533.33333f * 64.f) // shouldn't be changed
|
||||
#define CELL_SIZE float(HGRID_MAP_SIZE/(float)CELL_NUMBER)
|
||||
|
||||
typedef G3D::Table<const T*, NodeArray<Node> > MemberTable;
|
||||
|
||||
MemberTable memberTable;
|
||||
Node* nodes[CELL_NUMBER][CELL_NUMBER];
|
||||
|
||||
RegularGrid2D(){
|
||||
memset(nodes, 0, sizeof(nodes));
|
||||
}
|
||||
|
||||
~RegularGrid2D(){
|
||||
for (int x = 0; x < CELL_NUMBER; ++x)
|
||||
for (int y = 0; y < CELL_NUMBER; ++y)
|
||||
delete nodes[x][y];
|
||||
}
|
||||
|
||||
void insert(const T& value)
|
||||
{
|
||||
G3D::Vector3 pos[9];
|
||||
pos[0] = value.getBounds().corner(0);
|
||||
pos[1] = value.getBounds().corner(1);
|
||||
pos[2] = value.getBounds().corner(2);
|
||||
pos[3] = value.getBounds().corner(3);
|
||||
pos[4] = (pos[0] + pos[1])/2.0f;
|
||||
pos[5] = (pos[1] + pos[2])/2.0f;
|
||||
pos[6] = (pos[2] + pos[3])/2.0f;
|
||||
pos[7] = (pos[3] + pos[0])/2.0f;
|
||||
pos[8] = (pos[0] + pos[2])/2.0f;
|
||||
|
||||
NodeArray<Node> na;
|
||||
for (uint8 i=0; i<9; ++i)
|
||||
{
|
||||
Cell c = Cell::ComputeCell(pos[i].x, pos[i].y);
|
||||
if (!c.isValid())
|
||||
continue;
|
||||
Node& node = getGridFor(pos[i].x, pos[i].y);
|
||||
na.AddNode(&node);
|
||||
}
|
||||
|
||||
for (uint8 i=0; i<9; ++i)
|
||||
{
|
||||
if (na._nodes[i])
|
||||
na._nodes[i]->insert(value);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
memberTable.set(&value, na);
|
||||
}
|
||||
|
||||
void remove(const T& value)
|
||||
{
|
||||
NodeArray<Node>& na = memberTable[&value];
|
||||
for (uint8 i=0; i<9; ++i)
|
||||
{
|
||||
if (na._nodes[i])
|
||||
na._nodes[i]->remove(value);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the member
|
||||
memberTable.remove(&value);
|
||||
}
|
||||
|
||||
void balance()
|
||||
{
|
||||
for (int x = 0; x < CELL_NUMBER; ++x)
|
||||
for (int y = 0; y < CELL_NUMBER; ++y)
|
||||
if (Node* n = nodes[x][y])
|
||||
n->balance();
|
||||
}
|
||||
|
||||
bool contains(const T& value) const { return memberTable.containsKey(&value); }
|
||||
int size() const { return memberTable.size(); }
|
||||
|
||||
struct Cell
|
||||
{
|
||||
int x, y;
|
||||
bool operator == (const Cell& c2) const { return x == c2.x && y == c2.y;}
|
||||
|
||||
static Cell ComputeCell(float fx, float fy)
|
||||
{
|
||||
Cell c = { int(fx * (1.f/CELL_SIZE) + (CELL_NUMBER/2)), int(fy * (1.f/CELL_SIZE) + (CELL_NUMBER/2)) };
|
||||
return c;
|
||||
}
|
||||
|
||||
bool isValid() const { return x >= 0 && x < CELL_NUMBER && y >= 0 && y < CELL_NUMBER;}
|
||||
};
|
||||
|
||||
|
||||
Node& getGridFor(float fx, float fy)
|
||||
{
|
||||
Cell c = Cell::ComputeCell(fx, fy);
|
||||
return getGrid(c.x, c.y);
|
||||
}
|
||||
|
||||
Node& getGrid(int x, int y)
|
||||
{
|
||||
ASSERT(x < CELL_NUMBER && y < CELL_NUMBER);
|
||||
if (!nodes[x][y])
|
||||
nodes[x][y] = NodeCreatorFunc::makeNode(x, y);
|
||||
return *nodes[x][y];
|
||||
}
|
||||
|
||||
template<typename RayCallback>
|
||||
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float max_dist, bool stopAtFirstHit)
|
||||
{
|
||||
intersectRay(ray, intersectCallback, max_dist, ray.origin() + ray.direction() * max_dist, stopAtFirstHit);
|
||||
}
|
||||
|
||||
template<typename RayCallback>
|
||||
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& max_dist, const G3D::Vector3& end, bool stopAtFirstHit)
|
||||
{
|
||||
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
|
||||
if (!cell.isValid())
|
||||
return;
|
||||
|
||||
Cell last_cell = Cell::ComputeCell(end.x, end.y);
|
||||
|
||||
if (cell == last_cell)
|
||||
{
|
||||
if (Node* node = nodes[cell.x][cell.y])
|
||||
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
|
||||
return;
|
||||
}
|
||||
|
||||
float voxel = (float)CELL_SIZE;
|
||||
float kx_inv = ray.invDirection().x, bx = ray.origin().x;
|
||||
float ky_inv = ray.invDirection().y, by = ray.origin().y;
|
||||
|
||||
int stepX, stepY;
|
||||
float tMaxX, tMaxY;
|
||||
if (kx_inv >= 0)
|
||||
{
|
||||
stepX = 1;
|
||||
float x_border = (cell.x+1) * voxel;
|
||||
tMaxX = (x_border - bx) * kx_inv;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepX = -1;
|
||||
float x_border = (cell.x-1) * voxel;
|
||||
tMaxX = (x_border - bx) * kx_inv;
|
||||
}
|
||||
|
||||
if (ky_inv >= 0)
|
||||
{
|
||||
stepY = 1;
|
||||
float y_border = (cell.y+1) * voxel;
|
||||
tMaxY = (y_border - by) * ky_inv;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepY = -1;
|
||||
float y_border = (cell.y-1) * voxel;
|
||||
tMaxY = (y_border - by) * ky_inv;
|
||||
}
|
||||
|
||||
//int Cycles = std::max((int)ceilf(max_dist/tMaxX),(int)ceilf(max_dist/tMaxY));
|
||||
//int i = 0;
|
||||
|
||||
float tDeltaX = voxel * fabs(kx_inv);
|
||||
float tDeltaY = voxel * fabs(ky_inv);
|
||||
do
|
||||
{
|
||||
if (Node* node = nodes[cell.x][cell.y])
|
||||
{
|
||||
//float enterdist = max_dist;
|
||||
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
|
||||
}
|
||||
if (cell == last_cell)
|
||||
break;
|
||||
if (tMaxX < tMaxY)
|
||||
{
|
||||
tMaxX += tDeltaX;
|
||||
cell.x += stepX;
|
||||
}
|
||||
else
|
||||
{
|
||||
tMaxY += tDeltaY;
|
||||
cell.y += stepY;
|
||||
}
|
||||
//++i;
|
||||
} while (cell.isValid());
|
||||
}
|
||||
|
||||
template<typename IsectCallback>
|
||||
void intersectPoint(const G3D::Vector3& point, IsectCallback& intersectCallback)
|
||||
{
|
||||
Cell cell = Cell::ComputeCell(point.x, point.y);
|
||||
if (!cell.isValid())
|
||||
return;
|
||||
if (Node* node = nodes[cell.x][cell.y])
|
||||
node->intersectPoint(point, intersectCallback);
|
||||
}
|
||||
|
||||
// Optimized verson of intersectRay function for rays with vertical directions
|
||||
template<typename RayCallback>
|
||||
void intersectZAllignedRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& max_dist)
|
||||
{
|
||||
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
|
||||
if (!cell.isValid())
|
||||
return;
|
||||
if (Node* node = nodes[cell.x][cell.y])
|
||||
node->intersectRay(ray, intersectCallback, max_dist, false);
|
||||
}
|
||||
};
|
||||
|
||||
#undef CELL_SIZE
|
||||
#undef HGRID_MAP_SIZE
|
||||
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _VMAPDEFINITIONS_H
|
||||
#define _VMAPDEFINITIONS_H
|
||||
#include <cstring>
|
||||
|
||||
#define LIQUID_TILE_SIZE (533.333f / 128.f)
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
const char VMAP_MAGIC[] = "VMAP_4.1";
|
||||
const char RAW_VMAP_MAGIC[] = "VMAP041"; // used in extracted vmap files with raw data
|
||||
const char GAMEOBJECT_MODELS[] = "GameObjectModels.dtree";
|
||||
|
||||
// defined in TileAssembler.cpp currently...
|
||||
bool readChunk(FILE* rf, char *dest, const char *compare, uint32 len);
|
||||
}
|
||||
#endif
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _VMAPTOOLS_H
|
||||
#define _VMAPTOOLS_H
|
||||
|
||||
#include <G3D/CollisionDetection.h>
|
||||
#include <G3D/AABox.h>
|
||||
|
||||
#include "NodeValueAccess.h"
|
||||
|
||||
/**
|
||||
The Class is mainly taken from G3D/AABSPTree.h but modified to be able to use our internal data structure.
|
||||
This is an iterator that helps us analysing the BSP-Trees.
|
||||
The collision detection is modified to return true, if we are inside an object.
|
||||
*/
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
template<class TValue>
|
||||
class IntersectionCallBack {
|
||||
public:
|
||||
TValue* closestEntity;
|
||||
G3D::Vector3 hitLocation;
|
||||
G3D::Vector3 hitNormal;
|
||||
|
||||
void operator()(const G3D::Ray& ray, const TValue* entity, bool StopAtFirstHit, float& distance) {
|
||||
entity->intersect(ray, distance, StopAtFirstHit, hitLocation, hitNormal);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================
|
||||
//==============================================================
|
||||
//==============================================================
|
||||
|
||||
class MyCollisionDetection
|
||||
{
|
||||
private:
|
||||
public:
|
||||
|
||||
static bool collisionLocationForMovingPointFixedAABox(
|
||||
const G3D::Vector3& origin,
|
||||
const G3D::Vector3& dir,
|
||||
const G3D::AABox& box,
|
||||
G3D::Vector3& location,
|
||||
bool& Inside)
|
||||
{
|
||||
|
||||
// Integer representation of a floating-point value.
|
||||
#define IR(x) (reinterpret_cast<G3D::uint32 const&>(x))
|
||||
|
||||
Inside = true;
|
||||
const G3D::Vector3& MinB = box.low();
|
||||
const G3D::Vector3& MaxB = box.high();
|
||||
G3D::Vector3 MaxT(-1.0f, -1.0f, -1.0f);
|
||||
|
||||
// Find candidate planes.
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (origin[i] < MinB[i])
|
||||
{
|
||||
location[i] = MinB[i];
|
||||
Inside = false;
|
||||
|
||||
// Calculate T distances to candidate planes
|
||||
if (IR(dir[i]))
|
||||
{
|
||||
MaxT[i] = (MinB[i] - origin[i]) / dir[i];
|
||||
}
|
||||
}
|
||||
else if (origin[i] > MaxB[i])
|
||||
{
|
||||
location[i] = MaxB[i];
|
||||
Inside = false;
|
||||
|
||||
// Calculate T distances to candidate planes
|
||||
if (IR(dir[i]))
|
||||
{
|
||||
MaxT[i] = (MaxB[i] - origin[i]) / dir[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Inside)
|
||||
{
|
||||
// definite hit
|
||||
location = origin;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get largest of the maxT's for final choice of intersection
|
||||
int WhichPlane = 0;
|
||||
if (MaxT[1] > MaxT[WhichPlane])
|
||||
{
|
||||
WhichPlane = 1;
|
||||
}
|
||||
|
||||
if (MaxT[2] > MaxT[WhichPlane])
|
||||
{
|
||||
WhichPlane = 2;
|
||||
}
|
||||
|
||||
// Check final candidate actually inside box
|
||||
if (IR(MaxT[WhichPlane]) & 0x80000000)
|
||||
{
|
||||
// Miss the box
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (i != WhichPlane)
|
||||
{
|
||||
location[i] = origin[i] + MaxT[WhichPlane] * dir[i];
|
||||
if ((location[i] < MinB[i]) ||
|
||||
(location[i] > MaxB[i]))
|
||||
{
|
||||
// On this plane we're outside the box extents, so
|
||||
// we miss the box
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Choose the normal to be the plane normal facing into the ray
|
||||
normal = G3D::Vector3::zero();
|
||||
normal[WhichPlane] = (dir[WhichPlane] > 0) ? -1.0 : 1.0;
|
||||
*/
|
||||
return true;
|
||||
|
||||
#undef IR
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CHARGE = 22911,
|
||||
SPELL_CLEAVE = 40504,
|
||||
SPELL_DEMORALIZING_SHOUT = 23511,
|
||||
SPELL_ENRAGE = 8599,
|
||||
SPELL_WHIRLWIND = 13736,
|
||||
|
||||
SPELL_NORTH_MARSHAL = 45828,
|
||||
SPELL_SOUTH_MARSHAL = 45829,
|
||||
SPELL_STONEHEARTH_MARSHAL = 45830,
|
||||
SPELL_ICEWING_MARSHAL = 45831,
|
||||
SPELL_ICEBLOOD_WARMASTER = 45822,
|
||||
SPELL_TOWER_POINT_WARMASTER = 45823,
|
||||
SPELL_WEST_FROSTWOLF_WARMASTER = 45824,
|
||||
SPELL_EAST_FROSTWOLF_WARMASTER = 45826
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_NORTH_MARSHAL = 14762,
|
||||
NPC_SOUTH_MARSHAL = 14763,
|
||||
NPC_ICEWING_MARSHAL = 14764,
|
||||
NPC_STONEHEARTH_MARSHAL = 14765,
|
||||
NPC_EAST_FROSTWOLF_WARMASTER = 14772,
|
||||
NPC_ICEBLOOD_WARMASTER = 14773,
|
||||
NPC_TOWER_POINT_WARMASTER = 14776,
|
||||
NPC_WEST_FROSTWOLF_WARMASTER = 14777
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_CHARGE_TARGET = 1,
|
||||
EVENT_CLEAVE = 2,
|
||||
EVENT_DEMORALIZING_SHOUT = 3,
|
||||
EVENT_WHIRLWIND = 4,
|
||||
EVENT_ENRAGE = 5,
|
||||
EVENT_CHECK_RESET = 6
|
||||
};
|
||||
|
||||
struct SpellPair
|
||||
{
|
||||
uint32 npcEntry;
|
||||
uint32 spellId;
|
||||
};
|
||||
|
||||
uint8 const MAX_SPELL_PAIRS = 8;
|
||||
SpellPair const _auraPairs[MAX_SPELL_PAIRS] =
|
||||
{
|
||||
{ NPC_NORTH_MARSHAL, SPELL_NORTH_MARSHAL },
|
||||
{ NPC_SOUTH_MARSHAL, SPELL_SOUTH_MARSHAL },
|
||||
{ NPC_STONEHEARTH_MARSHAL, SPELL_STONEHEARTH_MARSHAL },
|
||||
{ NPC_ICEWING_MARSHAL, SPELL_ICEWING_MARSHAL },
|
||||
{ NPC_EAST_FROSTWOLF_WARMASTER, SPELL_EAST_FROSTWOLF_WARMASTER },
|
||||
{ NPC_WEST_FROSTWOLF_WARMASTER, SPELL_WEST_FROSTWOLF_WARMASTER },
|
||||
{ NPC_TOWER_POINT_WARMASTER, SPELL_TOWER_POINT_WARMASTER },
|
||||
{ NPC_ICEBLOOD_WARMASTER, SPELL_ICEBLOOD_WARMASTER }
|
||||
};
|
||||
|
||||
class npc_av_marshal_or_warmaster : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_av_marshal_or_warmaster() : CreatureScript("npc_av_marshal_or_warmaster") { }
|
||||
|
||||
struct npc_av_marshal_or_warmasterAI : public ScriptedAI
|
||||
{
|
||||
npc_av_marshal_or_warmasterAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_CHARGE_TARGET, urand(2 * IN_MILLISECONDS, 12 * IN_MILLISECONDS));
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(1 * IN_MILLISECONDS, 11 * IN_MILLISECONDS));
|
||||
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 2000);
|
||||
events.ScheduleEvent(EVENT_WHIRLWIND, urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
|
||||
events.ScheduleEvent(EVENT_ENRAGE, urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
|
||||
events.ScheduleEvent(EVENT_CHECK_RESET, 5000);
|
||||
|
||||
_hasAura = false;
|
||||
}
|
||||
|
||||
void JustRespawned()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
// I have a feeling this isn't blizzlike, but owell, I'm only passing by and cleaning up.
|
||||
if (!_hasAura)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_SPELL_PAIRS; ++i)
|
||||
if (_auraPairs[i].npcEntry == me->GetEntry())
|
||||
DoCast(me, _auraPairs[i].spellId);
|
||||
|
||||
_hasAura = true;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CHARGE_TARGET:
|
||||
DoCastVictim(SPELL_CHARGE);
|
||||
events.ScheduleEvent(EVENT_CHARGE, urand(10 * IN_MILLISECONDS, 25 * IN_MILLISECONDS));
|
||||
break;
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(10 * IN_MILLISECONDS, 16 * IN_MILLISECONDS));
|
||||
break;
|
||||
case EVENT_DEMORALIZING_SHOUT:
|
||||
DoCast(me, SPELL_DEMORALIZING_SHOUT);
|
||||
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
|
||||
break;
|
||||
case EVENT_WHIRLWIND:
|
||||
DoCast(me, SPELL_WHIRLWIND);
|
||||
events.ScheduleEvent(EVENT_WHIRLWIND, urand(10 * IN_MILLISECONDS, 25 * IN_MILLISECONDS));
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, urand(10 * IN_MILLISECONDS, 30 * IN_MILLISECONDS));
|
||||
break;
|
||||
case EVENT_CHECK_RESET:
|
||||
{
|
||||
Position const& _homePosition = me->GetHomePosition();
|
||||
if (me->GetDistance2d(_homePosition.GetPositionX(), _homePosition.GetPositionY()) > 50.0f)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_RESET, 5000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
bool _hasAura;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new npc_av_marshal_or_warmasterAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_alterac_valley()
|
||||
{
|
||||
new npc_av_marshal_or_warmaster();
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_ARCANE_EXPLOSION = 46608,
|
||||
SPELL_CONE_OF_COLD = 38384,
|
||||
SPELL_FIREBALL = 46988,
|
||||
SPELL_FROSTBOLT = 46987
|
||||
};
|
||||
|
||||
enum Yells
|
||||
{
|
||||
YELL_AGGRO = 0,
|
||||
YELL_EVADE = 1,
|
||||
YELL_SALVATION = 2,
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_WATER_ELEMENTAL = 25040
|
||||
};
|
||||
|
||||
enum WaterElementalSpells
|
||||
{
|
||||
SPELL_WATERBOLT = 46983
|
||||
};
|
||||
|
||||
class npc_water_elemental : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_water_elemental() : CreatureScript("npc_water_elemental") { }
|
||||
|
||||
struct npc_water_elementalAI : public ScriptedAI
|
||||
{
|
||||
npc_water_elementalAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 waterBoltTimer;
|
||||
uint64 balindaGUID;
|
||||
uint32 resetTimer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
waterBoltTimer = 3 * IN_MILLISECONDS;
|
||||
resetTimer = 5 * IN_MILLISECONDS;
|
||||
balindaGUID = 0;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (waterBoltTimer < diff)
|
||||
{
|
||||
DoCastVictim(SPELL_WATERBOLT);
|
||||
waterBoltTimer = 5 * IN_MILLISECONDS;
|
||||
} else waterBoltTimer -= diff;
|
||||
|
||||
// check if creature is not outside of building
|
||||
if (resetTimer < diff)
|
||||
{
|
||||
if (Creature* pBalinda = ObjectAccessor::GetCreature(*me, balindaGUID))
|
||||
if (me->GetDistance2d(pBalinda->GetHomePosition().GetPositionX(), pBalinda->GetHomePosition().GetPositionY()) > 50)
|
||||
EnterEvadeMode();
|
||||
resetTimer = 5 * IN_MILLISECONDS;
|
||||
} else resetTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new npc_water_elementalAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_balinda : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_balinda() : CreatureScript("boss_balinda") { }
|
||||
|
||||
struct boss_balindaAI : public ScriptedAI
|
||||
{
|
||||
boss_balindaAI(Creature* creature) : ScriptedAI(creature), summons(me) { }
|
||||
|
||||
uint32 arcaneExplosionTimer;
|
||||
uint32 coneOfColdTimer;
|
||||
uint32 fireBoltTimer;
|
||||
uint32 frostboltTimer;
|
||||
uint32 resetTimer;
|
||||
uint32 waterElementalTimer;
|
||||
|
||||
SummonList summons;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
arcaneExplosionTimer = urand(5 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
|
||||
coneOfColdTimer = 8 * IN_MILLISECONDS;
|
||||
fireBoltTimer = 1 * IN_MILLISECONDS;
|
||||
frostboltTimer = 4 * IN_MILLISECONDS;
|
||||
resetTimer = 5 * IN_MILLISECONDS;
|
||||
waterElementalTimer = 0;
|
||||
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
Talk(YELL_AGGRO);
|
||||
}
|
||||
|
||||
void JustRespawned()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summoned)
|
||||
{
|
||||
CAST_AI(npc_water_elemental::npc_water_elementalAI, summoned->AI())->balindaGUID = me->GetGUID();
|
||||
summoned->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true));
|
||||
summoned->setFaction(me->getFaction());
|
||||
summons.Summon(summoned);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (waterElementalTimer < diff)
|
||||
{
|
||||
if (summons.empty())
|
||||
me->SummonCreature(NPC_WATER_ELEMENTAL, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45 * IN_MILLISECONDS);
|
||||
waterElementalTimer = 50 * IN_MILLISECONDS;
|
||||
} else waterElementalTimer -= diff;
|
||||
|
||||
if (arcaneExplosionTimer < diff)
|
||||
{
|
||||
DoCastVictim(SPELL_ARCANE_EXPLOSION);
|
||||
arcaneExplosionTimer = urand(5 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
|
||||
} else arcaneExplosionTimer -= diff;
|
||||
|
||||
if (coneOfColdTimer < diff)
|
||||
{
|
||||
DoCastVictim(SPELL_CONE_OF_COLD);
|
||||
coneOfColdTimer = urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
|
||||
} else coneOfColdTimer -= diff;
|
||||
|
||||
if (fireBoltTimer < diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FIREBALL);
|
||||
fireBoltTimer = urand(5 * IN_MILLISECONDS, 9 * IN_MILLISECONDS);
|
||||
} else fireBoltTimer -= diff;
|
||||
|
||||
if (frostboltTimer < diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FROSTBOLT);
|
||||
frostboltTimer = urand(4 * IN_MILLISECONDS, 12 * IN_MILLISECONDS);
|
||||
} else frostboltTimer -= diff;
|
||||
|
||||
// check if creature is not outside of building
|
||||
if (resetTimer < diff)
|
||||
{
|
||||
if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
Talk(YELL_EVADE);
|
||||
}
|
||||
resetTimer = 5 * IN_MILLISECONDS;
|
||||
} else resetTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_balindaAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_balinda()
|
||||
{
|
||||
new boss_balinda;
|
||||
new npc_water_elemental;
|
||||
};
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_WHIRLWIND = 15589,
|
||||
SPELL_WHIRLWIND2 = 13736,
|
||||
SPELL_KNOCKDOWN = 19128,
|
||||
SPELL_FRENZY = 8269,
|
||||
SPELL_SWEEPING_STRIKES = 18765, // not sure
|
||||
SPELL_CLEAVE = 20677, // not sure
|
||||
SPELL_WINDFURY = 35886, // not sure
|
||||
SPELL_STORMPIKE = 51876 // not sure
|
||||
};
|
||||
|
||||
enum Yells
|
||||
{
|
||||
YELL_AGGRO = 0,
|
||||
YELL_EVADE = 1,
|
||||
YELL_RESPAWN = 2,
|
||||
YELL_RANDOM = 3
|
||||
};
|
||||
|
||||
class boss_drekthar : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_drekthar() : CreatureScript("boss_drekthar") { }
|
||||
|
||||
struct boss_drektharAI : public ScriptedAI
|
||||
{
|
||||
boss_drektharAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 WhirlwindTimer;
|
||||
uint32 Whirlwind2Timer;
|
||||
uint32 KnockdownTimer;
|
||||
uint32 FrenzyTimer;
|
||||
uint32 YellTimer;
|
||||
uint32 ResetTimer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
WhirlwindTimer = urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
|
||||
Whirlwind2Timer = urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
|
||||
KnockdownTimer = 12 * IN_MILLISECONDS;
|
||||
FrenzyTimer = 6 * IN_MILLISECONDS;
|
||||
ResetTimer = 5 * IN_MILLISECONDS;
|
||||
YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
Talk(YELL_AGGRO);
|
||||
}
|
||||
|
||||
void JustRespawned()
|
||||
{
|
||||
Reset();
|
||||
Talk(YELL_RESPAWN);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (WhirlwindTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_WHIRLWIND);
|
||||
WhirlwindTimer = urand(8 * IN_MILLISECONDS, 18 * IN_MILLISECONDS);
|
||||
} else WhirlwindTimer -= diff;
|
||||
|
||||
if (Whirlwind2Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_WHIRLWIND2);
|
||||
Whirlwind2Timer = urand(7 * IN_MILLISECONDS, 25 * IN_MILLISECONDS);
|
||||
} else Whirlwind2Timer -= diff;
|
||||
|
||||
if (KnockdownTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_KNOCKDOWN);
|
||||
KnockdownTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
|
||||
} else KnockdownTimer -= diff;
|
||||
|
||||
if (FrenzyTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FRENZY);
|
||||
FrenzyTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS);
|
||||
} else FrenzyTimer -= diff;
|
||||
|
||||
if (YellTimer <= diff)
|
||||
{
|
||||
Talk(YELL_RANDOM);
|
||||
YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds
|
||||
} else YellTimer -= diff;
|
||||
|
||||
// check if creature is not outside of building
|
||||
if (ResetTimer <= diff)
|
||||
{
|
||||
if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
Talk(YELL_EVADE);
|
||||
}
|
||||
ResetTimer = 5 * IN_MILLISECONDS;
|
||||
} else ResetTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_drektharAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_drekthar()
|
||||
{
|
||||
new boss_drekthar;
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CLEAVE = 15284,
|
||||
SPELL_FRIGHTENING_SHOUT = 19134,
|
||||
SPELL_WHIRLWIND1 = 15589,
|
||||
SPELL_WHIRLWIND2 = 13736,
|
||||
SPELL_MORTAL_STRIKE = 16856
|
||||
};
|
||||
|
||||
enum Yells
|
||||
{
|
||||
YELL_AGGRO = 0,
|
||||
YELL_EVADE = 1
|
||||
};
|
||||
|
||||
class boss_galvangar : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_galvangar() : CreatureScript("boss_galvangar") { }
|
||||
|
||||
struct boss_galvangarAI : public ScriptedAI
|
||||
{
|
||||
boss_galvangarAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 CleaveTimer;
|
||||
uint32 FrighteningShoutTimer;
|
||||
uint32 Whirlwind1Timer;
|
||||
uint32 Whirlwind2Timer;
|
||||
uint32 MortalStrikeTimer;
|
||||
uint32 ResetTimer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
CleaveTimer = urand(1 * IN_MILLISECONDS, 9 * IN_MILLISECONDS);
|
||||
FrighteningShoutTimer = urand(2 * IN_MILLISECONDS, 19 * IN_MILLISECONDS);
|
||||
Whirlwind1Timer = urand(1 * IN_MILLISECONDS, 13 * IN_MILLISECONDS);
|
||||
Whirlwind2Timer = urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
|
||||
MortalStrikeTimer = urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
|
||||
ResetTimer = 5 * IN_MILLISECONDS;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
Talk(YELL_AGGRO);
|
||||
}
|
||||
|
||||
void JustRespawned()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (CleaveTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
CleaveTimer = urand(10 * IN_MILLISECONDS, 16 * IN_MILLISECONDS);
|
||||
} else CleaveTimer -= diff;
|
||||
|
||||
if (FrighteningShoutTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FRIGHTENING_SHOUT);
|
||||
FrighteningShoutTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
|
||||
} else FrighteningShoutTimer -= diff;
|
||||
|
||||
if (Whirlwind1Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_WHIRLWIND1);
|
||||
Whirlwind1Timer = urand(6 * IN_MILLISECONDS, 10 * IN_MILLISECONDS);
|
||||
} else Whirlwind1Timer -= diff;
|
||||
|
||||
if (Whirlwind2Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_WHIRLWIND2);
|
||||
Whirlwind2Timer = urand(10 * IN_MILLISECONDS, 25 * IN_MILLISECONDS);
|
||||
} else Whirlwind2Timer -= diff;
|
||||
|
||||
if (MortalStrikeTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_MORTAL_STRIKE);
|
||||
MortalStrikeTimer = urand(10 * IN_MILLISECONDS, 30 * IN_MILLISECONDS);
|
||||
} else MortalStrikeTimer -= diff;
|
||||
|
||||
// check if creature is not outside of building
|
||||
if (ResetTimer <= diff)
|
||||
{
|
||||
if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
Talk(YELL_EVADE);
|
||||
}
|
||||
ResetTimer = 5 * IN_MILLISECONDS;
|
||||
} else ResetTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_galvangarAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_galvangar()
|
||||
{
|
||||
new boss_galvangar;
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Yells
|
||||
{
|
||||
YELL_AGGRO = 0,
|
||||
YELL_EVADE = 1,
|
||||
//YELL_RESPAWN1 = -1810010, // Missing in database
|
||||
//YELL_RESPAWN2 = -1810011, // Missing in database
|
||||
YELL_RANDOM = 2,
|
||||
YELL_SPELL = 3,
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_AVATAR = 19135,
|
||||
SPELL_THUNDERCLAP = 15588,
|
||||
SPELL_STORMBOLT = 20685 // not sure
|
||||
};
|
||||
|
||||
class boss_vanndar : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_vanndar() : CreatureScript("boss_vanndar") { }
|
||||
|
||||
struct boss_vanndarAI : public ScriptedAI
|
||||
{
|
||||
boss_vanndarAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 AvatarTimer;
|
||||
uint32 ThunderclapTimer;
|
||||
uint32 StormboltTimer;
|
||||
uint32 ResetTimer;
|
||||
uint32 YellTimer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
AvatarTimer = 3 * IN_MILLISECONDS;
|
||||
ThunderclapTimer = 4 * IN_MILLISECONDS;
|
||||
StormboltTimer = 6 * IN_MILLISECONDS;
|
||||
ResetTimer = 5 * IN_MILLISECONDS;
|
||||
YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
Talk(YELL_AGGRO);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (AvatarTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_AVATAR);
|
||||
AvatarTimer = urand(15 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
|
||||
} else AvatarTimer -= diff;
|
||||
|
||||
if (ThunderclapTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_THUNDERCLAP);
|
||||
ThunderclapTimer = urand(5 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
|
||||
} else ThunderclapTimer -= diff;
|
||||
|
||||
if (StormboltTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_STORMBOLT);
|
||||
StormboltTimer = urand(10 * IN_MILLISECONDS, 25 * IN_MILLISECONDS);
|
||||
} else StormboltTimer -= diff;
|
||||
|
||||
if (YellTimer <= diff)
|
||||
{
|
||||
Talk(YELL_RANDOM);
|
||||
YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds
|
||||
} else YellTimer -= diff;
|
||||
|
||||
// check if creature is not outside of building
|
||||
if (ResetTimer <= diff)
|
||||
{
|
||||
if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
Talk(YELL_EVADE);
|
||||
}
|
||||
ResetTimer = 5 * IN_MILLISECONDS;
|
||||
} else ResetTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_vanndarAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_vanndar()
|
||||
{
|
||||
new boss_vanndar;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DEF_BRD_H
|
||||
#define DEF_BRD_H
|
||||
|
||||
enum FactionIds
|
||||
{
|
||||
FACTION_NEUTRAL = 734,
|
||||
FACTION_HOSTILE = 754,
|
||||
FACTION_FRIEND = 35
|
||||
};
|
||||
|
||||
enum DataTypes
|
||||
{
|
||||
TYPE_RING_OF_LAW = 1,
|
||||
TYPE_VAULT = 2,
|
||||
TYPE_BAR = 3,
|
||||
TYPE_TOMB_OF_SEVEN = 4,
|
||||
TYPE_LYCEUM = 5,
|
||||
TYPE_IRON_HALL = 6,
|
||||
|
||||
DATA_EMPEROR = 10,
|
||||
DATA_PHALANX = 11,
|
||||
|
||||
DATA_ARENA1 = 12,
|
||||
DATA_ARENA2 = 13,
|
||||
DATA_ARENA3 = 14,
|
||||
DATA_ARENA4 = 15,
|
||||
|
||||
DATA_GO_BAR_KEG = 16,
|
||||
DATA_GO_BAR_KEG_TRAP = 17,
|
||||
DATA_GO_BAR_DOOR = 18,
|
||||
DATA_GO_CHALICE = 19,
|
||||
|
||||
DATA_GHOSTKILL = 20,
|
||||
DATA_EVENSTARTER = 21,
|
||||
|
||||
DATA_GOLEM_DOOR_N = 22,
|
||||
DATA_GOLEM_DOOR_S = 23,
|
||||
|
||||
DATA_THRONE_DOOR = 24,
|
||||
|
||||
DATA_SF_BRAZIER_N = 25,
|
||||
DATA_SF_BRAZIER_S = 26,
|
||||
DATA_MOIRA = 27,
|
||||
|
||||
DATA_OPEN_COFFER_DOORS = 30,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FIREBLAST = 15573
|
||||
};
|
||||
|
||||
class boss_ambassador_flamelash : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_ambassador_flamelash() : CreatureScript("boss_ambassador_flamelash") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_ambassador_flamelashAI(creature);
|
||||
}
|
||||
|
||||
struct boss_ambassador_flamelashAI : public ScriptedAI
|
||||
{
|
||||
boss_ambassador_flamelashAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 FireBlast_Timer;
|
||||
uint32 Spirit_Timer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
FireBlast_Timer = 2000;
|
||||
Spirit_Timer = 24000;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) { }
|
||||
|
||||
void SummonSpirits(Unit* victim)
|
||||
{
|
||||
if (Creature* Spirit = DoSpawnCreature(9178, float(irand(-9, 9)), float(irand(-9, 9)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000))
|
||||
Spirit->AI()->AttackStart(victim);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//FireBlast_Timer
|
||||
if (FireBlast_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FIREBLAST);
|
||||
FireBlast_Timer = 7000;
|
||||
} else FireBlast_Timer -= diff;
|
||||
|
||||
//Spirit_Timer
|
||||
if (Spirit_Timer <= diff)
|
||||
{
|
||||
SummonSpirits(me->GetVictim());
|
||||
SummonSpirits(me->GetVictim());
|
||||
SummonSpirits(me->GetVictim());
|
||||
SummonSpirits(me->GetVictim());
|
||||
|
||||
Spirit_Timer = 30000;
|
||||
} else Spirit_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_ambassador_flamelash()
|
||||
{
|
||||
new boss_ambassador_flamelash();
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SHADOWBOLT = 17228,
|
||||
SPELL_CURSEOFTONGUES = 15470,
|
||||
SPELL_CURSEOFWEAKNESS = 17227,
|
||||
SPELL_DEMONARMOR = 11735,
|
||||
SPELL_ENVELOPINGWEB = 15471
|
||||
};
|
||||
|
||||
class boss_anubshiah : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_anubshiah() : CreatureScript("boss_anubshiah") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_anubshiahAI(creature);
|
||||
}
|
||||
|
||||
struct boss_anubshiahAI : public ScriptedAI
|
||||
{
|
||||
boss_anubshiahAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 ShadowBolt_Timer;
|
||||
uint32 CurseOfTongues_Timer;
|
||||
uint32 CurseOfWeakness_Timer;
|
||||
uint32 DemonArmor_Timer;
|
||||
uint32 EnvelopingWeb_Timer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ShadowBolt_Timer = 7000;
|
||||
CurseOfTongues_Timer = 24000;
|
||||
CurseOfWeakness_Timer = 12000;
|
||||
DemonArmor_Timer = 3000;
|
||||
EnvelopingWeb_Timer = 16000;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) { }
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//ShadowBolt_Timer
|
||||
if (ShadowBolt_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOWBOLT);
|
||||
ShadowBolt_Timer = 7000;
|
||||
} else ShadowBolt_Timer -= diff;
|
||||
|
||||
//CurseOfTongues_Timer
|
||||
if (CurseOfTongues_Timer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_CURSEOFTONGUES);
|
||||
CurseOfTongues_Timer = 18000;
|
||||
} else CurseOfTongues_Timer -= diff;
|
||||
|
||||
//CurseOfWeakness_Timer
|
||||
if (CurseOfWeakness_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_CURSEOFWEAKNESS);
|
||||
CurseOfWeakness_Timer = 45000;
|
||||
} else CurseOfWeakness_Timer -= diff;
|
||||
|
||||
//DemonArmor_Timer
|
||||
if (DemonArmor_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_DEMONARMOR);
|
||||
DemonArmor_Timer = 300000;
|
||||
} else DemonArmor_Timer -= diff;
|
||||
|
||||
//EnvelopingWeb_Timer
|
||||
if (EnvelopingWeb_Timer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_ENVELOPINGWEB);
|
||||
EnvelopingWeb_Timer = 12000;
|
||||
} else EnvelopingWeb_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_anubshiah()
|
||||
{
|
||||
new boss_anubshiah();
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_depths.h"
|
||||
|
||||
enum Yells
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_HANDOFTHAURISSAN = 17492,
|
||||
SPELL_AVATAROFFLAME = 15636
|
||||
};
|
||||
|
||||
class boss_emperor_dagran_thaurissan : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_emperor_dagran_thaurissan() : CreatureScript("boss_emperor_dagran_thaurissan") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_draganthaurissanAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_draganthaurissanAI : public ScriptedAI
|
||||
{
|
||||
boss_draganthaurissanAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = me->GetInstanceScript();
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
uint32 HandOfThaurissan_Timer;
|
||||
uint32 AvatarOfFlame_Timer;
|
||||
//uint32 Counter;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
HandOfThaurissan_Timer = 4000;
|
||||
AvatarOfFlame_Timer = 25000;
|
||||
//Counter= 0;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
me->CallForHelp(VISIBLE_RANGE);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
if (Creature* Moira = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_MOIRA)))
|
||||
{
|
||||
Moira->AI()->EnterEvadeMode();
|
||||
Moira->setFaction(35);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (HandOfThaurissan_Timer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target, SPELL_HANDOFTHAURISSAN);
|
||||
|
||||
//3 Hands of Thaurissan will be cast
|
||||
//if (Counter < 3)
|
||||
//{
|
||||
// HandOfThaurissan_Timer = 1000;
|
||||
// ++Counter;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
HandOfThaurissan_Timer = 5000;
|
||||
//Counter = 0;
|
||||
//}
|
||||
} else HandOfThaurissan_Timer -= diff;
|
||||
|
||||
//AvatarOfFlame_Timer
|
||||
if (AvatarOfFlame_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_AVATAROFFLAME);
|
||||
AvatarOfFlame_Timer = 18000;
|
||||
} else AvatarOfFlame_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_draganthaurissan()
|
||||
{
|
||||
new boss_emperor_dagran_thaurissan();
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_MIGHTYBLOW = 14099,
|
||||
SPELL_HAMSTRING = 9080,
|
||||
SPELL_CLEAVE = 20691
|
||||
};
|
||||
|
||||
class boss_general_angerforge : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_general_angerforge() : CreatureScript("boss_general_angerforge") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_general_angerforgeAI(creature);
|
||||
}
|
||||
|
||||
struct boss_general_angerforgeAI : public ScriptedAI
|
||||
{
|
||||
boss_general_angerforgeAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 MightyBlow_Timer;
|
||||
uint32 HamString_Timer;
|
||||
uint32 Cleave_Timer;
|
||||
uint32 Adds_Timer;
|
||||
bool Medics;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
MightyBlow_Timer = 8000;
|
||||
HamString_Timer = 12000;
|
||||
Cleave_Timer = 16000;
|
||||
Adds_Timer = 0;
|
||||
Medics = false;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) { }
|
||||
|
||||
void SummonAdds(Unit* victim)
|
||||
{
|
||||
if (Creature* SummonedAdd = DoSpawnCreature(8901, float(irand(-14, 14)), float(irand(-14, 14)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000))
|
||||
SummonedAdd->AI()->AttackStart(victim);
|
||||
}
|
||||
|
||||
void SummonMedics(Unit* victim)
|
||||
{
|
||||
if (Creature* SummonedMedic = DoSpawnCreature(8894, float(irand(-9, 9)), float(irand(-9, 9)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000))
|
||||
SummonedMedic->AI()->AttackStart(victim);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//MightyBlow_Timer
|
||||
if (MightyBlow_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_MIGHTYBLOW);
|
||||
MightyBlow_Timer = 18000;
|
||||
} else MightyBlow_Timer -= diff;
|
||||
|
||||
//HamString_Timer
|
||||
if (HamString_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_HAMSTRING);
|
||||
HamString_Timer = 15000;
|
||||
} else HamString_Timer -= diff;
|
||||
|
||||
//Cleave_Timer
|
||||
if (Cleave_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
Cleave_Timer = 9000;
|
||||
} else Cleave_Timer -= diff;
|
||||
|
||||
//Adds_Timer
|
||||
if (HealthBelowPct(21))
|
||||
{
|
||||
if (Adds_Timer <= diff)
|
||||
{
|
||||
// summon 3 Adds every 25s
|
||||
SummonAdds(me->GetVictim());
|
||||
SummonAdds(me->GetVictim());
|
||||
SummonAdds(me->GetVictim());
|
||||
|
||||
Adds_Timer = 25000;
|
||||
} else Adds_Timer -= diff;
|
||||
}
|
||||
|
||||
//Summon Medics
|
||||
if (!Medics && HealthBelowPct(21))
|
||||
{
|
||||
SummonMedics(me->GetVictim());
|
||||
SummonMedics(me->GetVictim());
|
||||
Medics = true;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_general_angerforge()
|
||||
{
|
||||
new boss_general_angerforge();
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_WHIRLWIND = 15589,
|
||||
SPELL_MORTALSTRIKE = 24573
|
||||
};
|
||||
|
||||
class boss_gorosh_the_dervish : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_gorosh_the_dervish() : CreatureScript("boss_gorosh_the_dervish") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_gorosh_the_dervishAI(creature);
|
||||
}
|
||||
|
||||
struct boss_gorosh_the_dervishAI : public ScriptedAI
|
||||
{
|
||||
boss_gorosh_the_dervishAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 WhirlWind_Timer;
|
||||
uint32 MortalStrike_Timer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
WhirlWind_Timer = 12000;
|
||||
MortalStrike_Timer = 22000;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//WhirlWind_Timer
|
||||
if (WhirlWind_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_WHIRLWIND);
|
||||
WhirlWind_Timer = 15000;
|
||||
} else WhirlWind_Timer -= diff;
|
||||
|
||||
//MortalStrike_Timer
|
||||
if (MortalStrike_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_MORTALSTRIKE);
|
||||
MortalStrike_Timer = 15000;
|
||||
} else MortalStrike_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_gorosh_the_dervish()
|
||||
{
|
||||
new boss_gorosh_the_dervish();
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Grizzle
|
||||
{
|
||||
SPELL_GROUNDTREMOR = 6524,
|
||||
SPELL_FRENZY = 28371,
|
||||
EMOTE_FRENZY_KILL = 0
|
||||
};
|
||||
|
||||
class boss_grizzle : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_grizzle() : CreatureScript("boss_grizzle") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_grizzleAI(creature);
|
||||
}
|
||||
|
||||
struct boss_grizzleAI : public ScriptedAI
|
||||
{
|
||||
boss_grizzleAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 GroundTremor_Timer;
|
||||
uint32 Frenzy_Timer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
GroundTremor_Timer = 12000;
|
||||
Frenzy_Timer =0;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) { }
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//GroundTremor_Timer
|
||||
if (GroundTremor_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_GROUNDTREMOR);
|
||||
GroundTremor_Timer = 8000;
|
||||
} else GroundTremor_Timer -= diff;
|
||||
|
||||
//Frenzy_Timer
|
||||
if (HealthBelowPct(51))
|
||||
{
|
||||
if (Frenzy_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_FRENZY);
|
||||
Talk(EMOTE_FRENZY_KILL);
|
||||
|
||||
Frenzy_Timer = 15000;
|
||||
} else Frenzy_Timer -= diff;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_grizzle()
|
||||
{
|
||||
new boss_grizzle();
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SHADOWWORDPAIN = 10894,
|
||||
SPELL_MANABURN = 10876,
|
||||
SPELL_PSYCHICSCREAM = 8122,
|
||||
SPELL_SHADOWSHIELD = 22417
|
||||
};
|
||||
|
||||
class boss_high_interrogator_gerstahn : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_high_interrogator_gerstahn() : CreatureScript("boss_high_interrogator_gerstahn") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_high_interrogator_gerstahnAI(creature);
|
||||
}
|
||||
|
||||
struct boss_high_interrogator_gerstahnAI : public ScriptedAI
|
||||
{
|
||||
boss_high_interrogator_gerstahnAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 ShadowWordPain_Timer;
|
||||
uint32 ManaBurn_Timer;
|
||||
uint32 PsychicScream_Timer;
|
||||
uint32 ShadowShield_Timer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ShadowWordPain_Timer = 4000;
|
||||
ManaBurn_Timer = 14000;
|
||||
PsychicScream_Timer = 32000;
|
||||
ShadowShield_Timer = 8000;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) { }
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//ShadowWordPain_Timer
|
||||
if (ShadowWordPain_Timer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_SHADOWWORDPAIN);
|
||||
ShadowWordPain_Timer = 7000;
|
||||
} else ShadowWordPain_Timer -= diff;
|
||||
|
||||
//ManaBurn_Timer
|
||||
if (ManaBurn_Timer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_MANABURN);
|
||||
ManaBurn_Timer = 10000;
|
||||
} else ManaBurn_Timer -= diff;
|
||||
|
||||
//PsychicScream_Timer
|
||||
if (PsychicScream_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_PSYCHICSCREAM);
|
||||
PsychicScream_Timer = 30000;
|
||||
} else PsychicScream_Timer -= diff;
|
||||
|
||||
//ShadowShield_Timer
|
||||
if (ShadowShield_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_SHADOWSHIELD);
|
||||
ShadowShield_Timer = 25000;
|
||||
} else ShadowShield_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_high_interrogator_gerstahn()
|
||||
{
|
||||
new boss_high_interrogator_gerstahn();
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FIERYBURST = 13900,
|
||||
SPELL_WARSTOMP = 24375
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
DATA_THRONE_DOOR = 24 // not id or guid of doors but number of enum in blackrock_depths.h
|
||||
};
|
||||
|
||||
class boss_magmus : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_magmus() : CreatureScript("boss_magmus") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_magmusAI(creature);
|
||||
}
|
||||
|
||||
struct boss_magmusAI : public ScriptedAI
|
||||
{
|
||||
boss_magmusAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 FieryBurst_Timer;
|
||||
uint32 WarStomp_Timer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
FieryBurst_Timer = 5000;
|
||||
WarStomp_Timer =0;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) { }
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//FieryBurst_Timer
|
||||
if (FieryBurst_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FIERYBURST);
|
||||
FieryBurst_Timer = 6000;
|
||||
} else FieryBurst_Timer -= diff;
|
||||
|
||||
//WarStomp_Timer
|
||||
if (HealthBelowPct(51))
|
||||
{
|
||||
if (WarStomp_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_WARSTOMP);
|
||||
WarStomp_Timer = 8000;
|
||||
} else WarStomp_Timer -= diff;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
// When he die open door to last chamber
|
||||
void JustDied(Unit* killer)
|
||||
{
|
||||
if (InstanceScript* instance = killer->GetInstanceScript())
|
||||
instance->HandleGameObject(instance->GetData64(DATA_THRONE_DOOR), true);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_magmus()
|
||||
{
|
||||
new boss_magmus();
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_HEAL = 10917,
|
||||
SPELL_RENEW = 10929,
|
||||
SPELL_SHIELD = 10901,
|
||||
SPELL_MINDBLAST = 10947,
|
||||
SPELL_SHADOWWORDPAIN = 10894,
|
||||
SPELL_SMITE = 10934
|
||||
};
|
||||
|
||||
class boss_moira_bronzebeard : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_moira_bronzebeard() : CreatureScript("boss_moira_bronzebeard") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_moira_bronzebeardAI(creature);
|
||||
}
|
||||
|
||||
struct boss_moira_bronzebeardAI : public ScriptedAI
|
||||
{
|
||||
boss_moira_bronzebeardAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 Heal_Timer;
|
||||
uint32 MindBlast_Timer;
|
||||
uint32 ShadowWordPain_Timer;
|
||||
uint32 Smite_Timer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Heal_Timer = 12000; //These times are probably wrong
|
||||
MindBlast_Timer = 16000;
|
||||
ShadowWordPain_Timer = 2000;
|
||||
Smite_Timer = 8000;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) { }
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//MindBlast_Timer
|
||||
if (MindBlast_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_MINDBLAST);
|
||||
MindBlast_Timer = 14000;
|
||||
} else MindBlast_Timer -= diff;
|
||||
|
||||
//ShadowWordPain_Timer
|
||||
if (ShadowWordPain_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOWWORDPAIN);
|
||||
ShadowWordPain_Timer = 18000;
|
||||
} else ShadowWordPain_Timer -= diff;
|
||||
|
||||
//Smite_Timer
|
||||
if (Smite_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SMITE);
|
||||
Smite_Timer = 10000;
|
||||
} else Smite_Timer -= diff;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_moira_bronzebeard()
|
||||
{
|
||||
new boss_moira_bronzebeard();
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "blackrock_depths.h"
|
||||
#include "Player.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SMELT_DARK_IRON = 14891,
|
||||
SPELL_LEARN_SMELT = 14894,
|
||||
};
|
||||
|
||||
enum Quests
|
||||
{
|
||||
QUEST_SPECTRAL_CHALICE = 4083
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
DATA_SKILLPOINT_MIN = 230
|
||||
};
|
||||
|
||||
#define GOSSIP_ITEM_TEACH_1 "Teach me the art of smelting dark iron"
|
||||
#define GOSSIP_ITEM_TEACH_2 "Continue..."
|
||||
#define GOSSIP_ITEM_TEACH_3 "[PH] Continue..."
|
||||
#define GOSSIP_ITEM_TRIBUTE "I want to pay tribute"
|
||||
|
||||
class boss_gloomrel : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_gloomrel() : CreatureScript("boss_gloomrel") { }
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action)
|
||||
{
|
||||
player->PlayerTalkClass->ClearMenus();
|
||||
switch (action)
|
||||
{
|
||||
case GOSSIP_ACTION_INFO_DEF+1:
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TEACH_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11);
|
||||
player->SEND_GOSSIP_MENU(2606, creature->GetGUID());
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF+11:
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
player->CastSpell(player, SPELL_LEARN_SMELT, false);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF+2:
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TEACH_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22);
|
||||
player->SEND_GOSSIP_MENU(2604, creature->GetGUID());
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF+22:
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
if (InstanceScript* instance = creature->GetInstanceScript())
|
||||
{
|
||||
//are 5 minutes expected? go template may have data to despawn when used at quest
|
||||
instance->DoRespawnGameObject(instance->GetData64(DATA_GO_CHALICE), MINUTE*5);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature)
|
||||
{
|
||||
if (player->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) == 1 && player->GetSkillValue(SKILL_MINING) >= DATA_SKILLPOINT_MIN && !player->HasSpell(SPELL_SMELT_DARK_IRON))
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TEACH_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
|
||||
if (player->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) == 0 && player->GetSkillValue(SKILL_MINING) >= DATA_SKILLPOINT_MIN)
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TRIBUTE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
|
||||
player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
enum DoomrelSpells
|
||||
{
|
||||
SPELL_SHADOWBOLTVOLLEY = 15245,
|
||||
SPELL_IMMOLATE = 12742,
|
||||
SPELL_CURSEOFWEAKNESS = 12493,
|
||||
SPELL_DEMONARMOR = 13787,
|
||||
SPELL_SUMMON_VOIDWALKERS = 15092
|
||||
};
|
||||
|
||||
#define GOSSIP_ITEM_CHALLENGE "Your bondage is at an end, Doom'rel. I challenge you!"
|
||||
#define GOSSIP_SELECT_DOOMREL "[PH] Continue..."
|
||||
|
||||
class boss_doomrel : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_doomrel() : CreatureScript("boss_doomrel") { }
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action)
|
||||
{
|
||||
player->PlayerTalkClass->ClearMenus();
|
||||
switch (action)
|
||||
{
|
||||
case GOSSIP_ACTION_INFO_DEF+1:
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT_DOOMREL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
player->SEND_GOSSIP_MENU(2605, creature->GetGUID());
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF+2:
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
//start event here
|
||||
creature->setFaction(FACTION_HOSTILE);
|
||||
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
||||
creature->AI()->AttackStart(player);
|
||||
InstanceScript* instance = creature->GetInstanceScript();
|
||||
if (instance)
|
||||
instance->SetData64(DATA_EVENSTARTER, player->GetGUID());
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature)
|
||||
{
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_CHALLENGE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
player->SEND_GOSSIP_MENU(2601, creature->GetGUID());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_doomrelAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_doomrelAI : public ScriptedAI
|
||||
{
|
||||
boss_doomrelAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
uint32 ShadowVolley_Timer;
|
||||
uint32 Immolate_Timer;
|
||||
uint32 CurseOfWeakness_Timer;
|
||||
uint32 DemonArmor_Timer;
|
||||
bool Voidwalkers;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ShadowVolley_Timer = 10000;
|
||||
Immolate_Timer = 18000;
|
||||
CurseOfWeakness_Timer = 5000;
|
||||
DemonArmor_Timer = 16000;
|
||||
Voidwalkers = false;
|
||||
|
||||
me->setFaction(FACTION_FRIEND);
|
||||
|
||||
// was set before event start, so set again
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
||||
|
||||
if (instance->GetData(DATA_GHOSTKILL) >= 7)
|
||||
me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
else
|
||||
me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
}
|
||||
|
||||
void EnterEvadeMode()
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->DeleteThreatList();
|
||||
me->CombatStop(true);
|
||||
me->LoadCreaturesAddon(true);
|
||||
if (me->IsAlive())
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
me->SetLootRecipient(NULL);
|
||||
instance->SetData64(DATA_EVENSTARTER, 0);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
instance->SetData(DATA_GHOSTKILL, 1);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//ShadowVolley_Timer
|
||||
if (ShadowVolley_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOWBOLTVOLLEY);
|
||||
ShadowVolley_Timer = 12000;
|
||||
} else ShadowVolley_Timer -= diff;
|
||||
|
||||
//Immolate_Timer
|
||||
if (Immolate_Timer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_IMMOLATE);
|
||||
|
||||
Immolate_Timer = 25000;
|
||||
} else Immolate_Timer -= diff;
|
||||
|
||||
//CurseOfWeakness_Timer
|
||||
if (CurseOfWeakness_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_CURSEOFWEAKNESS);
|
||||
CurseOfWeakness_Timer = 45000;
|
||||
} else CurseOfWeakness_Timer -= diff;
|
||||
|
||||
//DemonArmor_Timer
|
||||
if (DemonArmor_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_DEMONARMOR);
|
||||
DemonArmor_Timer = 300000;
|
||||
} else DemonArmor_Timer -= diff;
|
||||
|
||||
//Summon Voidwalkers
|
||||
if (!Voidwalkers && HealthBelowPct(51))
|
||||
{
|
||||
DoCastVictim(SPELL_SUMMON_VOIDWALKERS, true);
|
||||
Voidwalkers = true;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_tomb_of_seven()
|
||||
{
|
||||
new boss_gloomrel();
|
||||
new boss_doomrel();
|
||||
}
|
||||
@@ -1,476 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "blackrock_depths.h"
|
||||
|
||||
#define TIMER_TOMBOFTHESEVEN 15000
|
||||
#define MAX_ENCOUNTER 6
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_EMPEROR = 9019,
|
||||
NPC_PHALANX = 9502,
|
||||
NPC_ANGERREL = 9035,
|
||||
NPC_DOPEREL = 9040,
|
||||
NPC_HATEREL = 9034,
|
||||
NPC_VILEREL = 9036,
|
||||
NPC_SEETHREL = 9038,
|
||||
NPC_GLOOMREL = 9037,
|
||||
NPC_DOOMREL = 9039,
|
||||
NPC_MAGMUS = 9938,
|
||||
NPC_MOIRA = 8929,
|
||||
|
||||
NPC_WATCHMAN_DOOMGRIP = 9476,
|
||||
};
|
||||
|
||||
enum GameObjects
|
||||
{
|
||||
GO_ARENA1 = 161525,
|
||||
GO_ARENA2 = 161522,
|
||||
GO_ARENA3 = 161524,
|
||||
GO_ARENA4 = 161523,
|
||||
GO_SHADOW_LOCK = 161460,
|
||||
GO_SHADOW_MECHANISM = 161461,
|
||||
GO_SHADOW_GIANT_DOOR = 157923,
|
||||
GO_SHADOW_DUMMY = 161516,
|
||||
GO_BAR_KEG_SHOT = 170607,
|
||||
GO_BAR_KEG_TRAP = 171941,
|
||||
GO_BAR_DOOR = 170571,
|
||||
GO_TOMB_ENTER = 170576,
|
||||
GO_TOMB_EXIT = 170577,
|
||||
GO_LYCEUM = 170558,
|
||||
GO_SF_N = 174745, // Shadowforge Brazier North
|
||||
GO_SF_S = 174744, // Shadowforge Brazier South
|
||||
GO_GOLEM_ROOM_N = 170573, // Magmus door North
|
||||
GO_GOLEM_ROOM_S = 170574, // Magmus door Soutsh
|
||||
GO_THRONE_ROOM = 170575, // Throne door
|
||||
GO_SPECTRAL_CHALICE = 164869,
|
||||
GO_CHEST_SEVEN = 169243
|
||||
};
|
||||
|
||||
class instance_blackrock_depths : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
instance_blackrock_depths() : InstanceMapScript("instance_blackrock_depths", 230) { }
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const
|
||||
{
|
||||
return new instance_blackrock_depths_InstanceMapScript(map);
|
||||
}
|
||||
|
||||
struct instance_blackrock_depths_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
instance_blackrock_depths_InstanceMapScript(Map* map) : InstanceScript(map) { }
|
||||
|
||||
uint32 encounter[MAX_ENCOUNTER];
|
||||
std::string str_data;
|
||||
|
||||
uint64 EmperorGUID;
|
||||
uint64 PhalanxGUID;
|
||||
uint64 MagmusGUID;
|
||||
uint64 MoiraGUID;
|
||||
|
||||
uint64 GoArena1GUID;
|
||||
uint64 GoArena2GUID;
|
||||
uint64 GoArena3GUID;
|
||||
uint64 GoArena4GUID;
|
||||
uint64 GoShadowLockGUID;
|
||||
uint64 GoShadowMechGUID;
|
||||
uint64 GoShadowGiantGUID;
|
||||
uint64 GoShadowDummyGUID;
|
||||
uint64 GoBarKegGUID;
|
||||
uint64 GoBarKegTrapGUID;
|
||||
uint64 GoBarDoorGUID;
|
||||
uint64 GoTombEnterGUID;
|
||||
uint64 GoTombExitGUID;
|
||||
uint64 GoLyceumGUID;
|
||||
uint64 GoSFSGUID;
|
||||
uint64 GoSFNGUID;
|
||||
uint64 GoGolemNGUID;
|
||||
uint64 GoGolemSGUID;
|
||||
uint64 GoThroneGUID;
|
||||
uint64 GoChestGUID;
|
||||
uint64 GoSpectralChaliceGUID;
|
||||
|
||||
uint32 BarAleCount;
|
||||
uint32 GhostKillCount;
|
||||
uint64 TombBossGUIDs[7];
|
||||
uint64 TombEventStarterGUID;
|
||||
uint32 TombTimer;
|
||||
uint32 TombEventCounter;
|
||||
uint32 OpenedCoofers;
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
memset(&encounter, 0, sizeof(encounter));
|
||||
|
||||
EmperorGUID = 0;
|
||||
PhalanxGUID = 0;
|
||||
MagmusGUID = 0;
|
||||
MoiraGUID = 0;
|
||||
|
||||
GoArena1GUID = 0;
|
||||
GoArena2GUID = 0;
|
||||
GoArena3GUID = 0;
|
||||
GoArena4GUID = 0;
|
||||
GoShadowLockGUID = 0;
|
||||
GoShadowMechGUID = 0;
|
||||
GoShadowGiantGUID = 0;
|
||||
GoShadowDummyGUID = 0;
|
||||
GoBarKegGUID = 0;
|
||||
GoBarKegTrapGUID = 0;
|
||||
GoBarDoorGUID = 0;
|
||||
GoTombEnterGUID = 0;
|
||||
GoTombExitGUID = 0;
|
||||
GoLyceumGUID = 0;
|
||||
GoSFSGUID = 0;
|
||||
GoSFNGUID = 0;
|
||||
GoGolemNGUID = 0;
|
||||
GoGolemSGUID = 0;
|
||||
GoThroneGUID = 0;
|
||||
GoChestGUID = 0;
|
||||
GoSpectralChaliceGUID = 0;
|
||||
|
||||
BarAleCount = 0;
|
||||
GhostKillCount = 0;
|
||||
TombEventStarterGUID = 0;
|
||||
TombTimer = TIMER_TOMBOFTHESEVEN;
|
||||
TombEventCounter = 0;
|
||||
OpenedCoofers = 0;
|
||||
|
||||
for (uint8 i = 0; i < 7; ++i)
|
||||
TombBossGUIDs[i] = 0;
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature)
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_EMPEROR: EmperorGUID = creature->GetGUID(); break;
|
||||
case NPC_PHALANX: PhalanxGUID = creature->GetGUID(); break;
|
||||
case NPC_MOIRA: MoiraGUID = creature->GetGUID(); break;
|
||||
case NPC_DOOMREL: TombBossGUIDs[0] = creature->GetGUID(); break;
|
||||
case NPC_DOPEREL: TombBossGUIDs[1] = creature->GetGUID(); break;
|
||||
case NPC_HATEREL: TombBossGUIDs[2] = creature->GetGUID(); break;
|
||||
case NPC_VILEREL: TombBossGUIDs[3] = creature->GetGUID(); break;
|
||||
case NPC_SEETHREL: TombBossGUIDs[4] = creature->GetGUID(); break;
|
||||
case NPC_GLOOMREL: TombBossGUIDs[5] = creature->GetGUID(); break;
|
||||
case NPC_ANGERREL: TombBossGUIDs[6] = creature->GetGUID(); break;
|
||||
case NPC_MAGMUS:
|
||||
MagmusGUID = creature->GetGUID();
|
||||
if (!creature->IsAlive())
|
||||
HandleGameObject(GetData64(DATA_THRONE_DOOR), true); // if Magmus is dead open door to last boss
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go)
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_ARENA1: GoArena1GUID = go->GetGUID(); break;
|
||||
case GO_ARENA2: GoArena2GUID = go->GetGUID(); break;
|
||||
case GO_ARENA3: GoArena3GUID = go->GetGUID(); break;
|
||||
case GO_ARENA4: GoArena4GUID = go->GetGUID(); break;
|
||||
case GO_SHADOW_LOCK: GoShadowLockGUID = go->GetGUID(); break;
|
||||
case GO_SHADOW_MECHANISM: GoShadowMechGUID = go->GetGUID(); break;
|
||||
case GO_SHADOW_GIANT_DOOR: GoShadowGiantGUID = go->GetGUID(); break;
|
||||
case GO_SHADOW_DUMMY: GoShadowDummyGUID = go->GetGUID(); break;
|
||||
case GO_BAR_KEG_SHOT: GoBarKegGUID = go->GetGUID(); break;
|
||||
case GO_BAR_KEG_TRAP: GoBarKegTrapGUID = go->GetGUID(); break;
|
||||
case GO_BAR_DOOR: GoBarDoorGUID = go->GetGUID(); break;
|
||||
case GO_TOMB_ENTER: GoTombEnterGUID = go->GetGUID(); break;
|
||||
case GO_TOMB_EXIT:
|
||||
GoTombExitGUID = go->GetGUID();
|
||||
if (GhostKillCount >= 7)
|
||||
HandleGameObject(0, true, go);
|
||||
else
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_LYCEUM: GoLyceumGUID = go->GetGUID(); break;
|
||||
case GO_SF_S: GoSFSGUID = go->GetGUID(); break;
|
||||
case GO_SF_N: GoSFNGUID = go->GetGUID(); break;
|
||||
case GO_GOLEM_ROOM_N: GoGolemNGUID = go->GetGUID(); break;
|
||||
case GO_GOLEM_ROOM_S: GoGolemSGUID = go->GetGUID(); break;
|
||||
case GO_THRONE_ROOM: GoThroneGUID = go->GetGUID(); break;
|
||||
case GO_CHEST_SEVEN: GoChestGUID = go->GetGUID(); break;
|
||||
case GO_SPECTRAL_CHALICE: GoSpectralChaliceGUID = go->GetGUID(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetData64(uint32 type, uint64 data)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: Instance Blackrock Depths: SetData64 update (Type: %u Data " UI64FMTD ")", type, data);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DATA_EVENSTARTER:
|
||||
TombEventStarterGUID = data;
|
||||
if (!TombEventStarterGUID)
|
||||
TombOfSevenReset();//reset
|
||||
else
|
||||
TombOfSevenStart();//start
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: Instance Blackrock Depths: SetData update (Type: %u Data %u)", type, data);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_RING_OF_LAW:
|
||||
encounter[0] = data;
|
||||
break;
|
||||
case TYPE_VAULT:
|
||||
encounter[1] = data;
|
||||
break;
|
||||
case TYPE_BAR:
|
||||
if (data == SPECIAL)
|
||||
++BarAleCount;
|
||||
else
|
||||
encounter[2] = data;
|
||||
break;
|
||||
case TYPE_TOMB_OF_SEVEN:
|
||||
encounter[3] = data;
|
||||
break;
|
||||
case TYPE_LYCEUM:
|
||||
encounter[4] = data;
|
||||
break;
|
||||
case TYPE_IRON_HALL:
|
||||
encounter[5] = data;
|
||||
break;
|
||||
case DATA_GHOSTKILL:
|
||||
GhostKillCount += data;
|
||||
break;
|
||||
case DATA_OPEN_COFFER_DOORS:
|
||||
OpenedCoofers += 1;
|
||||
if (OpenedCoofers == 12)
|
||||
{
|
||||
Position pos = {812.15f, -348.91f, -50.579f, 0.7f};
|
||||
if (TempSummon* summon = instance->SummonCreature(NPC_WATCHMAN_DOOMGRIP, pos))
|
||||
summon->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (data == DONE || GhostKillCount >= 7)
|
||||
{
|
||||
OUT_SAVE_INST_DATA;
|
||||
|
||||
std::ostringstream saveStream;
|
||||
saveStream << encounter[0] << ' ' << encounter[1] << ' ' << encounter[2] << ' '
|
||||
<< encounter[3] << ' ' << encounter[4] << ' ' << encounter[5] << ' ' << GhostKillCount;
|
||||
|
||||
str_data = saveStream.str();
|
||||
|
||||
SaveToDB();
|
||||
OUT_SAVE_INST_DATA_COMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_RING_OF_LAW:
|
||||
return encounter[0];
|
||||
case TYPE_VAULT:
|
||||
return encounter[1];
|
||||
case TYPE_BAR:
|
||||
if (encounter[2] == IN_PROGRESS && BarAleCount == 3)
|
||||
return SPECIAL;
|
||||
else
|
||||
return encounter[2];
|
||||
case TYPE_TOMB_OF_SEVEN:
|
||||
return encounter[3];
|
||||
case TYPE_LYCEUM:
|
||||
return encounter[4];
|
||||
case TYPE_IRON_HALL:
|
||||
return encounter[5];
|
||||
case DATA_GHOSTKILL:
|
||||
return GhostKillCount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64 GetData64(uint32 data) const
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case DATA_EMPEROR:
|
||||
return EmperorGUID;
|
||||
case DATA_PHALANX:
|
||||
return PhalanxGUID;
|
||||
case DATA_MOIRA:
|
||||
return MoiraGUID;
|
||||
case DATA_ARENA1:
|
||||
return GoArena1GUID;
|
||||
case DATA_ARENA2:
|
||||
return GoArena2GUID;
|
||||
case DATA_ARENA3:
|
||||
return GoArena3GUID;
|
||||
case DATA_ARENA4:
|
||||
return GoArena4GUID;
|
||||
case DATA_GO_BAR_KEG:
|
||||
return GoBarKegGUID;
|
||||
case DATA_GO_BAR_KEG_TRAP:
|
||||
return GoBarKegTrapGUID;
|
||||
case DATA_GO_BAR_DOOR:
|
||||
return GoBarDoorGUID;
|
||||
case DATA_EVENSTARTER:
|
||||
return TombEventStarterGUID;
|
||||
case DATA_SF_BRAZIER_N:
|
||||
return GoSFNGUID;
|
||||
case DATA_SF_BRAZIER_S:
|
||||
return GoSFSGUID;
|
||||
case DATA_THRONE_DOOR:
|
||||
return GoThroneGUID;
|
||||
case DATA_GOLEM_DOOR_N:
|
||||
return GoGolemNGUID;
|
||||
case DATA_GOLEM_DOOR_S:
|
||||
return GoGolemSGUID;
|
||||
case DATA_GO_CHALICE:
|
||||
return GoSpectralChaliceGUID;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string GetSaveData()
|
||||
{
|
||||
return str_data;
|
||||
}
|
||||
|
||||
void Load(const char* in)
|
||||
{
|
||||
if (!in)
|
||||
{
|
||||
OUT_LOAD_INST_DATA_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
OUT_LOAD_INST_DATA(in);
|
||||
|
||||
std::istringstream loadStream(in);
|
||||
loadStream >> encounter[0] >> encounter[1] >> encounter[2] >> encounter[3]
|
||||
>> encounter[4] >> encounter[5] >> GhostKillCount;
|
||||
|
||||
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
|
||||
if (encounter[i] == IN_PROGRESS)
|
||||
encounter[i] = NOT_STARTED;
|
||||
if (GhostKillCount > 0 && GhostKillCount < 7)
|
||||
GhostKillCount = 0;//reset tomb of seven event
|
||||
if (GhostKillCount >= 7)
|
||||
GhostKillCount = 7;
|
||||
|
||||
OUT_LOAD_INST_DATA_COMPLETE;
|
||||
}
|
||||
|
||||
void TombOfSevenEvent()
|
||||
{
|
||||
if (GhostKillCount < 7 && TombBossGUIDs[TombEventCounter])
|
||||
{
|
||||
if (Creature* boss = instance->GetCreature(TombBossGUIDs[TombEventCounter]))
|
||||
{
|
||||
boss->setFaction(FACTION_HOSTILE);
|
||||
boss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
||||
if (Unit* target = boss->SelectNearestTarget(500))
|
||||
boss->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TombOfSevenReset()
|
||||
{
|
||||
HandleGameObject(GoTombExitGUID, false);//event reseted, close exit door
|
||||
HandleGameObject(GoTombEnterGUID, true);//event reseted, open entrance door
|
||||
for (uint8 i = 0; i < 7; ++i)
|
||||
{
|
||||
if (Creature* boss = instance->GetCreature(TombBossGUIDs[i]))
|
||||
{
|
||||
if (!boss->IsAlive())
|
||||
{//do not call EnterEvadeMode(), it will create infinit loops
|
||||
boss->Respawn();
|
||||
boss->RemoveAllAuras();
|
||||
boss->DeleteThreatList();
|
||||
boss->CombatStop(true);
|
||||
boss->LoadCreaturesAddon(true);
|
||||
boss->GetMotionMaster()->MoveTargetedHome();
|
||||
boss->SetLootRecipient(NULL);
|
||||
}
|
||||
boss->setFaction(FACTION_FRIEND);
|
||||
}
|
||||
}
|
||||
GhostKillCount = 0;
|
||||
TombEventStarterGUID = 0;
|
||||
TombEventCounter = 0;
|
||||
TombTimer = TIMER_TOMBOFTHESEVEN;
|
||||
SetData(TYPE_TOMB_OF_SEVEN, NOT_STARTED);
|
||||
}
|
||||
|
||||
void TombOfSevenStart()
|
||||
{
|
||||
HandleGameObject(GoTombExitGUID, false);//event started, close exit door
|
||||
HandleGameObject(GoTombEnterGUID, false);//event started, close entrance door
|
||||
SetData(TYPE_TOMB_OF_SEVEN, IN_PROGRESS);
|
||||
}
|
||||
|
||||
void TombOfSevenEnd()
|
||||
{
|
||||
DoRespawnGameObject(GoChestGUID, DAY);
|
||||
HandleGameObject(GoTombExitGUID, true);//event done, open exit door
|
||||
HandleGameObject(GoTombEnterGUID, true);//event done, open entrance door
|
||||
TombEventStarterGUID = 0;
|
||||
SetData(TYPE_TOMB_OF_SEVEN, DONE);
|
||||
}
|
||||
void Update(uint32 diff)
|
||||
{
|
||||
if (TombEventStarterGUID && GhostKillCount < 7)
|
||||
{
|
||||
if (TombTimer <= diff)
|
||||
{
|
||||
TombTimer = TIMER_TOMBOFTHESEVEN;
|
||||
++TombEventCounter;
|
||||
TombOfSevenEvent();
|
||||
// Check Killed bosses
|
||||
for (uint8 i = 0; i < 7; ++i)
|
||||
{
|
||||
if (Creature* boss = instance->GetCreature(TombBossGUIDs[i]))
|
||||
{
|
||||
if (!boss->IsAlive())
|
||||
{
|
||||
GhostKillCount = i+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else TombTimer -= diff;
|
||||
}
|
||||
if (GhostKillCount >= 7 && TombEventStarterGUID)
|
||||
TombOfSevenEnd();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_instance_blackrock_depths()
|
||||
{
|
||||
new instance_blackrock_depths();
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DEF_BLACKROCK_SPIRE_H
|
||||
#define DEF_BLACKROCK_SPIRE_H
|
||||
|
||||
uint32 const EncounterCount = 23;
|
||||
|
||||
#define BRSScriptName "instance_blackrock_spire"
|
||||
|
||||
enum DataTypes
|
||||
{
|
||||
DATA_HIGHLORD_OMOKK = 0,
|
||||
DATA_SHADOW_HUNTER_VOSHGAJIN = 1,
|
||||
DATA_WARMASTER_VOONE = 2,
|
||||
DATA_MOTHER_SMOLDERWEB = 3,
|
||||
DATA_UROK_DOOMHOWL = 4,
|
||||
DATA_QUARTERMASTER_ZIGRIS = 5,
|
||||
DATA_GIZRUL_THE_SLAVENER = 6,
|
||||
DATA_HALYCON = 7,
|
||||
DATA_OVERLORD_WYRMTHALAK = 8,
|
||||
DATA_PYROGAURD_EMBERSEER = 9,
|
||||
DATA_WARCHIEF_REND_BLACKHAND = 10,
|
||||
DATA_GYTH = 11,
|
||||
DATA_THE_BEAST = 12,
|
||||
DATA_GENERAL_DRAKKISATH = 13,
|
||||
DATA_LORD_VALTHALAK = 14,
|
||||
// Extra
|
||||
DATA_DRAGONSPIRE_ROOM = 15,
|
||||
DATA_HALL_RUNE_1 = 16,
|
||||
DATA_HALL_RUNE_2 = 17,
|
||||
DATA_HALL_RUNE_3 = 18,
|
||||
DATA_HALL_RUNE_4 = 19,
|
||||
DATA_HALL_RUNE_5 = 20,
|
||||
DATA_HALL_RUNE_6 = 21,
|
||||
DATA_HALL_RUNE_7 = 22
|
||||
};
|
||||
|
||||
enum CreaturesIds
|
||||
{
|
||||
NPC_HIGHLORD_OMOKK = 9196,
|
||||
NPC_SHADOW_HUNTER_VOSHGAJIN = 9236,
|
||||
NPC_WARMASTER_VOONE = 9237,
|
||||
NPC_MOTHER_SMOLDERWEB = 10596,
|
||||
NPC_UROK_DOOMHOWL = 10584,
|
||||
NPC_QUARTERMASTER_ZIGRIS = 9736,
|
||||
NPC_GIZRUL_THE_SLAVENER = 10268,
|
||||
NPC_HALYCON = 10220,
|
||||
NPC_OVERLORD_WYRMTHALAK = 9568,
|
||||
NPC_PYROGAURD_EMBERSEER = 9816,
|
||||
NPC_WARCHIEF_REND_BLACKHAND = 10429,
|
||||
NPC_GYTH = 10339,
|
||||
NPC_THE_BEAST = 10430,
|
||||
NPC_GENERAL_DRAKKISATH = 10363,
|
||||
NPC_BLACKHAND_DREADWEAVER = 9817,
|
||||
NPC_BLACKHAND_SUMMONER = 9818,
|
||||
NPC_BLACKHAND_VETERAN = 9819,
|
||||
NPC_BLACKHAND_INCARCERATOR = 10316,
|
||||
NPC_LORD_VICTOR_NEFARIUS = 10162
|
||||
};
|
||||
|
||||
enum AdditionalData
|
||||
{
|
||||
SPELL_SUMMON_ROOKERY_WHELP = 15745,
|
||||
EVENT_UROK_DOOMHOWL = 4845,
|
||||
EVENT_PYROGUARD_EMBERSEER = 4884,
|
||||
AREATRIGGER = 1,
|
||||
AREATRIGGER_DRAGONSPIRE_HALL = 2046,
|
||||
AREATRIGGER_BLACKROCK_STADIUM = 2026
|
||||
};
|
||||
|
||||
enum GameObjectsIds
|
||||
{
|
||||
GO_WHELP_SPAWNER = 175622, // trap spawned by go id 175124
|
||||
// Doors
|
||||
GO_EMBERSEER_IN = 175244, // First door to Pyroguard Emberseer
|
||||
GO_DOORS = 175705, // Second door to Pyroguard Emberseer
|
||||
GO_EMBERSEER_OUT = 175153, // Door after Pyroguard Emberseer event
|
||||
GO_GYTH_ENTRY_DOOR = 164726,
|
||||
GO_GYTH_COMBAT_DOOR = 175185,
|
||||
GO_GYTH_EXIT_DOOR = 175186,
|
||||
GO_DRAKKISATH_DOOR_1 = 175946,
|
||||
GO_DRAKKISATH_DOOR_2 = 175947,
|
||||
// Runes in dragonspire hall
|
||||
GO_HALL_RUNE_1 = 175197,
|
||||
GO_HALL_RUNE_2 = 175199,
|
||||
GO_HALL_RUNE_3 = 175195,
|
||||
GO_HALL_RUNE_4 = 175200,
|
||||
GO_HALL_RUNE_5 = 175198,
|
||||
GO_HALL_RUNE_6 = 175196,
|
||||
GO_HALL_RUNE_7 = 175194,
|
||||
// Runes in emberseers room
|
||||
GO_EMBERSEER_RUNE_1 = 175266,
|
||||
GO_EMBERSEER_RUNE_2 = 175267,
|
||||
GO_EMBERSEER_RUNE_3 = 175268,
|
||||
GO_EMBERSEER_RUNE_4 = 175269,
|
||||
GO_EMBERSEER_RUNE_5 = 175270,
|
||||
GO_EMBERSEER_RUNE_6 = 175271,
|
||||
GO_EMBERSEER_RUNE_7 = 175272,
|
||||
// For Gyth event
|
||||
GO_DR_PORTCULLIS = 175185,
|
||||
GO_PORTCULLIS_ACTIVE = 164726,
|
||||
GO_PORTCULLIS_TOBOSSROOMS = 175186,
|
||||
// Urok Doomhowl
|
||||
GO_UROK_PILE = 175621,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FIRENOVA = 23462,
|
||||
SPELL_CLEAVE = 20691,
|
||||
SPELL_CONFLIGURATION = 16805,
|
||||
SPELL_THUNDERCLAP = 15548, //Not sure if right ID. 23931 would be a harder possibility.
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_FIRE_NOVA = 1,
|
||||
EVENT_CLEAVE = 2,
|
||||
EVENT_CONFLIGURATION = 3,
|
||||
EVENT_THUNDERCLAP = 4,
|
||||
};
|
||||
|
||||
class boss_drakkisath : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_drakkisath() : CreatureScript("boss_drakkisath") { }
|
||||
|
||||
struct boss_drakkisathAI : public BossAI
|
||||
{
|
||||
boss_drakkisathAI(Creature* creature) : BossAI(creature, DATA_GENERAL_DRAKKISATH) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_FIRE_NOVA, 6000);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 8000);
|
||||
events.ScheduleEvent(EVENT_CONFLIGURATION, 15000);
|
||||
events.ScheduleEvent(EVENT_THUNDERCLAP, 17000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_FIRE_NOVA:
|
||||
DoCastVictim(SPELL_FIRENOVA);
|
||||
events.ScheduleEvent(EVENT_FIRE_NOVA, 10000);
|
||||
break;
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 8000);
|
||||
break;
|
||||
case EVENT_CONFLIGURATION:
|
||||
DoCastVictim(SPELL_CONFLIGURATION);
|
||||
events.ScheduleEvent(EVENT_CONFLIGURATION, 18000);
|
||||
break;
|
||||
case EVENT_THUNDERCLAP:
|
||||
DoCastVictim(SPELL_THUNDERCLAP);
|
||||
events.ScheduleEvent(EVENT_THUNDERCLAP, 20000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_drakkisathAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_drakkisath()
|
||||
{
|
||||
new boss_drakkisath();
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FATAL_BITE = 16495,
|
||||
SPELL_INFECTED_BITE = 16128,
|
||||
SPELL_FRENZY = 8269
|
||||
};
|
||||
|
||||
enum Paths
|
||||
{
|
||||
GIZRUL_PATH = 402450
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_FATAL_BITE = 1,
|
||||
EVENT_INFECTED_BITE = 2,
|
||||
EVENT_FRENZY = 3
|
||||
};
|
||||
|
||||
class boss_gizrul_the_slavener : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_gizrul_the_slavener() : CreatureScript("boss_gizrul_the_slavener") { }
|
||||
|
||||
struct boss_gizrul_the_slavenerAI : public BossAI
|
||||
{
|
||||
boss_gizrul_the_slavenerAI(Creature* creature) : BossAI(creature, DATA_GIZRUL_THE_SLAVENER) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void IsSummonedBy(Unit* /*summoner*/)
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(GIZRUL_PATH, false);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_FATAL_BITE, urand(17000,20000));
|
||||
events.ScheduleEvent(EVENT_INFECTED_BITE, urand(10000,12000));
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_FATAL_BITE:
|
||||
DoCastVictim(SPELL_FATAL_BITE);
|
||||
events.ScheduleEvent(EVENT_FATAL_BITE, urand(8000,10000));
|
||||
break;
|
||||
case EVENT_INFECTED_BITE:
|
||||
DoCast(me, SPELL_INFECTED_BITE);
|
||||
events.ScheduleEvent(EVENT_FATAL_BITE, urand(8000,10000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_gizrul_the_slavenerAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_gizrul_the_slavener()
|
||||
{
|
||||
new boss_gizrul_the_slavener();
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_REND_MOUNTS = 16167, // Change model
|
||||
SPELL_CORROSIVE_ACID = 16359, // Combat (self cast)
|
||||
SPELL_FLAMEBREATH = 16390, // Combat (Self cast)
|
||||
SPELL_FREEZE = 16350, // Combat (Self cast)
|
||||
SPELL_KNOCK_AWAY = 10101, // Combat
|
||||
SPELL_SUMMON_REND = 16328 // Summons Rend near death
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
NEFARIUS_PATH_2 = 1379671,
|
||||
NEFARIUS_PATH_3 = 1379672,
|
||||
GYTH_PATH_1 = 1379681,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_CORROSIVE_ACID = 1,
|
||||
EVENT_FREEZE = 2,
|
||||
EVENT_FLAME_BREATH = 3,
|
||||
EVENT_KNOCK_AWAY = 4,
|
||||
EVENT_SUMMONED_1 = 5,
|
||||
EVENT_SUMMONED_2 = 6
|
||||
};
|
||||
|
||||
class boss_gyth : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_gyth() : CreatureScript("boss_gyth") { }
|
||||
|
||||
struct boss_gythAI : public BossAI
|
||||
{
|
||||
boss_gythAI(Creature* creature) : BossAI(creature, DATA_GYTH) { }
|
||||
|
||||
bool SummonedRend;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
SummonedRend = false;
|
||||
if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS)
|
||||
{
|
||||
instance->SetBossState(DATA_GYTH, DONE);
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
|
||||
events.ScheduleEvent(EVENT_CORROSIVE_ACID, urand(8000, 16000));
|
||||
events.ScheduleEvent(EVENT_FREEZE, urand(8000, 16000));
|
||||
events.ScheduleEvent(EVENT_FLAME_BREATH, urand(8000, 16000));
|
||||
events.ScheduleEvent(EVENT_KNOCK_AWAY, urand(12000, 18000));
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
instance->SetBossState(DATA_GYTH, DONE);
|
||||
}
|
||||
|
||||
void SetData(uint32 /*type*/, uint32 data)
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case 1:
|
||||
events.ScheduleEvent(EVENT_SUMMONED_1, 1000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
|
||||
if (!SummonedRend && HealthBelowPct(5))
|
||||
{
|
||||
DoCast(me, SPELL_SUMMON_REND);
|
||||
me->RemoveAura(SPELL_REND_MOUNTS);
|
||||
SummonedRend = true;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SUMMONED_1:
|
||||
me->AddAura(SPELL_REND_MOUNTS, me);
|
||||
if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 40.0f))
|
||||
portcullis->UseDoorOrButton();
|
||||
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 75.0f, true))
|
||||
victor->AI()->SetData(1, 1);
|
||||
events.ScheduleEvent(EVENT_SUMMONED_2, 2000);
|
||||
break;
|
||||
case EVENT_SUMMONED_2:
|
||||
me->GetMotionMaster()->MovePath(GYTH_PATH_1, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CORROSIVE_ACID:
|
||||
DoCast(me, SPELL_CORROSIVE_ACID);
|
||||
events.ScheduleEvent(EVENT_CORROSIVE_ACID, urand(10000, 16000));
|
||||
break;
|
||||
case EVENT_FREEZE:
|
||||
DoCast(me, SPELL_FREEZE);
|
||||
events.ScheduleEvent(EVENT_FREEZE, urand(10000, 16000));
|
||||
break;
|
||||
case EVENT_FLAME_BREATH:
|
||||
DoCast(me, SPELL_FLAMEBREATH);
|
||||
events.ScheduleEvent(EVENT_FLAME_BREATH, urand(10000, 16000));
|
||||
break;
|
||||
case EVENT_KNOCK_AWAY:
|
||||
DoCastVictim(SPELL_KNOCK_AWAY);
|
||||
events.ScheduleEvent(EVENT_KNOCK_AWAY, urand(14000, 20000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_gythAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_gyth()
|
||||
{
|
||||
new boss_gyth();
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_REND = 13738,
|
||||
SPELL_THRASH = 3391,
|
||||
};
|
||||
|
||||
enum Says
|
||||
{
|
||||
EMOTE_DEATH = 0
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_REND = 1,
|
||||
EVENT_THRASH = 2,
|
||||
};
|
||||
|
||||
const Position SummonLocation = { -167.9561f, -411.7844f, 76.23057f, 1.53589f };
|
||||
|
||||
class boss_halycon : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_halycon() : CreatureScript("boss_halycon") { }
|
||||
|
||||
struct boss_halyconAI : public BossAI
|
||||
{
|
||||
boss_halyconAI(Creature* creature) : BossAI(creature, DATA_HALYCON) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
Summoned = false;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_REND, urand(17000,20000));
|
||||
events.ScheduleEvent(EVENT_THRASH, urand(10000,12000));
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
me->SummonCreature(NPC_GIZRUL_THE_SLAVENER, SummonLocation, TEMPSUMMON_TIMED_DESPAWN, 300000);
|
||||
Talk(EMOTE_DEATH);
|
||||
|
||||
Summoned = true;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_REND:
|
||||
DoCastVictim(SPELL_REND);
|
||||
events.ScheduleEvent(EVENT_REND, urand(8000,10000));
|
||||
break;
|
||||
case EVENT_THRASH:
|
||||
DoCast(me, SPELL_THRASH);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
bool Summoned;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_halyconAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_halycon()
|
||||
{
|
||||
new boss_halycon();
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FRENZY = 8269,
|
||||
SPELL_KNOCK_AWAY = 10101
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_FRENZY = 1,
|
||||
EVENT_KNOCK_AWAY = 2
|
||||
};
|
||||
|
||||
class boss_highlord_omokk : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_highlord_omokk() : CreatureScript("boss_highlord_omokk") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_highlordomokkAI(creature);
|
||||
}
|
||||
|
||||
struct boss_highlordomokkAI : public BossAI
|
||||
{
|
||||
boss_highlordomokkAI(Creature* creature) : BossAI(creature, DATA_HIGHLORD_OMOKK) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_FRENZY, 20000);
|
||||
events.ScheduleEvent(EVENT_KNOCK_AWAY, 18000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_FRENZY:
|
||||
DoCastVictim(SPELL_FRENZY);
|
||||
events.ScheduleEvent(EVENT_FRENZY, 60000);
|
||||
break;
|
||||
case EVENT_KNOCK_AWAY:
|
||||
DoCastVictim(SPELL_KNOCK_AWAY);
|
||||
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
void AddSC_boss_highlordomokk()
|
||||
{
|
||||
new boss_highlord_omokk();
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FRENZY = 8269,
|
||||
SPELL_SUMMON_SPECTRAL_ASSASSIN = 27249,
|
||||
SPELL_SHADOW_BOLT_VOLLEY = 27382,
|
||||
SPELL_SHADOW_WRATH = 27286
|
||||
};
|
||||
|
||||
enum Says
|
||||
{
|
||||
EMOTE_FRENZY = 0
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SUMMON_SPECTRAL_ASSASSIN = 1,
|
||||
EVENT_SHADOW_BOLT_VOLLEY = 2,
|
||||
EVENT_SHADOW_WRATH = 3
|
||||
};
|
||||
|
||||
class boss_lord_valthalak : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_lord_valthalak() : CreatureScript("boss_lord_valthalak") { }
|
||||
|
||||
struct boss_lord_valthalakAI : public BossAI
|
||||
{
|
||||
boss_lord_valthalakAI(Creature* creature) : BossAI(creature, DATA_LORD_VALTHALAK) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
frenzy40 = false;
|
||||
frenzy15 = false;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, urand(6000,8000));
|
||||
events.ScheduleEvent(EVENT_SHADOW_WRATH, urand(9000,18000));
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
instance->SetData(DATA_LORD_VALTHALAK, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SUMMON_SPECTRAL_ASSASSIN:
|
||||
DoCast(me, SPELL_SUMMON_SPECTRAL_ASSASSIN);
|
||||
events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, urand(30000,35000));
|
||||
break;
|
||||
case EVENT_SHADOW_BOLT_VOLLEY:
|
||||
DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, urand(4000,6000));
|
||||
break;
|
||||
case EVENT_SHADOW_WRATH:
|
||||
DoCastVictim(SPELL_SHADOW_WRATH);
|
||||
events.ScheduleEvent(EVENT_SHADOW_WRATH, urand(19000,24000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frenzy40)
|
||||
{
|
||||
if (HealthBelowPct(40))
|
||||
{
|
||||
DoCast(me, SPELL_FRENZY);
|
||||
events.CancelEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN);
|
||||
frenzy40 = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frenzy15)
|
||||
{
|
||||
if (HealthBelowPct(15))
|
||||
{
|
||||
DoCast(me, SPELL_FRENZY);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, urand(7000,14000));
|
||||
frenzy15 = true;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
bool frenzy40;
|
||||
bool frenzy15;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_lord_valthalakAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_lord_valthalak()
|
||||
{
|
||||
new boss_lord_valthalak();
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CRYSTALIZE = 16104,
|
||||
SPELL_MOTHERSMILK = 16468,
|
||||
SPELL_SUMMON_SPIRE_SPIDERLING = 16103,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_CRYSTALIZE = 1,
|
||||
EVENT_MOTHERS_MILK = 2,
|
||||
};
|
||||
|
||||
class boss_mother_smolderweb : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_mother_smolderweb() : CreatureScript("boss_mother_smolderweb") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_mothersmolderwebAI(creature);
|
||||
}
|
||||
|
||||
struct boss_mothersmolderwebAI : public BossAI
|
||||
{
|
||||
boss_mothersmolderwebAI(Creature* creature) : BossAI(creature, DATA_MOTHER_SMOLDERWEB) {}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_CRYSTALIZE, 20 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_MOTHERS_MILK, 10 * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32 &damage, DamageEffectType, SpellSchoolMask)
|
||||
{
|
||||
if (me->GetHealth() <= damage)
|
||||
DoCast(me, SPELL_SUMMON_SPIRE_SPIDERLING, true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CRYSTALIZE:
|
||||
DoCast(me, SPELL_CRYSTALIZE);
|
||||
events.ScheduleEvent(EVENT_CRYSTALIZE, 15 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_MOTHERS_MILK:
|
||||
DoCast(me, SPELL_MOTHERSMILK);
|
||||
events.ScheduleEvent(EVENT_MOTHERS_MILK, urand(5 * IN_MILLISECONDS, 12500));
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
void AddSC_boss_mothersmolderweb()
|
||||
{
|
||||
new boss_mother_smolderweb();
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_BLASTWAVE = 11130,
|
||||
SPELL_SHOUT = 23511,
|
||||
SPELL_CLEAVE = 20691,
|
||||
SPELL_KNOCKAWAY = 20686
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_BLAST_WAVE = 1,
|
||||
EVENT_SHOUT = 2,
|
||||
EVENT_CLEAVE = 3,
|
||||
EVENT_KNOCK_AWAY = 4
|
||||
};
|
||||
|
||||
enum Adds
|
||||
{
|
||||
NPC_SPIRESTONE_WARLORD = 9216,
|
||||
NPC_SMOLDERTHORN_BERSERKER = 9268
|
||||
};
|
||||
|
||||
const Position SummonLocation1 = { -39.355f, -513.456f, 88.472f, 4.679f };
|
||||
const Position SummonLocation2 = { -49.875f, -511.896f, 88.195f, 4.613f };
|
||||
|
||||
class boss_overlord_wyrmthalak : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_overlord_wyrmthalak() : CreatureScript("boss_overlord_wyrmthalak") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_overlordwyrmthalakAI(creature);
|
||||
}
|
||||
|
||||
struct boss_overlordwyrmthalakAI : public BossAI
|
||||
{
|
||||
boss_overlordwyrmthalakAI(Creature* creature) : BossAI(creature, DATA_OVERLORD_WYRMTHALAK) { }
|
||||
|
||||
bool Summoned;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
Summoned = false;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_BLAST_WAVE, 20 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_SHOUT, 2 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 6 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12 * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!Summoned && HealthBelowPct(51))
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
{
|
||||
if (Creature* warlord = me->SummonCreature(NPC_SPIRESTONE_WARLORD, SummonLocation1, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS))
|
||||
warlord->AI()->AttackStart(target);
|
||||
if (Creature* berserker = me->SummonCreature(NPC_SMOLDERTHORN_BERSERKER, SummonLocation2, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS))
|
||||
berserker->AI()->AttackStart(target);
|
||||
Summoned = true;
|
||||
}
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BLAST_WAVE:
|
||||
DoCastVictim(SPELL_BLASTWAVE);
|
||||
events.ScheduleEvent(EVENT_BLAST_WAVE, 20 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_SHOUT:
|
||||
DoCastVictim(SPELL_SHOUT);
|
||||
events.ScheduleEvent(EVENT_SHOUT, 10 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 7 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_KNOCK_AWAY:
|
||||
DoCastVictim(SPELL_KNOCKAWAY);
|
||||
events.ScheduleEvent(EVENT_KNOCK_AWAY, 14 * IN_MILLISECONDS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_overlordwyrmthalak()
|
||||
{
|
||||
new boss_overlord_wyrmthalak();
|
||||
}
|
||||
@@ -1,441 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Player.h"
|
||||
#include "Spell.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Text
|
||||
{
|
||||
EMOTE_ONE_STACK = 0,
|
||||
EMOTE_TEN_STACK = 1,
|
||||
EMOTE_FREE_OF_BONDS = 2,
|
||||
YELL_FREE_OF_BONDS = 3
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_ENCAGED_EMBERSEER = 15282, // Self on spawn
|
||||
SPELL_FIRE_SHIELD_TRIGGER = 13377, // Self on spawn missing from 335 dbc triggers SPELL_FIRE_SHIELD every 3 sec
|
||||
SPELL_FIRE_SHIELD = 13376, // Triggered by SPELL_FIRE_SHIELD_TRIGGER
|
||||
SPELL_FREEZE_ANIM = 16245, // Self on event start
|
||||
SPELL_EMBERSEER_GROWING = 16048, // Self on event start
|
||||
SPELL_EMBERSEER_GROWING_TRIGGER = 16049, // Triggered by SPELL_EMBERSEER_GROWING
|
||||
SPELL_EMBERSEER_FULL_STRENGTH = 16047, // Emberseer Full Strength
|
||||
SPELL_FIRENOVA = 23462, // Combat
|
||||
SPELL_FLAMEBUFFET = 23341, // Combat
|
||||
SPELL_PYROBLAST = 17274, // Combat
|
||||
// Blackhand Incarcerator Spells
|
||||
SPELL_ENCAGE_EMBERSEER = 15281, // Emberseer on spawn
|
||||
SPELL_STRIKE = 15580, // Combat
|
||||
SPELL_ENCAGE = 16045, // Combat
|
||||
// Cast on player by altar
|
||||
SPELL_EMBERSEER_OBJECT_VISUAL = 16532
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
// Respawn
|
||||
EVENT_RESPAWN = 1,
|
||||
// Pre fight
|
||||
EVENT_PRE_FIGHT_1 = 2,
|
||||
EVENT_PRE_FIGHT_2 = 3,
|
||||
// Combat
|
||||
EVENT_FIRENOVA = 4,
|
||||
EVENT_FLAMEBUFFET = 5,
|
||||
EVENT_PYROBLAST = 6,
|
||||
// Hack due to trigger spell not in dbc
|
||||
EVENT_FIRE_SHIELD = 7,
|
||||
// Make sure all players have aura from altar
|
||||
EVENT_PLAYER_CHECK = 8,
|
||||
EVENT_ENTER_COMBAT = 9
|
||||
};
|
||||
|
||||
class boss_pyroguard_emberseer : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_pyroguard_emberseer() : CreatureScript("boss_pyroguard_emberseer") { }
|
||||
|
||||
struct boss_pyroguard_emberseerAI : public BossAI
|
||||
{
|
||||
boss_pyroguard_emberseerAI(Creature* creature) : BossAI(creature, DATA_PYROGAURD_EMBERSEER) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE);
|
||||
events.Reset();
|
||||
// Apply auras on spawn and reset
|
||||
// DoCast(me, SPELL_FIRE_SHIELD_TRIGGER); // Need to find this in old DBC if possible
|
||||
me->RemoveAura(SPELL_EMBERSEER_FULL_STRENGTH);
|
||||
me->RemoveAura(SPELL_EMBERSEER_GROWING);
|
||||
me->RemoveAura(SPELL_EMBERSEER_GROWING_TRIGGER);
|
||||
events.ScheduleEvent(EVENT_RESPAWN, 5000);
|
||||
// Hack for missing trigger spell
|
||||
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3000);
|
||||
|
||||
// Open doors on reset
|
||||
if (instance->GetBossState(DATA_PYROGAURD_EMBERSEER) == IN_PROGRESS)
|
||||
OpenDoors(false); // Opens 2 entrance doors
|
||||
}
|
||||
|
||||
void SetData(uint32 /*type*/, uint32 data)
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case 1:
|
||||
events.ScheduleEvent(EVENT_PLAYER_CHECK, 5000);
|
||||
break;
|
||||
case 2:
|
||||
// Close these two doors on Blackhand Incarcerators aggro
|
||||
if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_IN)))
|
||||
if (door1->GetGoState() == GO_STATE_ACTIVE)
|
||||
door1->SetGoState(GO_STATE_READY);
|
||||
if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetData64(GO_DOORS)))
|
||||
if (door2->GetGoState() == GO_STATE_ACTIVE)
|
||||
door2->SetGoState(GO_STATE_READY);
|
||||
break;
|
||||
case 3:
|
||||
Reset();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
// ### TODO Check combat timing ###
|
||||
events.ScheduleEvent(EVENT_FIRENOVA, 6000);
|
||||
events.ScheduleEvent(EVENT_FLAMEBUFFET, 3000);
|
||||
events.ScheduleEvent(EVENT_PYROBLAST, 14000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
// Activate all the runes
|
||||
UpdateRunes(GO_STATE_READY);
|
||||
// Opens all 3 doors
|
||||
OpenDoors(true);
|
||||
// Complete encounter
|
||||
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, DONE);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell)
|
||||
{
|
||||
if (spell->Id == SPELL_ENCAGE_EMBERSEER)
|
||||
{
|
||||
if (!me->GetAuraCount(SPELL_ENCAGED_EMBERSEER))
|
||||
me->CastSpell(me, SPELL_ENCAGED_EMBERSEER);
|
||||
}
|
||||
|
||||
if (spell->Id == SPELL_EMBERSEER_GROWING_TRIGGER)
|
||||
{
|
||||
if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 10)
|
||||
Talk(EMOTE_TEN_STACK);
|
||||
|
||||
if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 20)
|
||||
{
|
||||
me->RemoveAura(SPELL_ENCAGED_EMBERSEER);
|
||||
me->RemoveAura(SPELL_FREEZE_ANIM);
|
||||
me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH);
|
||||
Talk(EMOTE_FREE_OF_BONDS);
|
||||
Talk(YELL_FREE_OF_BONDS);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE);
|
||||
events.ScheduleEvent(EVENT_ENTER_COMBAT, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenDoors(bool Boss_Killed)
|
||||
{
|
||||
// These two doors reopen on reset or boss kill
|
||||
if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_IN)))
|
||||
door1->SetGoState(GO_STATE_ACTIVE);
|
||||
if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetData64(GO_DOORS)))
|
||||
door2->SetGoState(GO_STATE_ACTIVE);
|
||||
|
||||
// This door opens on boss kill
|
||||
if (Boss_Killed)
|
||||
if (GameObject* door3 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_OUT)))
|
||||
door3->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
void UpdateRunes(GOState state)
|
||||
{
|
||||
// update all runes
|
||||
if (GameObject* rune1 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_RUNE_1)))
|
||||
rune1->SetGoState(state);
|
||||
if (GameObject* rune2 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_RUNE_2)))
|
||||
rune2->SetGoState(state);
|
||||
if (GameObject* rune3 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_RUNE_3)))
|
||||
rune3->SetGoState(state);
|
||||
if (GameObject* rune4 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_RUNE_4)))
|
||||
rune4->SetGoState(state);
|
||||
if (GameObject* rune5 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_RUNE_5)))
|
||||
rune5->SetGoState(state);
|
||||
if (GameObject* rune6 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_RUNE_6)))
|
||||
rune6->SetGoState(state);
|
||||
if (GameObject* rune7 = me->GetMap()->GetGameObject(instance->GetData64(GO_EMBERSEER_RUNE_7)))
|
||||
rune7->SetGoState(state);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_RESPAWN:
|
||||
{
|
||||
// Respawn all Blackhand Incarcerators
|
||||
std::list<Creature*> creatureList;
|
||||
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f);
|
||||
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
|
||||
if (Creature* creature = *itr)
|
||||
{
|
||||
if (!creature->IsAlive())
|
||||
creature->Respawn();
|
||||
|
||||
creature->AI()->SetData(1, 2);
|
||||
}
|
||||
me->AddAura(SPELL_ENCAGED_EMBERSEER, me);
|
||||
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, NOT_STARTED);
|
||||
break;
|
||||
}
|
||||
case EVENT_PRE_FIGHT_1:
|
||||
{
|
||||
// Set data on all Blackhand Incarcerators
|
||||
std::list<Creature*> creatureList;
|
||||
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f);
|
||||
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
|
||||
{
|
||||
if (Creature* creature = *itr)
|
||||
creature->AI()->SetData(1, 1);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_PRE_FIGHT_2, 32000);
|
||||
break;
|
||||
}
|
||||
case EVENT_PRE_FIGHT_2:
|
||||
me->CastSpell(me, SPELL_FREEZE_ANIM);
|
||||
me->CastSpell(me, SPELL_EMBERSEER_GROWING);
|
||||
Talk(EMOTE_ONE_STACK);
|
||||
break;
|
||||
case EVENT_FIRE_SHIELD:
|
||||
// #### Spell isn't doing any damage ??? ####
|
||||
DoCast(me, SPELL_FIRE_SHIELD);
|
||||
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3000);
|
||||
break;
|
||||
case EVENT_PLAYER_CHECK:
|
||||
{
|
||||
// Check to see if all players in instance have aura SPELL_EMBERSEER_START before starting event
|
||||
bool _hasAura = false;
|
||||
Map::PlayerList const &players = me->GetMap()->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
if (Player* player = itr->GetSource()->ToPlayer())
|
||||
if (player->HasAura(SPELL_EMBERSEER_OBJECT_VISUAL))
|
||||
_hasAura = true;
|
||||
|
||||
if (_hasAura)
|
||||
{
|
||||
events.ScheduleEvent(EVENT_PRE_FIGHT_1, 1000);
|
||||
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_ENTER_COMBAT:
|
||||
AttackStart(me->SelectNearestPlayer(30.0f));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_FIRE_SHIELD:
|
||||
DoCast(me, SPELL_FIRE_SHIELD);
|
||||
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3000);
|
||||
break;
|
||||
case EVENT_FIRENOVA:
|
||||
DoCast(me, SPELL_FIRENOVA);
|
||||
events.ScheduleEvent(EVENT_FIRENOVA, 6000);
|
||||
break;
|
||||
case EVENT_FLAMEBUFFET:
|
||||
DoCast(me, SPELL_FLAMEBUFFET);
|
||||
events.ScheduleEvent(EVENT_FLAMEBUFFET, 14000);
|
||||
break;
|
||||
case EVENT_PYROBLAST:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_PYROBLAST);
|
||||
events.ScheduleEvent(EVENT_PYROBLAST, 15000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_pyroguard_emberseerAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
/*####
|
||||
## npc_blackhand_incarcerator
|
||||
####*/
|
||||
|
||||
enum IncarceratorEvents
|
||||
{
|
||||
// OOC
|
||||
EVENT_ENCAGED_EMBERSEER = 1,
|
||||
// Combat
|
||||
EVENT_STRIKE = 2,
|
||||
EVENT_ENCAGE = 3
|
||||
};
|
||||
|
||||
class npc_blackhand_incarcerator : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_blackhand_incarcerator() : CreatureScript("npc_blackhand_incarcerator") { }
|
||||
|
||||
struct npc_blackhand_incarceratorAI : public ScriptedAI
|
||||
{
|
||||
npc_blackhand_incarceratorAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
|
||||
Emberseer->AI()->SetData(1, 3);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
me->DespawnOrUnsummon(10000);
|
||||
}
|
||||
|
||||
void SetData(uint32 data, uint32 value)
|
||||
{
|
||||
if (data == 1 && value == 1)
|
||||
{
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
|
||||
_events.CancelEvent(EVENT_ENCAGED_EMBERSEER);
|
||||
}
|
||||
|
||||
if (data == 1 && value == 2)
|
||||
_events.ScheduleEvent(EVENT_ENCAGED_EMBERSEER, 1000);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
// Used to close doors
|
||||
if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
|
||||
Emberseer->AI()->SetData(1, 2);
|
||||
|
||||
// Had to do this because CallForHelp will ignore any npcs without LOS
|
||||
std::list<Creature*> creatureList;
|
||||
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 60.0f);
|
||||
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
|
||||
{
|
||||
if (Creature* creature = *itr)
|
||||
creature->SetInCombatWithZone(); // AI()->AttackStart(me->GetVictim());
|
||||
}
|
||||
|
||||
_events.ScheduleEvent(EVENT_STRIKE, urand(8000, 16000));
|
||||
_events.ScheduleEvent(EVENT_ENCAGE, urand(10000, 20000));
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
|
||||
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
_events.Update(diff);
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ENCAGED_EMBERSEER:
|
||||
{
|
||||
if (me->GetPositionX() == me->GetHomePosition().GetPositionX())
|
||||
if (!me->HasAura(SPELL_ENCAGE_EMBERSEER))
|
||||
if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
|
||||
DoCast(Emberseer, SPELL_ENCAGE_EMBERSEER);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_STRIKE:
|
||||
DoCastVictim(SPELL_STRIKE, true);
|
||||
_events.ScheduleEvent(EVENT_STRIKE, urand(14000, 23000));
|
||||
break;
|
||||
case EVENT_ENCAGE:
|
||||
DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), EVENT_ENCAGE, true);
|
||||
_events.ScheduleEvent(EVENT_ENCAGE, urand(6000, 12000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap _events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new npc_blackhand_incarceratorAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_pyroguard_emberseer()
|
||||
{
|
||||
new boss_pyroguard_emberseer();
|
||||
new npc_blackhand_incarcerator();
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SHOOT = 16496,
|
||||
SPELL_STUNBOMB = 16497,
|
||||
SPELL_HEALING_POTION = 15504,
|
||||
SPELL_HOOKEDNET = 15609
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SHOOT = 1,
|
||||
EVENT_STUN_BOMB = 2
|
||||
};
|
||||
|
||||
class quartermaster_zigris : public CreatureScript
|
||||
{
|
||||
public:
|
||||
quartermaster_zigris() : CreatureScript("quartermaster_zigris") { }
|
||||
|
||||
struct boss_quatermasterzigrisAI : public BossAI
|
||||
{
|
||||
boss_quatermasterzigrisAI(Creature* creature) : BossAI(creature, DATA_QUARTERMASTER_ZIGRIS) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_SHOOT, 1000);
|
||||
events.ScheduleEvent(EVENT_STUN_BOMB, 16000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SHOOT:
|
||||
DoCastVictim(SPELL_SHOOT);
|
||||
events.ScheduleEvent(EVENT_SHOOT, 500);
|
||||
break;
|
||||
case EVENT_STUN_BOMB:
|
||||
DoCastVictim(SPELL_STUNBOMB);
|
||||
events.ScheduleEvent(EVENT_STUN_BOMB, 14000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_quatermasterzigrisAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_quatermasterzigris()
|
||||
{
|
||||
new quartermaster_zigris();
|
||||
}
|
||||
@@ -1,448 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Player.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_WHIRLWIND = 13736, // sniffed
|
||||
SPELL_CLEAVE = 15284,
|
||||
SPELL_MORTAL_STRIKE = 16856,
|
||||
SPELL_FRENZY = 8269,
|
||||
SPELL_KNOCKDOWN = 13360 // On spawn during Gyth fight
|
||||
};
|
||||
|
||||
enum Says
|
||||
{
|
||||
// Rend Blackhand
|
||||
SAY_BLACKHAND_1 = 0,
|
||||
SAY_BLACKHAND_2 = 1,
|
||||
EMOTE_BLACKHAND_DISMOUNT = 2,
|
||||
// Victor Nefarius
|
||||
SAY_NEFARIUS_0 = 0,
|
||||
SAY_NEFARIUS_1 = 1,
|
||||
SAY_NEFARIUS_2 = 2,
|
||||
SAY_NEFARIUS_3 = 3,
|
||||
SAY_NEFARIUS_4 = 4,
|
||||
SAY_NEFARIUS_5 = 5,
|
||||
SAY_NEFARIUS_6 = 6,
|
||||
SAY_NEFARIUS_7 = 7,
|
||||
SAY_NEFARIUS_8 = 8,
|
||||
SAY_NEFARIUS_9 = 9,
|
||||
};
|
||||
|
||||
enum Adds
|
||||
{
|
||||
NPC_CHROMATIC_WHELP = 10442,
|
||||
NPC_CHROMATIC_DRAGONSPAWN = 10447,
|
||||
NPC_BLACKHAND_DRAGON_HANDLER = 10742
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
NEFARIUS_PATH_1 = 1379670,
|
||||
NEFARIUS_PATH_2 = 1379671,
|
||||
NEFARIUS_PATH_3 = 1379672,
|
||||
REND_PATH_1 = 1379680,
|
||||
REND_PATH_2 = 1379681,
|
||||
};
|
||||
|
||||
/*
|
||||
struct Wave
|
||||
{
|
||||
uint32 entry;
|
||||
float x_pos;
|
||||
float y_pos;
|
||||
float z_pos;
|
||||
float o_pos;
|
||||
};
|
||||
|
||||
static Wave Wave2[]= // 22 sec
|
||||
{
|
||||
{ 10447, 209.8637f, -428.2729f, 110.9877f, 0.6632251f },
|
||||
{ 10442, 209.3122f, -430.8724f, 110.9814f, 2.9147f },
|
||||
{ 10442, 211.3309f, -425.9111f, 111.0006f, 1.727876f }
|
||||
};
|
||||
|
||||
static Wave Wave3[]= // 60 sec
|
||||
{
|
||||
{ 10742, 208.6493f, -424.5787f, 110.9872f, 5.8294f },
|
||||
{ 10447, 203.9482f, -428.9446f, 110.982f, 4.677482f },
|
||||
{ 10442, 203.3441f, -426.8668f, 110.9772f, 4.712389f },
|
||||
{ 10442, 206.3079f, -424.7509f, 110.9943f, 4.08407f }
|
||||
};
|
||||
|
||||
static Wave Wave4[]= // 49 sec
|
||||
{
|
||||
{ 10742, 212.3541f, -412.6826f, 111.0352f, 5.88176f },
|
||||
{ 10447, 212.5754f, -410.2841f, 111.0296f, 2.740167f },
|
||||
{ 10442, 212.3449f, -414.8659f, 111.0348f, 2.356194f },
|
||||
{ 10442, 210.6568f, -412.1552f, 111.0124f, 0.9773844f }
|
||||
};
|
||||
|
||||
static Wave Wave5[]= // 60 sec
|
||||
{
|
||||
{ 10742, 210.2188f, -410.6686f, 111.0211f, 5.8294f },
|
||||
{ 10447, 209.4078f, -414.13f, 111.0264f, 4.677482f },
|
||||
{ 10442, 208.0858f, -409.3145f, 111.0118f, 4.642576f },
|
||||
{ 10442, 207.9811f, -413.0728f, 111.0098f, 5.288348f },
|
||||
{ 10442, 208.0854f, -412.1505f, 111.0057f, 4.08407f }
|
||||
};
|
||||
|
||||
static Wave Wave6[]= // 27 sec
|
||||
{
|
||||
{ 10742, 213.9138f, -426.512f, 111.0013f, 3.316126f },
|
||||
{ 10447, 213.7121f, -429.8102f, 110.9888f, 1.413717f },
|
||||
{ 10447, 213.7157f, -424.4268f, 111.009f, 3.001966f },
|
||||
{ 10442, 210.8935f, -423.913f, 111.0125f, 5.969026f },
|
||||
{ 10442, 212.2642f, -430.7648f, 110.9807f, 5.934119f }
|
||||
};
|
||||
*/
|
||||
|
||||
Position const GythLoc = { 211.762f, -397.5885f, 111.1817f, 4.747295f };
|
||||
Position const Teleport1Loc = { 194.2993f, -474.0814f, 121.4505f, -0.01225555f };
|
||||
Position const Teleport2Loc = { 216.485f, -434.93f, 110.888f, -0.01225555f };
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_START_1 = 1,
|
||||
EVENT_START_2 = 2,
|
||||
EVENT_START_3 = 3,
|
||||
EVENT_START_4 = 4,
|
||||
EVENT_TURN_TO_REND = 5,
|
||||
EVENT_TURN_TO_PLAYER = 6,
|
||||
EVENT_TURN_TO_FACING_1 = 7,
|
||||
EVENT_TURN_TO_FACING_2 = 8,
|
||||
EVENT_TURN_TO_FACING_3 = 9,
|
||||
EVENT_WAVE_1 = 10,
|
||||
EVENT_WAVE_2 = 11,
|
||||
EVENT_WAVE_3 = 12,
|
||||
EVENT_WAVE_4 = 13,
|
||||
EVENT_WAVE_5 = 14,
|
||||
EVENT_WAVE_6 = 15,
|
||||
EVENT_WAVES_TEXT_1 = 16,
|
||||
EVENT_WAVES_TEXT_2 = 17,
|
||||
EVENT_WAVES_TEXT_3 = 18,
|
||||
EVENT_WAVES_TEXT_4 = 19,
|
||||
EVENT_WAVES_TEXT_5 = 20,
|
||||
EVENT_WAVES_COMPLETE_TEXT_1 = 21,
|
||||
EVENT_WAVES_COMPLETE_TEXT_2 = 22,
|
||||
EVENT_WAVES_COMPLETE_TEXT_3 = 23,
|
||||
EVENT_WAVES_EMOTE_1 = 24,
|
||||
EVENT_WAVES_EMOTE_2 = 25,
|
||||
EVENT_PATH_REND = 26,
|
||||
EVENT_PATH_NEFARIUS = 27,
|
||||
EVENT_TELEPORT_1 = 28,
|
||||
EVENT_TELEPORT_2 = 29,
|
||||
EVENT_WHIRLWIND = 30,
|
||||
EVENT_CLEAVE = 31,
|
||||
EVENT_MORTAL_STRIKE = 32,
|
||||
};
|
||||
|
||||
class boss_rend_blackhand : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_rend_blackhand() : CreatureScript("boss_rend_blackhand") { }
|
||||
|
||||
struct boss_rend_blackhandAI : public BossAI
|
||||
{
|
||||
boss_rend_blackhandAI(Creature* creature) : BossAI(creature, DATA_WARCHIEF_REND_BLACKHAND) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
gythEvent = false;
|
||||
victorGUID = 0;
|
||||
portcullisGUID = 0;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_WHIRLWIND, urand(13000, 15000));
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(15000, 17000));
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(17000, 19000));
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 75.0f, true))
|
||||
victor->AI()->SetData(1, 2);
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data)
|
||||
{
|
||||
if (type == AREATRIGGER && data == AREATRIGGER_BLACKROCK_STADIUM)
|
||||
{
|
||||
if (!gythEvent)
|
||||
{
|
||||
gythEvent = true;
|
||||
|
||||
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f, true))
|
||||
victorGUID = victor->GetGUID();
|
||||
|
||||
if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 50.0f))
|
||||
portcullisGUID = portcullis->GetGUID();
|
||||
|
||||
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0);
|
||||
events.ScheduleEvent(EVENT_START_1, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id)
|
||||
{
|
||||
if (type == WAYPOINT_MOTION_TYPE)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 5:
|
||||
events.ScheduleEvent(EVENT_TELEPORT_1, 2000);
|
||||
break;
|
||||
case 11:
|
||||
if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 10.0f, true))
|
||||
gyth->AI()->SetData(1, 1);
|
||||
me->DespawnOrUnsummon(1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (gythEvent)
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_START_1:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_0);
|
||||
events.ScheduleEvent(EVENT_START_2, 4000);
|
||||
break;
|
||||
case EVENT_START_2:
|
||||
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0);
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
|
||||
events.ScheduleEvent(EVENT_START_3, 4000);
|
||||
break;
|
||||
case EVENT_START_3:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_1);
|
||||
events.ScheduleEvent(EVENT_WAVE_1, 2000);
|
||||
events.ScheduleEvent(EVENT_TURN_TO_REND, 4000);
|
||||
events.ScheduleEvent(EVENT_WAVES_TEXT_1, 20000);
|
||||
break;
|
||||
case EVENT_TURN_TO_REND:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
{
|
||||
victor->SetFacingToObject(me);
|
||||
victor->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
|
||||
}
|
||||
break;
|
||||
case EVENT_TURN_TO_PLAYER:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
if (Unit* player = victor->SelectNearestPlayer(60.0f))
|
||||
victor->SetFacingToObject(player);
|
||||
break;
|
||||
case EVENT_TURN_TO_FACING_1:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->SetFacingTo(1.518436f);
|
||||
break;
|
||||
case EVENT_TURN_TO_FACING_2:
|
||||
me->SetFacingTo(1.658063f);
|
||||
break;
|
||||
case EVENT_TURN_TO_FACING_3:
|
||||
me->SetFacingTo(1.500983f);
|
||||
break;
|
||||
case EVENT_WAVES_EMOTE_1:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION);
|
||||
break;
|
||||
case EVENT_WAVES_EMOTE_2:
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
|
||||
break;
|
||||
case EVENT_WAVES_TEXT_1:
|
||||
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0);
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_2);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
|
||||
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4000);
|
||||
events.ScheduleEvent(EVENT_WAVES_EMOTE_1, 5000);
|
||||
events.ScheduleEvent(EVENT_WAVE_2, 2000);
|
||||
events.ScheduleEvent(EVENT_WAVES_TEXT_2, 20000);
|
||||
break;
|
||||
case EVENT_WAVES_TEXT_2:
|
||||
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0);
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_3);
|
||||
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4000);
|
||||
events.ScheduleEvent(EVENT_WAVE_3, 2000);
|
||||
events.ScheduleEvent(EVENT_WAVES_TEXT_3, 20000);
|
||||
break;
|
||||
case EVENT_WAVES_TEXT_3:
|
||||
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0);
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_4);
|
||||
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4000);
|
||||
events.ScheduleEvent(EVENT_WAVE_4, 2000);
|
||||
events.ScheduleEvent(EVENT_WAVES_TEXT_4, 20000);
|
||||
break;
|
||||
case EVENT_WAVES_TEXT_4:
|
||||
Talk(SAY_BLACKHAND_1);
|
||||
events.ScheduleEvent(EVENT_WAVES_EMOTE_2, 4000);
|
||||
events.ScheduleEvent(EVENT_TURN_TO_FACING_3, 8000);
|
||||
events.ScheduleEvent(EVENT_WAVE_5, 2000);
|
||||
events.ScheduleEvent(EVENT_WAVES_TEXT_5, 20000);
|
||||
break;
|
||||
case EVENT_WAVES_TEXT_5:
|
||||
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0);
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_5);
|
||||
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4000);
|
||||
events.ScheduleEvent(EVENT_WAVE_6, 2000);
|
||||
events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_1, 20000);
|
||||
break;
|
||||
case EVENT_WAVES_COMPLETE_TEXT_1:
|
||||
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0);
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_6);
|
||||
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4000);
|
||||
events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_2, 13000);
|
||||
break;
|
||||
case EVENT_WAVES_COMPLETE_TEXT_2:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_7);
|
||||
Talk(SAY_BLACKHAND_2);
|
||||
events.ScheduleEvent(EVENT_PATH_REND, 1000);
|
||||
events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_3, 4000);
|
||||
break;
|
||||
case EVENT_WAVES_COMPLETE_TEXT_3:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->AI()->Talk(SAY_NEFARIUS_8);
|
||||
events.ScheduleEvent(EVENT_PATH_NEFARIUS, 1000);
|
||||
events.ScheduleEvent(EVENT_PATH_REND, 1000);
|
||||
break;
|
||||
case EVENT_PATH_NEFARIUS:
|
||||
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
|
||||
victor->GetMotionMaster()->MovePath(NEFARIUS_PATH_1, true);
|
||||
break;
|
||||
case EVENT_PATH_REND:
|
||||
me->GetMotionMaster()->MovePath(REND_PATH_1, false);
|
||||
break;
|
||||
case EVENT_TELEPORT_1:
|
||||
me->NearTeleportTo(194.2993f, -474.0814f, 121.4505f, -0.01225555f);
|
||||
events.ScheduleEvent(EVENT_TELEPORT_2, 50000);
|
||||
break;
|
||||
case EVENT_TELEPORT_2:
|
||||
me->NearTeleportTo(216.485f, -434.93f, 110.888f, -0.01225555f);
|
||||
me->SummonCreature(NPC_GYTH, 211.762f, -397.5885f, 111.1817f, 4.747295f);
|
||||
break;
|
||||
case EVENT_WAVE_1:
|
||||
if (GameObject* portcullis = me->GetMap()->GetGameObject(portcullisGUID))
|
||||
portcullis->UseDoorOrButton();
|
||||
// move wave
|
||||
break;
|
||||
case EVENT_WAVE_2:
|
||||
// spawn wave
|
||||
if (GameObject* portcullis = me->GetMap()->GetGameObject(portcullisGUID))
|
||||
portcullis->UseDoorOrButton();
|
||||
// move wave
|
||||
break;
|
||||
case EVENT_WAVE_3:
|
||||
// spawn wave
|
||||
if (GameObject* portcullis = me->GetMap()->GetGameObject(portcullisGUID))
|
||||
portcullis->UseDoorOrButton();
|
||||
// move wave
|
||||
break;
|
||||
case EVENT_WAVE_4:
|
||||
// spawn wave
|
||||
if (GameObject* portcullis = me->GetMap()->GetGameObject(portcullisGUID))
|
||||
portcullis->UseDoorOrButton();
|
||||
// move wave
|
||||
break;
|
||||
case EVENT_WAVE_5:
|
||||
// spawn wave
|
||||
if (GameObject* portcullis = me->GetMap()->GetGameObject(portcullisGUID))
|
||||
portcullis->UseDoorOrButton();
|
||||
// move wave
|
||||
break;
|
||||
case EVENT_WAVE_6:
|
||||
// spawn wave
|
||||
if (GameObject* portcullis = me->GetMap()->GetGameObject(portcullisGUID))
|
||||
portcullis->UseDoorOrButton();
|
||||
// move wave
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_WHIRLWIND:
|
||||
DoCast(SPELL_WHIRLWIND);
|
||||
events.ScheduleEvent(EVENT_WHIRLWIND, urand(13000, 18000));
|
||||
break;
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(10000, 14000));
|
||||
break;
|
||||
case EVENT_MORTAL_STRIKE:
|
||||
DoCastVictim(SPELL_MORTAL_STRIKE);
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(14000, 16000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool gythEvent;
|
||||
uint64 victorGUID;
|
||||
uint64 portcullisGUID;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_rend_blackhandAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_rend_blackhand()
|
||||
{
|
||||
new boss_rend_blackhand();
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CURSEOFBLOOD = 24673,
|
||||
SPELL_HEX = 16708,
|
||||
SPELL_CLEAVE = 20691,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_CURSE_OF_BLOOD = 1,
|
||||
EVENT_HEX = 2,
|
||||
EVENT_CLEAVE = 3,
|
||||
};
|
||||
|
||||
class boss_shadow_hunter_voshgajin : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_shadow_hunter_voshgajin() : CreatureScript("boss_shadow_hunter_voshgajin") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_shadowvoshAI(creature);
|
||||
}
|
||||
|
||||
struct boss_shadowvoshAI : public BossAI
|
||||
{
|
||||
boss_shadowvoshAI(Creature* creature) : BossAI(creature, DATA_SHADOW_HUNTER_VOSHGAJIN) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
//DoCast(me, SPELL_ICEARMOR, true);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 2 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_HEX, 8 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 14 * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CURSE_OF_BLOOD:
|
||||
DoCastVictim(SPELL_CURSEOFBLOOD);
|
||||
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 45 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_HEX:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_HEX);
|
||||
events.ScheduleEvent(EVENT_HEX, 15 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 7 * IN_MILLISECONDS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
void AddSC_boss_shadowvosh()
|
||||
{
|
||||
new boss_shadow_hunter_voshgajin();
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FLAMEBREAK = 16785,
|
||||
SPELL_IMMOLATE = 20294,
|
||||
SPELL_TERRIFYINGROAR = 14100,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_FLAME_BREAK = 1,
|
||||
EVENT_IMMOLATE = 2,
|
||||
EVENT_TERRIFYING_ROAR = 3,
|
||||
};
|
||||
|
||||
class boss_the_beast : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_the_beast() : CreatureScript("boss_the_beast") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_thebeastAI(creature);
|
||||
}
|
||||
|
||||
struct boss_thebeastAI : public BossAI
|
||||
{
|
||||
boss_thebeastAI(Creature* creature) : BossAI(creature, DATA_THE_BEAST) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_FLAME_BREAK, 12 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_IMMOLATE, 3 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 23 * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_FLAME_BREAK:
|
||||
DoCastVictim(SPELL_FLAMEBREAK);
|
||||
events.ScheduleEvent(EVENT_FLAME_BREAK, 10 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_IMMOLATE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_IMMOLATE);
|
||||
events.ScheduleEvent(EVENT_IMMOLATE, 8 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_TERRIFYING_ROAR:
|
||||
DoCastVictim(SPELL_TERRIFYINGROAR);
|
||||
events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 20 * IN_MILLISECONDS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_thebeast()
|
||||
{
|
||||
new boss_the_beast();
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_REND = 16509,
|
||||
SPELL_STRIKE = 15580,
|
||||
SPELL_INTIMIDATING_ROAR = 16508,
|
||||
SPELL_UROK_SPAWN = 16473,
|
||||
};
|
||||
|
||||
enum Says
|
||||
{
|
||||
SAY_SUMMON = 0,
|
||||
SAY_AGGRO = 1,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_REND = 1,
|
||||
EVENT_STRIKE = 2,
|
||||
EVENT_INTIMIDATING_ROAR = 3
|
||||
};
|
||||
|
||||
class boss_urok_doomhowl : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_urok_doomhowl() : CreatureScript("boss_urok_doomhowl") { }
|
||||
|
||||
struct boss_urok_doomhowlAI : public BossAI
|
||||
{
|
||||
boss_urok_doomhowlAI(Creature* creature) : BossAI(creature, DATA_UROK_DOOMHOWL) {}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void InitializeAI()
|
||||
{
|
||||
me->CastSpell(me, SPELL_UROK_SPAWN, true);
|
||||
BossAI::InitializeAI();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(SPELL_REND, urand(17000,20000));
|
||||
events.ScheduleEvent(SPELL_STRIKE, urand(10000,12000));
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case SPELL_REND:
|
||||
DoCastVictim(SPELL_REND);
|
||||
events.ScheduleEvent(SPELL_REND, urand(8000,10000));
|
||||
break;
|
||||
case SPELL_STRIKE:
|
||||
DoCastVictim(SPELL_STRIKE);
|
||||
events.ScheduleEvent(SPELL_STRIKE, urand(8000,10000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_urok_doomhowlAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_urok_doomhowl()
|
||||
{
|
||||
new boss_urok_doomhowl();
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SNAPKICK = 15618,
|
||||
SPELL_CLEAVE = 15284,
|
||||
SPELL_UPPERCUT = 10966,
|
||||
SPELL_MORTALSTRIKE = 16856,
|
||||
SPELL_PUMMEL = 15615,
|
||||
SPELL_THROWAXE = 16075
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SNAP_KICK = 1,
|
||||
EVENT_CLEAVE = 2,
|
||||
EVENT_UPPERCUT = 3,
|
||||
EVENT_MORTAL_STRIKE = 4,
|
||||
EVENT_PUMMEL = 5,
|
||||
EVENT_THROW_AXE = 6
|
||||
};
|
||||
|
||||
class boss_warmaster_voone : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_warmaster_voone() : CreatureScript("boss_warmaster_voone") { }
|
||||
|
||||
struct boss_warmastervooneAI : public BossAI
|
||||
{
|
||||
boss_warmastervooneAI(Creature* creature) : BossAI(creature, DATA_WARMASTER_VOONE) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_SNAP_KICK, 8 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 14 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_UPPERCUT, 20 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 12 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_PUMMEL, 32 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_THROW_AXE, 1 * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SNAP_KICK:
|
||||
DoCastVictim(SPELL_SNAPKICK);
|
||||
events.ScheduleEvent(EVENT_SNAP_KICK, 6 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 12 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_UPPERCUT:
|
||||
DoCastVictim(SPELL_UPPERCUT);
|
||||
events.ScheduleEvent(EVENT_UPPERCUT, 14 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_MORTAL_STRIKE:
|
||||
DoCastVictim(SPELL_MORTALSTRIKE);
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 10 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_PUMMEL:
|
||||
DoCastVictim(SPELL_PUMMEL);
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 16 * IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_THROW_AXE:
|
||||
DoCastVictim(SPELL_THROWAXE);
|
||||
events.ScheduleEvent(EVENT_THROW_AXE, 8 * IN_MILLISECONDS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_warmastervooneAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_warmastervoone()
|
||||
{
|
||||
new boss_warmaster_voone();
|
||||
}
|
||||
@@ -1,646 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackrock_spire.h"
|
||||
|
||||
//uint32 const DragonspireRunes[7] = { GO_HALL_RUNE_1, GO_HALL_RUNE_2, GO_HALL_RUNE_3, GO_HALL_RUNE_4, GO_HALL_RUNE_5, GO_HALL_RUNE_6, GO_HALL_RUNE_7 };
|
||||
|
||||
uint32 const DragonspireMobs[3] = { NPC_BLACKHAND_DREADWEAVER, NPC_BLACKHAND_SUMMONER, NPC_BLACKHAND_VETERAN };
|
||||
|
||||
enum EventIds
|
||||
{
|
||||
EVENT_DARGONSPIRE_ROOM_STORE = 1,
|
||||
EVENT_DARGONSPIRE_ROOM_CHECK = 2,
|
||||
EVENT_UROK_DOOMHOWL_SPAWNS_1 = 3,
|
||||
EVENT_UROK_DOOMHOWL_SPAWNS_2 = 4,
|
||||
EVENT_UROK_DOOMHOWL_SPAWNS_3 = 5,
|
||||
EVENT_UROK_DOOMHOWL_SPAWNS_4 = 6,
|
||||
EVENT_UROK_DOOMHOWL_SPAWNS_5 = 7,
|
||||
EVENT_UROK_DOOMHOWL_SPAWN_IN = 8
|
||||
};
|
||||
|
||||
class instance_blackrock_spire : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
instance_blackrock_spire() : InstanceMapScript(BRSScriptName, 229) { }
|
||||
|
||||
struct instance_blackrock_spireMapScript : public InstanceScript
|
||||
{
|
||||
instance_blackrock_spireMapScript(InstanceMap* map) : InstanceScript(map)
|
||||
{
|
||||
SetBossNumber(EncounterCount);
|
||||
HighlordOmokk = 0;
|
||||
ShadowHunterVoshgajin = 0;
|
||||
WarMasterVoone = 0;
|
||||
MotherSmolderweb = 0;
|
||||
UrokDoomhowl = 0;
|
||||
QuartermasterZigris = 0;
|
||||
GizrultheSlavener = 0;
|
||||
Halycon = 0;
|
||||
OverlordWyrmthalak = 0;
|
||||
PyroguardEmberseer = 0;
|
||||
WarchiefRendBlackhand = 0;
|
||||
Gyth = 0;
|
||||
LordVictorNefarius = 0;
|
||||
TheBeast = 0;
|
||||
GeneralDrakkisath = 0;
|
||||
go_emberseerin = 0;
|
||||
go_doors = 0;
|
||||
go_emberseerout = 0;
|
||||
go_blackrockaltar = 0;
|
||||
go_portcullis_active = 0;
|
||||
go_portcullis_tobossrooms = 0;
|
||||
go_urok_pile = 0;
|
||||
memset(go_roomrunes, 0, sizeof(go_roomrunes));
|
||||
memset(go_emberseerrunes, 0, sizeof(go_emberseerrunes));
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature)
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_HIGHLORD_OMOKK:
|
||||
HighlordOmokk = creature->GetGUID();
|
||||
break;
|
||||
case NPC_SHADOW_HUNTER_VOSHGAJIN:
|
||||
ShadowHunterVoshgajin = creature->GetGUID();
|
||||
break;
|
||||
case NPC_WARMASTER_VOONE:
|
||||
WarMasterVoone = creature->GetGUID();
|
||||
break;
|
||||
case NPC_MOTHER_SMOLDERWEB:
|
||||
MotherSmolderweb = creature->GetGUID();
|
||||
break;
|
||||
case NPC_UROK_DOOMHOWL:
|
||||
UrokDoomhowl = creature->GetGUID();
|
||||
break;
|
||||
case NPC_QUARTERMASTER_ZIGRIS:
|
||||
QuartermasterZigris = creature->GetGUID();
|
||||
break;
|
||||
case NPC_GIZRUL_THE_SLAVENER:
|
||||
GizrultheSlavener = creature->GetGUID();
|
||||
break;
|
||||
case NPC_HALYCON:
|
||||
Halycon = creature->GetGUID();
|
||||
break;
|
||||
case NPC_OVERLORD_WYRMTHALAK:
|
||||
OverlordWyrmthalak = creature->GetGUID();
|
||||
break;
|
||||
case NPC_PYROGAURD_EMBERSEER:
|
||||
PyroguardEmberseer = creature->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
creature->DisappearAndDie();
|
||||
break;
|
||||
case NPC_WARCHIEF_REND_BLACKHAND:
|
||||
WarchiefRendBlackhand = creature->GetGUID();
|
||||
if (GetBossState(DATA_GYTH) == DONE)
|
||||
creature->DisappearAndDie();
|
||||
break;
|
||||
case NPC_GYTH:
|
||||
Gyth = creature->GetGUID();
|
||||
break;
|
||||
case NPC_THE_BEAST:
|
||||
TheBeast = creature->GetGUID();
|
||||
break;
|
||||
case NPC_GENERAL_DRAKKISATH:
|
||||
GeneralDrakkisath = creature->GetGUID();
|
||||
break;
|
||||
case NPC_LORD_VICTOR_NEFARIUS:
|
||||
LordVictorNefarius = creature->GetGUID();
|
||||
if (GetBossState(DATA_GYTH) == DONE)
|
||||
creature->DisappearAndDie();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go)
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_WHELP_SPAWNER:
|
||||
go->CastSpell(NULL, SPELL_SUMMON_ROOKERY_WHELP);
|
||||
break;
|
||||
case GO_EMBERSEER_IN:
|
||||
go_emberseerin = go->GetGUID();
|
||||
if (GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE)
|
||||
HandleGameObject(0, true, go);
|
||||
break;
|
||||
case GO_DOORS:
|
||||
go_doors = go->GetGUID();
|
||||
if (GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE)
|
||||
HandleGameObject(0, true, go);
|
||||
break;
|
||||
case GO_EMBERSEER_OUT:
|
||||
go_emberseerout = go->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
HandleGameObject(0, true, go);
|
||||
break;
|
||||
case GO_HALL_RUNE_1:
|
||||
go_roomrunes[0] = go->GetGUID();
|
||||
if (GetBossState(DATA_HALL_RUNE_1) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_HALL_RUNE_2:
|
||||
go_roomrunes[1] = go->GetGUID();
|
||||
if (GetBossState(DATA_HALL_RUNE_2) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_HALL_RUNE_3:
|
||||
go_roomrunes[2] = go->GetGUID();
|
||||
if (GetBossState(DATA_HALL_RUNE_3) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_HALL_RUNE_4:
|
||||
go_roomrunes[3] = go->GetGUID();
|
||||
if (GetBossState(DATA_HALL_RUNE_4) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_HALL_RUNE_5:
|
||||
go_roomrunes[4] = go->GetGUID();
|
||||
if (GetBossState(DATA_HALL_RUNE_5) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_HALL_RUNE_6:
|
||||
go_roomrunes[5] = go->GetGUID();
|
||||
if (GetBossState(DATA_HALL_RUNE_6) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_HALL_RUNE_7:
|
||||
go_roomrunes[6] = go->GetGUID();
|
||||
if (GetBossState(DATA_HALL_RUNE_7) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_EMBERSEER_RUNE_1:
|
||||
go_emberseerrunes[0] = go->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_EMBERSEER_RUNE_2:
|
||||
go_emberseerrunes[1] = go->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_EMBERSEER_RUNE_3:
|
||||
go_emberseerrunes[2] = go->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_EMBERSEER_RUNE_4:
|
||||
go_emberseerrunes[3] = go->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_EMBERSEER_RUNE_5:
|
||||
go_emberseerrunes[4] = go->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_EMBERSEER_RUNE_6:
|
||||
go_emberseerrunes[5] = go->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_EMBERSEER_RUNE_7:
|
||||
go_emberseerrunes[6] = go->GetGUID();
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE)
|
||||
HandleGameObject(0, false, go);
|
||||
break;
|
||||
case GO_PORTCULLIS_ACTIVE:
|
||||
go_portcullis_active = go->GetGUID();
|
||||
if (GetBossState(DATA_GYTH) == DONE)
|
||||
HandleGameObject(0, true, go);
|
||||
break;
|
||||
case GO_PORTCULLIS_TOBOSSROOMS:
|
||||
go_portcullis_tobossrooms = go->GetGUID();
|
||||
if (GetBossState(DATA_GYTH) == DONE)
|
||||
HandleGameObject(0, true, go);
|
||||
break;
|
||||
case GO_UROK_PILE:
|
||||
go_urok_pile = go->GetGUID();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetBossState(uint32 type, EncounterState state)
|
||||
{
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DATA_HIGHLORD_OMOKK:
|
||||
case DATA_SHADOW_HUNTER_VOSHGAJIN:
|
||||
case DATA_WARMASTER_VOONE:
|
||||
case DATA_MOTHER_SMOLDERWEB:
|
||||
case DATA_UROK_DOOMHOWL:
|
||||
case DATA_QUARTERMASTER_ZIGRIS:
|
||||
case DATA_GIZRUL_THE_SLAVENER:
|
||||
case DATA_HALYCON:
|
||||
case DATA_OVERLORD_WYRMTHALAK:
|
||||
case DATA_PYROGAURD_EMBERSEER:
|
||||
case DATA_WARCHIEF_REND_BLACKHAND:
|
||||
case DATA_GYTH:
|
||||
case DATA_THE_BEAST:
|
||||
case DATA_GENERAL_DRAKKISATH:
|
||||
case DATA_DRAGONSPIRE_ROOM:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProcessEvent(WorldObject* /*obj*/, uint32 eventId)
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_PYROGUARD_EMBERSEER:
|
||||
if (GetBossState(DATA_PYROGAURD_EMBERSEER) == NOT_STARTED)
|
||||
{
|
||||
if (Creature* Emberseer = instance->GetCreature(PyroguardEmberseer))
|
||||
Emberseer->AI()->SetData(1, 1);
|
||||
}
|
||||
break;
|
||||
case EVENT_UROK_DOOMHOWL:
|
||||
if (GetBossState(DATA_UROK_DOOMHOWL) == NOT_STARTED)
|
||||
{
|
||||
if (GameObject* pile = instance->GetGameObject(go_urok_pile))
|
||||
pile->SetLootState(GO_JUST_DEACTIVATED);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AREATRIGGER:
|
||||
if (data == AREATRIGGER_DRAGONSPIRE_HALL)
|
||||
{
|
||||
if (GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE)
|
||||
Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_STORE, 1000);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64 GetData64(uint32 type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DATA_HIGHLORD_OMOKK:
|
||||
return HighlordOmokk;
|
||||
case DATA_SHADOW_HUNTER_VOSHGAJIN:
|
||||
return ShadowHunterVoshgajin;
|
||||
case DATA_WARMASTER_VOONE:
|
||||
return WarMasterVoone;
|
||||
case DATA_MOTHER_SMOLDERWEB:
|
||||
return MotherSmolderweb;
|
||||
case DATA_UROK_DOOMHOWL:
|
||||
return UrokDoomhowl;
|
||||
case DATA_QUARTERMASTER_ZIGRIS:
|
||||
return QuartermasterZigris;
|
||||
case DATA_GIZRUL_THE_SLAVENER:
|
||||
return GizrultheSlavener;
|
||||
case DATA_HALYCON:
|
||||
return Halycon;
|
||||
case DATA_OVERLORD_WYRMTHALAK:
|
||||
return OverlordWyrmthalak;
|
||||
case DATA_PYROGAURD_EMBERSEER:
|
||||
return PyroguardEmberseer;
|
||||
case DATA_WARCHIEF_REND_BLACKHAND:
|
||||
return WarchiefRendBlackhand;
|
||||
case DATA_GYTH:
|
||||
return Gyth;
|
||||
case DATA_THE_BEAST:
|
||||
return TheBeast;
|
||||
case DATA_GENERAL_DRAKKISATH:
|
||||
return GeneralDrakkisath;
|
||||
case GO_EMBERSEER_IN:
|
||||
return go_emberseerin;
|
||||
case GO_DOORS:
|
||||
return go_doors;
|
||||
case GO_EMBERSEER_OUT:
|
||||
return go_emberseerout;
|
||||
case GO_HALL_RUNE_1:
|
||||
return go_roomrunes[0];
|
||||
case GO_HALL_RUNE_2:
|
||||
return go_roomrunes[1];
|
||||
case GO_HALL_RUNE_3:
|
||||
return go_roomrunes[2];
|
||||
case GO_HALL_RUNE_4:
|
||||
return go_roomrunes[3];
|
||||
case GO_HALL_RUNE_5:
|
||||
return go_roomrunes[4];
|
||||
case GO_HALL_RUNE_6:
|
||||
return go_roomrunes[5];
|
||||
case GO_HALL_RUNE_7:
|
||||
return go_roomrunes[6];
|
||||
case GO_EMBERSEER_RUNE_1:
|
||||
return go_emberseerrunes[0];
|
||||
case GO_EMBERSEER_RUNE_2:
|
||||
return go_emberseerrunes[1];
|
||||
case GO_EMBERSEER_RUNE_3:
|
||||
return go_emberseerrunes[2];
|
||||
case GO_EMBERSEER_RUNE_4:
|
||||
return go_emberseerrunes[3];
|
||||
case GO_EMBERSEER_RUNE_5:
|
||||
return go_emberseerrunes[4];
|
||||
case GO_EMBERSEER_RUNE_6:
|
||||
return go_emberseerrunes[5];
|
||||
case GO_EMBERSEER_RUNE_7:
|
||||
return go_emberseerrunes[6];
|
||||
case GO_PORTCULLIS_ACTIVE:
|
||||
return go_portcullis_active;
|
||||
case GO_PORTCULLIS_TOBOSSROOMS:
|
||||
return go_portcullis_tobossrooms;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Update(uint32 diff)
|
||||
{
|
||||
Events.Update(diff);
|
||||
|
||||
while (uint32 eventId = Events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_DARGONSPIRE_ROOM_STORE:
|
||||
Dragonspireroomstore();
|
||||
Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_CHECK, 3000);
|
||||
break;
|
||||
case EVENT_DARGONSPIRE_ROOM_CHECK:
|
||||
Dragonspireroomcheck();
|
||||
if ((GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE))
|
||||
Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_CHECK, 3000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dragonspireroomstore()
|
||||
{
|
||||
uint8 creatureCount;
|
||||
|
||||
for (uint8 i = 0; i < 7; ++i)
|
||||
{
|
||||
creatureCount = 0;
|
||||
|
||||
if (GameObject* rune = instance->GetGameObject(go_roomrunes[i]))
|
||||
{
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
{
|
||||
std::list<Creature*> creatureList;
|
||||
GetCreatureListWithEntryInGrid(creatureList, rune, DragonspireMobs[j], 15.0f);
|
||||
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
|
||||
{
|
||||
if (Creature* creature = *itr)
|
||||
{
|
||||
runecreaturelist[i][creatureCount] = creature->GetGUID();
|
||||
++creatureCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dragonspireroomcheck()
|
||||
{
|
||||
Creature* mob = NULL;
|
||||
GameObject* rune = NULL;
|
||||
|
||||
for (uint8 i = 0; i < 7; ++i)
|
||||
{
|
||||
bool _mobAlive = false;
|
||||
rune = instance->GetGameObject(go_roomrunes[i]);
|
||||
if (!rune)
|
||||
continue;
|
||||
|
||||
if (rune->GetGoState() == GO_STATE_ACTIVE)
|
||||
{
|
||||
for (uint8 ii = 0; ii < 5; ++ii)
|
||||
{
|
||||
mob = instance->GetCreature(runecreaturelist[i][ii]);
|
||||
if (mob && mob->IsAlive())
|
||||
_mobAlive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_mobAlive && rune->GetGoState() == GO_STATE_ACTIVE)
|
||||
{
|
||||
HandleGameObject(0, false, rune);
|
||||
|
||||
switch (rune->GetEntry())
|
||||
{
|
||||
case GO_HALL_RUNE_1:
|
||||
SetBossState(DATA_HALL_RUNE_1, DONE);
|
||||
break;
|
||||
case GO_HALL_RUNE_2:
|
||||
SetBossState(DATA_HALL_RUNE_2, DONE);
|
||||
break;
|
||||
case GO_HALL_RUNE_3:
|
||||
SetBossState(DATA_HALL_RUNE_3, DONE);
|
||||
break;
|
||||
case GO_HALL_RUNE_4:
|
||||
SetBossState(DATA_HALL_RUNE_4, DONE);
|
||||
break;
|
||||
case GO_HALL_RUNE_5:
|
||||
SetBossState(DATA_HALL_RUNE_5, DONE);
|
||||
break;
|
||||
case GO_HALL_RUNE_6:
|
||||
SetBossState(DATA_HALL_RUNE_6, DONE);
|
||||
break;
|
||||
case GO_HALL_RUNE_7:
|
||||
SetBossState(DATA_HALL_RUNE_7, DONE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GetBossState(DATA_HALL_RUNE_1) == DONE && GetBossState(DATA_HALL_RUNE_2) == DONE && GetBossState(DATA_HALL_RUNE_3) == DONE &&
|
||||
GetBossState(DATA_HALL_RUNE_4) == DONE && GetBossState(DATA_HALL_RUNE_5) == DONE && GetBossState(DATA_HALL_RUNE_6) == DONE &&
|
||||
GetBossState(DATA_HALL_RUNE_7) == DONE)
|
||||
{
|
||||
SetBossState(DATA_DRAGONSPIRE_ROOM, DONE);
|
||||
if (GameObject* door1 = instance->GetGameObject(go_emberseerin))
|
||||
HandleGameObject(0, true, door1);
|
||||
if (GameObject* door2 = instance->GetGameObject(go_doors))
|
||||
HandleGameObject(0, true, door2);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetSaveData()
|
||||
{
|
||||
OUT_SAVE_INST_DATA;
|
||||
|
||||
std::ostringstream saveStream;
|
||||
saveStream << "B S " << GetBossSaveData();
|
||||
|
||||
OUT_SAVE_INST_DATA_COMPLETE;
|
||||
return saveStream.str();
|
||||
}
|
||||
|
||||
void Load(const char* strIn)
|
||||
{
|
||||
if (!strIn)
|
||||
{
|
||||
OUT_LOAD_INST_DATA_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
OUT_LOAD_INST_DATA(strIn);
|
||||
|
||||
char dataHead1, dataHead2;
|
||||
|
||||
std::istringstream loadStream(strIn);
|
||||
loadStream >> dataHead1 >> dataHead2;
|
||||
|
||||
if (dataHead1 == 'B' && dataHead2 == 'S')
|
||||
{
|
||||
for (uint8 i = 0; i < EncounterCount; ++i)
|
||||
{
|
||||
uint32 tmpState;
|
||||
loadStream >> tmpState;
|
||||
if (tmpState == IN_PROGRESS || tmpState > SPECIAL)
|
||||
tmpState = NOT_STARTED;
|
||||
|
||||
SetBossState(i, EncounterState(tmpState));
|
||||
}
|
||||
}
|
||||
else
|
||||
OUT_LOAD_INST_DATA_FAIL;
|
||||
|
||||
OUT_LOAD_INST_DATA_COMPLETE;
|
||||
}
|
||||
|
||||
protected:
|
||||
EventMap Events;
|
||||
uint64 HighlordOmokk;
|
||||
uint64 ShadowHunterVoshgajin;
|
||||
uint64 WarMasterVoone;
|
||||
uint64 MotherSmolderweb;
|
||||
uint64 UrokDoomhowl;
|
||||
uint64 QuartermasterZigris;
|
||||
uint64 GizrultheSlavener;
|
||||
uint64 Halycon;
|
||||
uint64 OverlordWyrmthalak;
|
||||
uint64 PyroguardEmberseer;
|
||||
uint64 WarchiefRendBlackhand;
|
||||
uint64 Gyth;
|
||||
uint64 LordVictorNefarius;
|
||||
uint64 TheBeast;
|
||||
uint64 GeneralDrakkisath;
|
||||
uint64 go_emberseerin;
|
||||
uint64 go_doors;
|
||||
uint64 go_emberseerout;
|
||||
uint64 go_blackrockaltar;
|
||||
uint64 go_roomrunes[7];
|
||||
uint64 go_emberseerrunes[7];
|
||||
uint64 runecreaturelist[7][5];
|
||||
uint64 go_portcullis_active;
|
||||
uint64 go_portcullis_tobossrooms;
|
||||
uint64 go_urok_pile;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const
|
||||
{
|
||||
return new instance_blackrock_spireMapScript(map);
|
||||
}
|
||||
};
|
||||
|
||||
/*#####
|
||||
# at_dragonspire_hall
|
||||
#####*/
|
||||
|
||||
class at_dragonspire_hall : public AreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_dragonspire_hall() : AreaTriggerScript("at_dragonspire_hall") { }
|
||||
|
||||
bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/)
|
||||
{
|
||||
if (player && player->IsAlive())
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
instance->SetData(AREATRIGGER, AREATRIGGER_DRAGONSPIRE_HALL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/*#####
|
||||
# at_blackrock_stadium
|
||||
#####*/
|
||||
|
||||
class at_blackrock_stadium : public AreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_blackrock_stadium() : AreaTriggerScript("at_blackrock_stadium") { }
|
||||
|
||||
bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/)
|
||||
{
|
||||
if (player && player->IsAlive())
|
||||
{
|
||||
InstanceScript* instance = player->GetInstanceScript();
|
||||
if (!instance)
|
||||
return false;
|
||||
|
||||
if (Creature* rend = player->FindNearestCreature(NPC_WARCHIEF_REND_BLACKHAND, 50.0f))
|
||||
{
|
||||
rend->AI()->SetData(AREATRIGGER, AREATRIGGER_BLACKROCK_STADIUM);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_blackrock_spire()
|
||||
{
|
||||
new instance_blackrock_spire();
|
||||
new at_dragonspire_hall();
|
||||
new at_blackrock_stadium();
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DEF_BLACKWING_LAIR_H
|
||||
#define DEF_BLACKWING_LAIR_H
|
||||
|
||||
uint32 const EncounterCount = 8;
|
||||
|
||||
#define BRLScriptName "instance_blackwing_lair"
|
||||
|
||||
enum BWLEncounter
|
||||
{
|
||||
BOSS_RAZORGORE = 0,
|
||||
BOSS_VAELASTRAZ = 1,
|
||||
BOSS_BROODLORD = 2,
|
||||
BOSS_FIREMAW = 3,
|
||||
BOSS_EBONROC = 4,
|
||||
BOSS_FLAMEGOR = 5,
|
||||
BOSS_CHROMAGGUS = 6,
|
||||
BOSS_NEFARIAN = 7
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
{
|
||||
NPC_RAZORGORE = 12435,
|
||||
NPC_BLACKWING_DRAGON = 12422,
|
||||
NPC_BLACKWING_TASKMASTER = 12458,
|
||||
NPC_BLACKWING_LEGIONAIRE = 12416,
|
||||
NPC_BLACKWING_WARLOCK = 12459,
|
||||
NPC_VAELASTRAZ = 13020,
|
||||
NPC_BROODLORD = 12017,
|
||||
NPC_FIRENAW = 11983,
|
||||
NPC_EBONROC = 14601,
|
||||
NPC_FLAMEGOR = 11981,
|
||||
NPC_CHROMAGGUS = 14020,
|
||||
NPC_VICTOR_NEFARIUS = 10162,
|
||||
NPC_NEFARIAN = 11583
|
||||
};
|
||||
|
||||
enum BWLData64
|
||||
{
|
||||
DATA_RAZORGORE_THE_UNTAMED = 1,
|
||||
DATA_VAELASTRAZ_THE_CORRUPT,
|
||||
DATA_BROODLORD_LASHLAYER,
|
||||
DATA_FIRENAW,
|
||||
DATA_EBONROC,
|
||||
DATA_FLAMEGOR,
|
||||
DATA_CHROMAGGUS,
|
||||
DATA_LORD_VICTOR_NEFARIUS,
|
||||
DATA_NEFARIAN
|
||||
};
|
||||
|
||||
enum BWLEvents
|
||||
{
|
||||
EVENT_RAZOR_SPAWN = 1,
|
||||
EVENT_RAZOR_PHASE_TWO = 2,
|
||||
EVENT_RESPAWN_NEFARIUS = 3
|
||||
};
|
||||
|
||||
enum BWLMisc
|
||||
{
|
||||
// Razorgore Egg Event
|
||||
ACTION_PHASE_TWO = 1,
|
||||
DATA_EGG_EVENT
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackwing_lair.h"
|
||||
|
||||
enum Say
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_LEASH = 1
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CLEAVE = 26350,
|
||||
SPELL_BLASTWAVE = 23331,
|
||||
SPELL_MORTALSTRIKE = 24573,
|
||||
SPELL_KNOCKBACK = 25778
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_CLEAVE = 1,
|
||||
EVENT_BLASTWAVE = 2,
|
||||
EVENT_MORTALSTRIKE = 3,
|
||||
EVENT_KNOCKBACK = 4,
|
||||
EVENT_CHECK = 5
|
||||
};
|
||||
|
||||
class boss_broodlord : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_broodlord() : CreatureScript("boss_broodlord") { }
|
||||
|
||||
struct boss_broodlordAI : public BossAI
|
||||
{
|
||||
boss_broodlordAI(Creature* creature) : BossAI(creature, BOSS_BROODLORD) { }
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
if (instance->GetBossState(BOSS_VAELASTRAZ) != DONE)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
|
||||
_EnterCombat();
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 8000);
|
||||
events.ScheduleEvent(EVENT_BLASTWAVE, 12000);
|
||||
events.ScheduleEvent(EVENT_MORTALSTRIKE, 20000);
|
||||
events.ScheduleEvent(EVENT_KNOCKBACK, 30000);
|
||||
events.ScheduleEvent(EVENT_CHECK, 1000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 7000);
|
||||
break;
|
||||
case EVENT_BLASTWAVE:
|
||||
DoCastVictim(SPELL_BLASTWAVE);
|
||||
events.ScheduleEvent(EVENT_BLASTWAVE, urand(8000, 16000));
|
||||
break;
|
||||
case EVENT_MORTALSTRIKE:
|
||||
DoCastVictim(SPELL_MORTALSTRIKE);
|
||||
events.ScheduleEvent(EVENT_MORTALSTRIKE, urand(25000, 35000));
|
||||
break;
|
||||
case EVENT_KNOCKBACK:
|
||||
DoCastVictim(SPELL_KNOCKBACK);
|
||||
if (DoGetThreat(me->GetVictim()))
|
||||
DoModifyThreatPercent(me->GetVictim(), -50);
|
||||
events.ScheduleEvent(EVENT_KNOCKBACK, urand(15000, 30000));
|
||||
break;
|
||||
case EVENT_CHECK:
|
||||
if (me->GetDistance(me->GetHomePosition()) > 150.0f)
|
||||
{
|
||||
Talk(SAY_LEASH);
|
||||
EnterEvadeMode();
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK, 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_broodlordAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_broodlord()
|
||||
{
|
||||
new boss_broodlord();
|
||||
}
|
||||
@@ -1,292 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Player.h"
|
||||
#include "blackwing_lair.h"
|
||||
|
||||
enum Emotes
|
||||
{
|
||||
EMOTE_FRENZY = 0,
|
||||
EMOTE_SHIMMER = 1,
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// These spells are actually called elemental shield
|
||||
// What they do is decrease all damage by 75% then they increase
|
||||
// One school of damage by 1100%
|
||||
SPELL_FIRE_VULNERABILITY = 22277,
|
||||
SPELL_FROST_VULNERABILITY = 22278,
|
||||
SPELL_SHADOW_VULNERABILITY = 22279,
|
||||
SPELL_NATURE_VULNERABILITY = 22280,
|
||||
SPELL_ARCANE_VULNERABILITY = 22281,
|
||||
// Other spells
|
||||
SPELL_INCINERATE = 23308, //Incinerate 23308, 23309
|
||||
SPELL_TIMELAPSE = 23310, //Time lapse 23310, 23311(old threat mod that was removed in 2.01)
|
||||
SPELL_CORROSIVEACID = 23313, //Corrosive Acid 23313, 23314
|
||||
SPELL_IGNITEFLESH = 23315, //Ignite Flesh 23315, 23316
|
||||
SPELL_FROSTBURN = 23187, //Frost burn 23187, 23189
|
||||
// Brood Affliction 23173 - Scripted Spell that cycles through all targets within 100 yards and has a chance to cast one of the afflictions on them
|
||||
// Since Scripted spells arn't coded I'll just write a function that does the same thing
|
||||
SPELL_BROODAF_BLUE = 23153, //Blue affliction 23153
|
||||
SPELL_BROODAF_BLACK = 23154, //Black affliction 23154
|
||||
SPELL_BROODAF_RED = 23155, //Red affliction 23155 (23168 on death)
|
||||
SPELL_BROODAF_BRONZE = 23170, //Bronze Affliction 23170
|
||||
SPELL_BROODAF_GREEN = 23169, //Brood Affliction Green 23169
|
||||
SPELL_CHROMATIC_MUT_1 = 23174, //Spell cast on player if they get all 5 debuffs
|
||||
SPELL_FRENZY = 28371, //The frenzy spell may be wrong
|
||||
SPELL_ENRAGE = 28747
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SHIMMER = 1,
|
||||
EVENT_BREATH_1 = 2,
|
||||
EVENT_BREATH_2 = 3,
|
||||
EVENT_AFFLICTION = 4,
|
||||
EVENT_FRENZY = 5
|
||||
};
|
||||
|
||||
class boss_chromaggus : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_chromaggus() : CreatureScript("boss_chromaggus") { }
|
||||
|
||||
struct boss_chromaggusAI : public BossAI
|
||||
{
|
||||
boss_chromaggusAI(Creature* creature) : BossAI(creature, BOSS_CHROMAGGUS)
|
||||
{
|
||||
// Select the 2 breaths that we are going to use until despawned
|
||||
// 5 possiblities for the first breath, 4 for the second, 20 total possiblites
|
||||
// This way we don't end up casting 2 of the same breath
|
||||
// TL TL would be stupid
|
||||
switch (urand(0, 19))
|
||||
{
|
||||
// B1 - Incin
|
||||
case 0:
|
||||
Breath1_Spell = SPELL_INCINERATE;
|
||||
Breath2_Spell = SPELL_TIMELAPSE;
|
||||
break;
|
||||
case 1:
|
||||
Breath1_Spell = SPELL_INCINERATE;
|
||||
Breath2_Spell = SPELL_CORROSIVEACID;
|
||||
break;
|
||||
case 2:
|
||||
Breath1_Spell = SPELL_INCINERATE;
|
||||
Breath2_Spell = SPELL_IGNITEFLESH;
|
||||
break;
|
||||
case 3:
|
||||
Breath1_Spell = SPELL_INCINERATE;
|
||||
Breath2_Spell = SPELL_FROSTBURN;
|
||||
break;
|
||||
|
||||
// B1 - TL
|
||||
case 4:
|
||||
Breath1_Spell = SPELL_TIMELAPSE;
|
||||
Breath2_Spell = SPELL_INCINERATE;
|
||||
break;
|
||||
case 5:
|
||||
Breath1_Spell = SPELL_TIMELAPSE;
|
||||
Breath2_Spell = SPELL_CORROSIVEACID;
|
||||
break;
|
||||
case 6:
|
||||
Breath1_Spell = SPELL_TIMELAPSE;
|
||||
Breath2_Spell = SPELL_IGNITEFLESH;
|
||||
break;
|
||||
case 7:
|
||||
Breath1_Spell = SPELL_TIMELAPSE;
|
||||
Breath2_Spell = SPELL_FROSTBURN;
|
||||
break;
|
||||
|
||||
//B1 - Acid
|
||||
case 8:
|
||||
Breath1_Spell = SPELL_CORROSIVEACID;
|
||||
Breath2_Spell = SPELL_INCINERATE;
|
||||
break;
|
||||
case 9:
|
||||
Breath1_Spell = SPELL_CORROSIVEACID;
|
||||
Breath2_Spell = SPELL_TIMELAPSE;
|
||||
break;
|
||||
case 10:
|
||||
Breath1_Spell = SPELL_CORROSIVEACID;
|
||||
Breath2_Spell = SPELL_IGNITEFLESH;
|
||||
break;
|
||||
case 11:
|
||||
Breath1_Spell = SPELL_CORROSIVEACID;
|
||||
Breath2_Spell = SPELL_FROSTBURN;
|
||||
break;
|
||||
|
||||
//B1 - Ignite
|
||||
case 12:
|
||||
Breath1_Spell = SPELL_IGNITEFLESH;
|
||||
Breath2_Spell = SPELL_INCINERATE;
|
||||
break;
|
||||
case 13:
|
||||
Breath1_Spell = SPELL_IGNITEFLESH;
|
||||
Breath2_Spell = SPELL_CORROSIVEACID;
|
||||
break;
|
||||
case 14:
|
||||
Breath1_Spell = SPELL_IGNITEFLESH;
|
||||
Breath2_Spell = SPELL_TIMELAPSE;
|
||||
break;
|
||||
case 15:
|
||||
Breath1_Spell = SPELL_IGNITEFLESH;
|
||||
Breath2_Spell = SPELL_FROSTBURN;
|
||||
break;
|
||||
|
||||
//B1 - Frost
|
||||
case 16:
|
||||
Breath1_Spell = SPELL_FROSTBURN;
|
||||
Breath2_Spell = SPELL_INCINERATE;
|
||||
break;
|
||||
case 17:
|
||||
Breath1_Spell = SPELL_FROSTBURN;
|
||||
Breath2_Spell = SPELL_TIMELAPSE;
|
||||
break;
|
||||
case 18:
|
||||
Breath1_Spell = SPELL_FROSTBURN;
|
||||
Breath2_Spell = SPELL_CORROSIVEACID;
|
||||
break;
|
||||
case 19:
|
||||
Breath1_Spell = SPELL_FROSTBURN;
|
||||
Breath2_Spell = SPELL_IGNITEFLESH;
|
||||
break;
|
||||
};
|
||||
|
||||
EnterEvadeMode();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
|
||||
CurrentVurln_Spell = 0; // We use this to store our last vulnerabilty spell so we can remove it later
|
||||
Enraged = false;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
if (instance->GetBossState(BOSS_FLAMEGOR) != DONE)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
_EnterCombat();
|
||||
|
||||
events.ScheduleEvent(EVENT_SHIMMER, 0);
|
||||
events.ScheduleEvent(EVENT_BREATH_1, 30000);
|
||||
events.ScheduleEvent(EVENT_BREATH_2, 60000);
|
||||
events.ScheduleEvent(EVENT_AFFLICTION, 10000);
|
||||
events.ScheduleEvent(EVENT_FRENZY, 15000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SHIMMER:
|
||||
{
|
||||
// Remove old vulnerabilty spell
|
||||
if (CurrentVurln_Spell)
|
||||
me->RemoveAurasDueToSpell(CurrentVurln_Spell);
|
||||
|
||||
// Cast new random vulnerabilty on self
|
||||
uint32 spell = RAND(SPELL_FIRE_VULNERABILITY, SPELL_FROST_VULNERABILITY, SPELL_SHADOW_VULNERABILITY, SPELL_NATURE_VULNERABILITY, SPELL_ARCANE_VULNERABILITY);
|
||||
DoCast(me, spell);
|
||||
CurrentVurln_Spell = spell;
|
||||
Talk(EMOTE_SHIMMER);
|
||||
events.ScheduleEvent(EVENT_SHIMMER, 45000);
|
||||
break;
|
||||
}
|
||||
case EVENT_BREATH_1:
|
||||
DoCastVictim(Breath1_Spell);
|
||||
events.ScheduleEvent(EVENT_BREATH_1, 60000);
|
||||
break;
|
||||
case EVENT_BREATH_2:
|
||||
DoCastVictim(Breath2_Spell);
|
||||
events.ScheduleEvent(EVENT_BREATH_2, 60000);
|
||||
break;
|
||||
case EVENT_AFFLICTION:
|
||||
{
|
||||
Map::PlayerList const &players = me->GetMap()->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
{
|
||||
if (Player* player = itr->GetSource()->ToPlayer())
|
||||
{
|
||||
DoCast(player, RAND(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN), true);
|
||||
|
||||
if (player->HasAura(SPELL_BROODAF_BLUE) &&
|
||||
player->HasAura(SPELL_BROODAF_BLACK) &&
|
||||
player->HasAura(SPELL_BROODAF_RED) &&
|
||||
player->HasAura(SPELL_BROODAF_BRONZE) &&
|
||||
player->HasAura(SPELL_BROODAF_GREEN))
|
||||
{
|
||||
DoCast(player, SPELL_CHROMATIC_MUT_1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_AFFLICTION, 10000);
|
||||
break;
|
||||
case EVENT_FRENZY:
|
||||
DoCast(me, SPELL_FRENZY);
|
||||
events.ScheduleEvent(EVENT_FRENZY, urand(10000, 15000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Enrage if not already enraged and below 20%
|
||||
if (!Enraged && HealthBelowPct(20))
|
||||
{
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
Enraged = true;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 Breath1_Spell;
|
||||
uint32 Breath2_Spell;
|
||||
uint32 CurrentVurln_Spell;
|
||||
bool Enraged;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_chromaggusAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_chromaggus()
|
||||
{
|
||||
new boss_chromaggus();
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackwing_lair.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SHADOWFLAME = 22539,
|
||||
SPELL_WINGBUFFET = 23339,
|
||||
SPELL_SHADOWOFEBONROC = 23340
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SHADOWFLAME = 1,
|
||||
EVENT_WINGBUFFET = 2,
|
||||
EVENT_SHADOWOFEBONROC = 3
|
||||
};
|
||||
|
||||
class boss_ebonroc : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_ebonroc() : CreatureScript("boss_ebonroc") { }
|
||||
|
||||
struct boss_ebonrocAI : public BossAI
|
||||
{
|
||||
boss_ebonrocAI(Creature* creature) : BossAI(creature, BOSS_EBONROC) { }
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
if (instance->GetBossState(BOSS_BROODLORD) != DONE)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
_EnterCombat();
|
||||
|
||||
events.ScheduleEvent(EVENT_SHADOWFLAME, urand(10000, 20000));
|
||||
events.ScheduleEvent(EVENT_WINGBUFFET, 30000);
|
||||
events.ScheduleEvent(EVENT_SHADOWOFEBONROC, urand(8000, 10000));
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SHADOWFLAME:
|
||||
DoCastVictim(SPELL_SHADOWFLAME);
|
||||
events.ScheduleEvent(EVENT_SHADOWFLAME, urand(10000, 20000));
|
||||
break;
|
||||
case EVENT_WINGBUFFET:
|
||||
DoCastVictim(SPELL_WINGBUFFET);
|
||||
events.ScheduleEvent(EVENT_WINGBUFFET, 30000);
|
||||
break;
|
||||
case EVENT_SHADOWOFEBONROC:
|
||||
DoCastVictim(SPELL_SHADOWOFEBONROC);
|
||||
events.ScheduleEvent(EVENT_SHADOWOFEBONROC, urand(8000, 10000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_ebonrocAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_ebonroc()
|
||||
{
|
||||
new boss_ebonroc();
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackwing_lair.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SHADOWFLAME = 22539,
|
||||
SPELL_WINGBUFFET = 23339,
|
||||
SPELL_FLAMEBUFFET = 23341
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SHADOWFLAME = 1,
|
||||
EVENT_WINGBUFFET = 2,
|
||||
EVENT_FLAMEBUFFET = 3
|
||||
};
|
||||
|
||||
class boss_firemaw : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_firemaw() : CreatureScript("boss_firemaw") { }
|
||||
|
||||
struct boss_firemawAI : public BossAI
|
||||
{
|
||||
boss_firemawAI(Creature* creature) : BossAI(creature, BOSS_FIREMAW) { }
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
if (instance->GetBossState(BOSS_BROODLORD) != DONE)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
_EnterCombat();
|
||||
|
||||
events.ScheduleEvent(EVENT_SHADOWFLAME, urand(10000, 20000));
|
||||
events.ScheduleEvent(EVENT_WINGBUFFET, 30000);
|
||||
events.ScheduleEvent(EVENT_FLAMEBUFFET, 5000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SHADOWFLAME:
|
||||
DoCastVictim(SPELL_SHADOWFLAME);
|
||||
events.ScheduleEvent(EVENT_SHADOWFLAME, urand(10000, 20000));
|
||||
break;
|
||||
case EVENT_WINGBUFFET:
|
||||
DoCastVictim(SPELL_WINGBUFFET);
|
||||
if (DoGetThreat(me->GetVictim()))
|
||||
DoModifyThreatPercent(me->GetVictim(), -75);
|
||||
events.ScheduleEvent(EVENT_WINGBUFFET, 30000);
|
||||
break;
|
||||
case EVENT_FLAMEBUFFET:
|
||||
DoCastVictim(SPELL_FLAMEBUFFET);
|
||||
events.ScheduleEvent(EVENT_FLAMEBUFFET, 5000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_firemawAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_firemaw()
|
||||
{
|
||||
new boss_firemaw();
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackwing_lair.h"
|
||||
|
||||
enum Emotes
|
||||
{
|
||||
EMOTE_FRENZY = 0,
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SHADOWFLAME = 22539,
|
||||
SPELL_WINGBUFFET = 23339,
|
||||
SPELL_FRENZY = 23342 //This spell periodically triggers fire nova
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SHADOWFLAME = 1,
|
||||
EVENT_WINGBUFFET = 2,
|
||||
EVENT_FRENZY = 3
|
||||
};
|
||||
|
||||
class boss_flamegor : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_flamegor() : CreatureScript("boss_flamegor") { }
|
||||
|
||||
struct boss_flamegorAI : public BossAI
|
||||
{
|
||||
boss_flamegorAI(Creature* creature) : BossAI(creature, BOSS_FLAMEGOR) { }
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
if (instance->GetBossState(BOSS_BROODLORD) != DONE)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
_EnterCombat();
|
||||
|
||||
events.ScheduleEvent(EVENT_SHADOWFLAME, urand(10000, 20000));
|
||||
events.ScheduleEvent(EVENT_WINGBUFFET, 30000);
|
||||
events.ScheduleEvent(EVENT_FRENZY, 10000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SHADOWFLAME:
|
||||
DoCastVictim(SPELL_SHADOWFLAME);
|
||||
events.ScheduleEvent(EVENT_SHADOWFLAME, urand(10000, 20000));
|
||||
break;
|
||||
case EVENT_WINGBUFFET:
|
||||
DoCastVictim(SPELL_WINGBUFFET);
|
||||
if (DoGetThreat(me->GetVictim()))
|
||||
DoModifyThreatPercent(me->GetVictim(), -75);
|
||||
events.ScheduleEvent(EVENT_WINGBUFFET, 30000);
|
||||
break;
|
||||
case EVENT_FRENZY:
|
||||
Talk(EMOTE_FRENZY);
|
||||
DoCast(me, SPELL_FRENZY);
|
||||
events.ScheduleEvent(EVENT_FRENZY, urand(8000, 10000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_flamegorAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_flamegor()
|
||||
{
|
||||
new boss_flamegor();
|
||||
}
|
||||
@@ -1,602 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackwing_lair.h"
|
||||
#include "Player.h"
|
||||
|
||||
enum Events
|
||||
{
|
||||
// Victor Nefarius
|
||||
EVENT_SPAWN_ADD = 1,
|
||||
EVENT_SHADOW_BOLT = 2,
|
||||
EVENT_FEAR = 3,
|
||||
EVENT_MIND_CONTROL = 4,
|
||||
// Nefarian
|
||||
EVENT_SHADOWFLAME = 5,
|
||||
EVENT_VEILOFSHADOW = 6,
|
||||
EVENT_CLEAVE = 7,
|
||||
EVENT_TAILLASH = 8,
|
||||
EVENT_CLASSCALL = 9,
|
||||
// UBRS
|
||||
EVENT_CHAOS_1 = 10,
|
||||
EVENT_CHAOS_2 = 11,
|
||||
EVENT_PATH_2 = 12,
|
||||
EVENT_PATH_3 = 13,
|
||||
EVENT_SUCCESS_1 = 14,
|
||||
EVENT_SUCCESS_2 = 15,
|
||||
EVENT_SUCCESS_3 = 16,
|
||||
};
|
||||
|
||||
enum Says
|
||||
{
|
||||
// Nefarius
|
||||
// UBRS
|
||||
SAY_CHAOS_SPELL = 9,
|
||||
SAY_SUCCESS = 10,
|
||||
SAY_FAILURE = 11,
|
||||
// BWL
|
||||
SAY_GAMESBEGIN_1 = 12,
|
||||
SAY_GAMESBEGIN_2 = 13,
|
||||
// SAY_VAEL_INTRO = 14, Not used - when he corrupts Vaelastrasz
|
||||
|
||||
// Nefarian
|
||||
SAY_RANDOM = 0,
|
||||
SAY_RAISE_SKELETONS = 1,
|
||||
SAY_SLAY = 2,
|
||||
SAY_DEATH = 3,
|
||||
|
||||
SAY_MAGE = 4,
|
||||
SAY_WARRIOR = 5,
|
||||
SAY_DRUID = 6,
|
||||
SAY_PRIEST = 7,
|
||||
SAY_PALADIN = 8,
|
||||
SAY_SHAMAN = 9,
|
||||
SAY_WARLOCK = 10,
|
||||
SAY_HUNTER = 11,
|
||||
SAY_ROGUE = 12,
|
||||
SAY_DEATH_KNIGHT = 13
|
||||
};
|
||||
|
||||
enum Gossip
|
||||
{
|
||||
GOSSIP_ID = 21332,
|
||||
GOSSIP_OPTION_ID = 0
|
||||
};
|
||||
|
||||
enum Paths
|
||||
{
|
||||
NEFARIUS_PATH_2 = 1379671,
|
||||
NEFARIUS_PATH_3 = 1379672
|
||||
};
|
||||
|
||||
enum GameObjects
|
||||
{
|
||||
GO_PORTCULLIS_ACTIVE = 164726,
|
||||
GO_PORTCULLIS_TOBOSSROOMS = 175186
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_BRONZE_DRAKANOID = 14263,
|
||||
NPC_BLUE_DRAKANOID = 14261,
|
||||
NPC_RED_DRAKANOID = 14264,
|
||||
NPC_GREEN_DRAKANOID = 14262,
|
||||
NPC_BLACK_DRAKANOID = 14265,
|
||||
NPC_CHROMATIC_DRAKANOID = 14302,
|
||||
NPC_BONE_CONSTRUCT = 14605,
|
||||
// UBRS
|
||||
NPC_GYTH = 10339
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// Victor Nefarius
|
||||
// UBRS Spells
|
||||
SPELL_CHROMATIC_CHAOS = 16337, // Self Cast hits 10339
|
||||
SPELL_VAELASTRASZZ_SPAWN = 16354, // Self Cast Depawn one sec after
|
||||
// BWL Spells
|
||||
SPELL_SHADOWBOLT = 22677,
|
||||
SPELL_SHADOWBOLT_VOLLEY = 22665,
|
||||
SPELL_SHADOW_COMMAND = 22667,
|
||||
SPELL_FEAR = 22678,
|
||||
|
||||
SPELL_NEFARIANS_BARRIER = 22663,
|
||||
|
||||
// Nefarian
|
||||
SPELL_SHADOWFLAME_INITIAL = 22992,
|
||||
SPELL_SHADOWFLAME = 22539,
|
||||
SPELL_BELLOWINGROAR = 22686,
|
||||
SPELL_VEILOFSHADOW = 7068,
|
||||
SPELL_CLEAVE = 20691,
|
||||
SPELL_TAILLASH = 23364,
|
||||
|
||||
SPELL_MAGE = 23410, // wild magic
|
||||
SPELL_WARRIOR = 23397, // beserk
|
||||
SPELL_DRUID = 23398, // cat form
|
||||
SPELL_PRIEST = 23401, // corrupted healing
|
||||
SPELL_PALADIN = 23418, // syphon blessing
|
||||
SPELL_SHAMAN = 23425, // totems
|
||||
SPELL_WARLOCK = 23427, // infernals
|
||||
SPELL_HUNTER = 23436, // bow broke
|
||||
SPELL_ROGUE = 23414, // Paralise
|
||||
SPELL_DEATH_KNIGHT = 49576 // Death Grip
|
||||
|
||||
// 19484
|
||||
// 22664
|
||||
// 22674
|
||||
// 22666
|
||||
};
|
||||
|
||||
Position const DrakeSpawnLoc[2] = // drakonid
|
||||
{
|
||||
{-7591.151855f, -1204.051880f, 476.800476f, 3.0f},
|
||||
{-7514.598633f, -1150.448853f, 476.796570f, 3.0f}
|
||||
};
|
||||
|
||||
Position const NefarianLoc[2] =
|
||||
{
|
||||
{-7449.763672f, -1387.816040f, 526.783691f, 3.0f}, // nefarian spawn
|
||||
{-7535.456543f, -1279.562500f, 476.798706f, 3.0f} // nefarian move
|
||||
};
|
||||
|
||||
uint32 const Entry[5] = {NPC_BRONZE_DRAKANOID, NPC_BLUE_DRAKANOID, NPC_RED_DRAKANOID, NPC_GREEN_DRAKANOID, NPC_BLACK_DRAKANOID};
|
||||
|
||||
class boss_victor_nefarius : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_victor_nefarius() : CreatureScript("boss_victor_nefarius") { }
|
||||
|
||||
struct boss_victor_nefariusAI : public BossAI
|
||||
{
|
||||
boss_victor_nefariusAI(Creature* creature) : BossAI(creature, BOSS_NEFARIAN) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
SpawnedAdds = 0;
|
||||
|
||||
if (me->GetMapId() == 469)
|
||||
{
|
||||
// pussywizard:
|
||||
bool reset = true;
|
||||
if (instance)
|
||||
if (Creature* nefarian = instance->instance->GetCreature(instance->GetData64(DATA_NEFARIAN)))
|
||||
reset = false;
|
||||
if (reset)
|
||||
_Reset();
|
||||
|
||||
// pussywizard:
|
||||
if (!instance || instance->GetBossState(BOSS_NEFARIAN) == DONE || instance->GetBossState(BOSS_NEFARIAN) == IN_PROGRESS)
|
||||
me->SetVisible(false);
|
||||
else
|
||||
me->SetVisible(true);
|
||||
|
||||
me->SetPhaseMask(1, true);
|
||||
me->SetUInt32Value(UNIT_NPC_FLAGS, 1);
|
||||
me->setFaction(35);
|
||||
me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR);
|
||||
me->RemoveAura(SPELL_NEFARIANS_BARRIER);
|
||||
}
|
||||
}
|
||||
|
||||
bool CanAIAttack(const Unit* target) const { return me->IsVisible(); }
|
||||
|
||||
void JustReachedHome()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void BeginEvent(Player* target)
|
||||
{
|
||||
_EnterCombat();
|
||||
|
||||
Talk(SAY_GAMESBEGIN_2);
|
||||
|
||||
me->setFaction(103);
|
||||
me->SetUInt32Value(UNIT_NPC_FLAGS, 0);
|
||||
DoCast(me, SPELL_NEFARIANS_BARRIER);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
AttackStart(target);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(3000, 10000));
|
||||
events.ScheduleEvent(EVENT_FEAR, urand(10000, 20000));
|
||||
//events.ScheduleEvent(EVENT_MIND_CONTROL, urand(30000, 35000));
|
||||
events.ScheduleEvent(EVENT_SPAWN_ADD, 10000);
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit*)
|
||||
{
|
||||
if (summon->GetEntry() != NPC_NEFARIAN)
|
||||
{
|
||||
summon->UpdateEntry(NPC_BONE_CONSTRUCT);
|
||||
summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
summon->SetReactState(REACT_PASSIVE);
|
||||
summon->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* /*summon*/) { }
|
||||
|
||||
void SetData(uint32 type, uint32 data)
|
||||
{
|
||||
if ( type == 1 && data == 1)
|
||||
{
|
||||
me->StopMoving();
|
||||
events.ScheduleEvent(EVENT_PATH_2, 9000);
|
||||
}
|
||||
|
||||
if (type == 1 && data == 2)
|
||||
events.ScheduleEvent(EVENT_SUCCESS_1, 5000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_PATH_2:
|
||||
me->GetMotionMaster()->MovePath(NEFARIUS_PATH_2, false);
|
||||
events.ScheduleEvent(EVENT_CHAOS_1, 7000);
|
||||
break;
|
||||
case EVENT_CHAOS_1:
|
||||
if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 75.0f, true))
|
||||
{
|
||||
me->SetFacingToObject(gyth);
|
||||
Talk(SAY_CHAOS_SPELL);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHAOS_2, 2000);
|
||||
break;
|
||||
case EVENT_CHAOS_2:
|
||||
DoCast(SPELL_CHROMATIC_CHAOS);
|
||||
me->SetFacingTo(1.570796f);
|
||||
break;
|
||||
case EVENT_SUCCESS_1:
|
||||
if (Unit* player = me->SelectNearestPlayer(60.0f))
|
||||
{
|
||||
me->SetInFront(player);
|
||||
Talk(SAY_SUCCESS);
|
||||
if (GameObject* portcullis1 = me->FindNearestGameObject(GO_PORTCULLIS_ACTIVE, 65.0f))
|
||||
portcullis1->SetGoState(GO_STATE_ACTIVE);
|
||||
if (GameObject* portcullis2 = me->FindNearestGameObject(GO_PORTCULLIS_TOBOSSROOMS, 80.0f))
|
||||
portcullis2->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_SUCCESS_2, 4000);
|
||||
break;
|
||||
case EVENT_SUCCESS_2:
|
||||
DoCast(me, SPELL_VAELASTRASZZ_SPAWN);
|
||||
me->DespawnOrUnsummon(1000);
|
||||
break;
|
||||
case EVENT_PATH_3:
|
||||
me->GetMotionMaster()->MovePath(NEFARIUS_PATH_3, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Only do this if we haven't spawned nefarian yet
|
||||
if (UpdateVictim() && SpawnedAdds <= 42)
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SHADOW_BOLT:
|
||||
switch (urand(0, 1))
|
||||
{
|
||||
case 0:
|
||||
DoCastVictim(SPELL_SHADOWBOLT_VOLLEY);
|
||||
break;
|
||||
case 1:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true))
|
||||
DoCast(target, SPELL_SHADOWBOLT);
|
||||
break;
|
||||
}
|
||||
DoResetThreat();
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(3000, 10000));
|
||||
break;
|
||||
case EVENT_FEAR:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true))
|
||||
DoCast(target, SPELL_FEAR);
|
||||
events.ScheduleEvent(EVENT_FEAR, urand(10000, 20000));
|
||||
break;
|
||||
case EVENT_MIND_CONTROL:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true))
|
||||
DoCast(target, SPELL_SHADOW_COMMAND);
|
||||
events.ScheduleEvent(EVENT_MIND_CONTROL, urand(30000, 35000));
|
||||
break;
|
||||
case EVENT_SPAWN_ADD:
|
||||
for (uint8 i=0; i<2; ++i)
|
||||
{
|
||||
uint32 CreatureID;
|
||||
if (urand(0, 2) == 0)
|
||||
CreatureID = NPC_CHROMATIC_DRAKANOID;
|
||||
else
|
||||
CreatureID = Entry[urand(0, 4)];
|
||||
if (Creature* dragon = me->SummonCreature(CreatureID, DrakeSpawnLoc[i]))
|
||||
{
|
||||
dragon->setFaction(103);
|
||||
dragon->AI()->AttackStart(me->GetVictim());
|
||||
}
|
||||
|
||||
if (++SpawnedAdds >= 42)
|
||||
{
|
||||
if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianLoc[0]))
|
||||
{
|
||||
nefarian->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
|
||||
nefarian->SetCanFly(true);
|
||||
nefarian->SetHover(false);
|
||||
nefarian->setActive(true);
|
||||
nefarian->SetHomePosition(NefarianLoc[1]);
|
||||
nefarian->GetMotionMaster()->MoveCharge(NefarianLoc[1].GetPositionX(), NefarianLoc[1].GetPositionY(), NefarianLoc[1].GetPositionZ(), 15.0f);
|
||||
|
||||
nefarian->AI()->DoCastAOE(SPELL_SHADOWFLAME_INITIAL);
|
||||
}
|
||||
events.CancelEvent(EVENT_MIND_CONTROL);
|
||||
events.CancelEvent(EVENT_FEAR);
|
||||
events.CancelEvent(EVENT_SHADOW_BOLT);
|
||||
me->SetVisible(false);
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_SPAWN_ADD, 4000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sGossipSelect(Player* player, uint32 sender, uint32 action)
|
||||
{
|
||||
if (sender == GOSSIP_ID && action == GOSSIP_OPTION_ID)
|
||||
{
|
||||
// pussywizard:
|
||||
InstanceScript* instance = player->GetInstanceScript();
|
||||
if (!instance || instance->GetBossState(BOSS_NEFARIAN) == DONE)
|
||||
return;
|
||||
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
Talk(SAY_GAMESBEGIN_1);
|
||||
BeginEvent(player);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 SpawnedAdds;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_victor_nefariusAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_nefarian : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_nefarian() : CreatureScript("boss_nefarian") { }
|
||||
|
||||
struct boss_nefarianAI : public BossAI
|
||||
{
|
||||
boss_nefarianAI(Creature* creature) : BossAI(creature, BOSS_NEFARIAN) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Phase3 = false;
|
||||
canDespawn = false;
|
||||
DespawnTimer = 30000;
|
||||
}
|
||||
|
||||
void JustReachedHome()
|
||||
{
|
||||
canDespawn = true;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
events.ScheduleEvent(EVENT_SHADOWFLAME, 12000);
|
||||
events.ScheduleEvent(EVENT_FEAR, urand(25000, 35000));
|
||||
events.ScheduleEvent(EVENT_VEILOFSHADOW, urand(25000, 35000));
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 7000);
|
||||
//events.ScheduleEvent(EVENT_TAILLASH, 10000);
|
||||
events.ScheduleEvent(EVENT_CLASSCALL, urand(30000, 35000));
|
||||
Talk(SAY_RANDOM);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*Killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim)
|
||||
{
|
||||
if (rand()%5)
|
||||
return;
|
||||
|
||||
Talk(SAY_SLAY, victim);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id)
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetWalk(false);
|
||||
me->SetInCombatWithZone();
|
||||
if (me->GetVictim())
|
||||
AttackStart(me->GetVictim());
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (canDespawn && DespawnTimer <= diff)
|
||||
{
|
||||
instance->SetBossState(BOSS_NEFARIAN, FAIL);
|
||||
|
||||
std::list<Creature*> constructList;
|
||||
me->GetCreatureListWithEntryInGrid(constructList, NPC_BONE_CONSTRUCT, 500.0f);
|
||||
for (std::list<Creature*>::const_iterator itr = constructList.begin(); itr != constructList.end(); ++itr)
|
||||
(*itr)->DespawnOrUnsummon();
|
||||
|
||||
} else DespawnTimer -= diff;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (canDespawn)
|
||||
canDespawn = false;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SHADOWFLAME:
|
||||
DoCastVictim(SPELL_SHADOWFLAME);
|
||||
events.ScheduleEvent(EVENT_SHADOWFLAME, 12000);
|
||||
break;
|
||||
case EVENT_FEAR:
|
||||
DoCastVictim(SPELL_BELLOWINGROAR);
|
||||
events.ScheduleEvent(EVENT_FEAR, urand(25000, 35000));
|
||||
break;
|
||||
case EVENT_VEILOFSHADOW:
|
||||
DoCastVictim(SPELL_VEILOFSHADOW);
|
||||
events.ScheduleEvent(EVENT_VEILOFSHADOW, urand(25000, 35000));
|
||||
break;
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 7000);
|
||||
break;
|
||||
case EVENT_TAILLASH:
|
||||
// Cast NYI since we need a better check for behind target
|
||||
DoCastVictim(SPELL_TAILLASH);
|
||||
events.ScheduleEvent(EVENT_TAILLASH, 10000);
|
||||
break;
|
||||
case EVENT_CLASSCALL:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
|
||||
switch (target->getClass())
|
||||
{
|
||||
case CLASS_MAGE:
|
||||
Talk(SAY_MAGE);
|
||||
DoCast(me, SPELL_MAGE);
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
Talk(SAY_WARRIOR);
|
||||
DoCast(me, SPELL_WARRIOR);
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
Talk(SAY_DRUID);
|
||||
DoCast(target, SPELL_DRUID);
|
||||
break;
|
||||
case CLASS_PRIEST:
|
||||
Talk(SAY_PRIEST);
|
||||
DoCast(me, SPELL_PRIEST);
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
Talk(SAY_PALADIN);
|
||||
DoCast(me, SPELL_PALADIN);
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
Talk(SAY_SHAMAN);
|
||||
DoCast(me, SPELL_SHAMAN);
|
||||
break;
|
||||
case CLASS_WARLOCK:
|
||||
Talk(SAY_WARLOCK);
|
||||
DoCast(me, SPELL_WARLOCK);
|
||||
break;
|
||||
case CLASS_HUNTER:
|
||||
Talk(SAY_HUNTER);
|
||||
DoCast(me, SPELL_HUNTER);
|
||||
break;
|
||||
case CLASS_ROGUE:
|
||||
Talk(SAY_ROGUE);
|
||||
DoCast(me, SPELL_ROGUE);
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
Talk(SAY_DEATH_KNIGHT);
|
||||
DoCast(me, SPELL_DEATH_KNIGHT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CLASSCALL, urand(30000, 35000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Phase3 begins when health below 20 pct
|
||||
if (!Phase3 && HealthBelowPct(20))
|
||||
{
|
||||
std::list<Creature*> constructList;
|
||||
me->GetCreatureListWithEntryInGrid(constructList, NPC_BONE_CONSTRUCT, 500.0f);
|
||||
for (std::list<Creature*>::const_iterator itr = constructList.begin(); itr != constructList.end(); ++itr)
|
||||
if ((*itr) && !(*itr)->IsAlive())
|
||||
{
|
||||
(*itr)->Respawn();
|
||||
(*itr)->SetInCombatWithZone();
|
||||
(*itr)->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
(*itr)->SetReactState(REACT_AGGRESSIVE);
|
||||
(*itr)->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
}
|
||||
|
||||
Phase3 = true;
|
||||
Talk(SAY_RAISE_SKELETONS);
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool canDespawn;
|
||||
uint32 DespawnTimer;
|
||||
bool Phase3;
|
||||
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_nefarianAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_nefarian()
|
||||
{
|
||||
new boss_victor_nefarius();
|
||||
new boss_nefarian();
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "blackwing_lair.h"
|
||||
#include "Player.h"
|
||||
|
||||
enum Say
|
||||
{
|
||||
SAY_EGGS_BROKEN1 = 0,
|
||||
SAY_EGGS_BROKEN2 = 1,
|
||||
SAY_EGGS_BROKEN3 = 2,
|
||||
SAY_DEATH = 3,
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_MINDCONTROL = 42013,
|
||||
SPELL_CHANNEL = 45537,
|
||||
SPELL_EGG_DESTROY = 19873,
|
||||
|
||||
SPELL_CLEAVE = 22540,
|
||||
SPELL_WARSTOMP = 24375,
|
||||
SPELL_FIREBALLVOLLEY = 22425,
|
||||
SPELL_CONFLAGRATION = 23023
|
||||
};
|
||||
|
||||
enum Summons
|
||||
{
|
||||
NPC_ELITE_DRACHKIN = 12422,
|
||||
NPC_ELITE_WARRIOR = 12458,
|
||||
NPC_WARRIOR = 12416,
|
||||
NPC_MAGE = 12420,
|
||||
NPC_WARLOCK = 12459,
|
||||
|
||||
GO_EGG = 177807
|
||||
};
|
||||
|
||||
enum EVENTS
|
||||
{
|
||||
EVENT_CLEAVE = 1,
|
||||
EVENT_STOMP = 2,
|
||||
EVENT_FIREBALL = 3,
|
||||
EVENT_CONFLAGRATION = 4
|
||||
};
|
||||
|
||||
class boss_razorgore : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_razorgore() : CreatureScript("boss_razorgore") { }
|
||||
|
||||
struct boss_razorgoreAI : public BossAI
|
||||
{
|
||||
boss_razorgoreAI(Creature* creature) : BossAI(creature, BOSS_RAZORGORE) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
|
||||
secondPhase = false;
|
||||
instance->SetData(DATA_EGG_EVENT, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetData(DATA_EGG_EVENT, NOT_STARTED);
|
||||
}
|
||||
|
||||
void DoChangePhase()
|
||||
{
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 15000);
|
||||
events.ScheduleEvent(EVENT_STOMP, 35000);
|
||||
events.ScheduleEvent(EVENT_FIREBALL, 7000);
|
||||
events.ScheduleEvent(EVENT_CONFLAGRATION, 12000);
|
||||
|
||||
secondPhase = true;
|
||||
me->RemoveAllAuras();
|
||||
me->SetHealth(me->GetMaxHealth());
|
||||
}
|
||||
|
||||
void DoAction(int32 action)
|
||||
{
|
||||
if (action == ACTION_PHASE_TWO)
|
||||
DoChangePhase();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask)
|
||||
{
|
||||
if (!secondPhase)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(7000, 10000));
|
||||
break;
|
||||
case EVENT_STOMP:
|
||||
DoCastVictim(SPELL_WARSTOMP);
|
||||
events.ScheduleEvent(EVENT_STOMP, urand(15000, 25000));
|
||||
break;
|
||||
case EVENT_FIREBALL:
|
||||
DoCastVictim(SPELL_FIREBALLVOLLEY);
|
||||
events.ScheduleEvent(EVENT_FIREBALL, urand(12000, 15000));
|
||||
break;
|
||||
case EVENT_CONFLAGRATION:
|
||||
DoCastVictim(SPELL_CONFLAGRATION);
|
||||
if (me->GetVictim() && me->GetVictim()->HasAura(SPELL_CONFLAGRATION))
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true))
|
||||
me->TauntApply(target);
|
||||
events.ScheduleEvent(EVENT_CONFLAGRATION, 30000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool secondPhase;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_razorgoreAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class go_orb_of_domination : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
go_orb_of_domination() : GameObjectScript("go_orb_of_domination") { }
|
||||
|
||||
bool OnGossipHello(Player* player, GameObject* go)
|
||||
{
|
||||
if (InstanceScript* instance = go->GetInstanceScript())
|
||||
if (instance->GetData(DATA_EGG_EVENT) != DONE)
|
||||
if (Creature* razor = ObjectAccessor::GetCreature(*go, instance->GetData64(DATA_RAZORGORE_THE_UNTAMED)))
|
||||
{
|
||||
razor->Attack(player, true);
|
||||
player->CastSpell(razor, SPELL_MINDCONTROL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class spell_egg_event : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_egg_event() : SpellScriptLoader("spell_egg_event") { }
|
||||
|
||||
class spell_egg_eventSpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_egg_eventSpellScript);
|
||||
|
||||
void HandleOnHit()
|
||||
{
|
||||
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
|
||||
instance->SetData(DATA_EGG_EVENT, SPECIAL);
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
OnHit += SpellHitFn(spell_egg_eventSpellScript::HandleOnHit);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const
|
||||
{
|
||||
return new spell_egg_eventSpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_razorgore()
|
||||
{
|
||||
new boss_razorgore();
|
||||
new go_orb_of_domination();
|
||||
new spell_egg_event();
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blackwing_lair.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "Player.h"
|
||||
|
||||
enum Says
|
||||
{
|
||||
SAY_LINE1 = 0,
|
||||
SAY_LINE2 = 1,
|
||||
SAY_LINE3 = 2,
|
||||
SAY_HALFLIFE = 3,
|
||||
SAY_KILLTARGET = 4
|
||||
};
|
||||
|
||||
enum Gossip
|
||||
{
|
||||
GOSSIP_ID = 21334,
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_ESSENCEOFTHERED = 23513,
|
||||
SPELL_FLAMEBREATH = 23461,
|
||||
SPELL_FIRENOVA = 23462,
|
||||
SPELL_TAILSWIPE = 15847,
|
||||
SPELL_BURNINGADRENALINE = 23620,
|
||||
SPELL_CLEAVE = 20684 //Chain cleave is most likely named something different and contains a dummy effect
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_SPEECH_1 = 1,
|
||||
EVENT_SPEECH_2 = 2,
|
||||
EVENT_SPEECH_3 = 3,
|
||||
EVENT_SPEECH_4 = 4,
|
||||
EVENT_ESSENCEOFTHERED = 5,
|
||||
EVENT_FLAMEBREATH = 6,
|
||||
EVENT_FIRENOVA = 7,
|
||||
EVENT_TAILSWIPE = 8,
|
||||
EVENT_CLEAVE = 9,
|
||||
EVENT_BURNINGADRENALINE_CASTER = 10,
|
||||
EVENT_BURNINGADRENALINE_TANK = 11
|
||||
};
|
||||
|
||||
class boss_vaelastrasz : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_vaelastrasz() : CreatureScript("boss_vaelastrasz") { }
|
||||
|
||||
struct boss_vaelAI : public BossAI
|
||||
{
|
||||
boss_vaelAI(Creature* creature) : BossAI(creature, BOSS_VAELASTRAZ)
|
||||
{
|
||||
creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
creature->setFaction(35);
|
||||
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_Reset();
|
||||
|
||||
me->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
PlayerGUID = 0;
|
||||
|
||||
HasYelled = false;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_EnterCombat();
|
||||
|
||||
DoCast(me, SPELL_ESSENCEOFTHERED);
|
||||
me->SetHealth(me->CountPctFromMaxHealth(30));
|
||||
// now drop damage requirement to be able to take loot
|
||||
me->ResetPlayerDamageReq();
|
||||
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 10000);
|
||||
events.ScheduleEvent(EVENT_FLAMEBREATH, 15000);
|
||||
events.ScheduleEvent(EVENT_FIRENOVA, 20000);
|
||||
events.ScheduleEvent(EVENT_TAILSWIPE, 11000);
|
||||
events.ScheduleEvent(EVENT_BURNINGADRENALINE_CASTER, 15000);
|
||||
events.ScheduleEvent(EVENT_BURNINGADRENALINE_TANK, 45000);
|
||||
}
|
||||
|
||||
void BeginSpeech(Unit* target)
|
||||
{
|
||||
PlayerGUID = target->GetGUID();
|
||||
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
events.ScheduleEvent(EVENT_SPEECH_1, 1000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim)
|
||||
{
|
||||
if (rand()%5)
|
||||
return;
|
||||
|
||||
Talk(SAY_KILLTARGET, victim);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
// Speech
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SPEECH_1:
|
||||
Talk(SAY_LINE1);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
|
||||
events.ScheduleEvent(EVENT_SPEECH_2, 12000);
|
||||
break;
|
||||
case EVENT_SPEECH_2:
|
||||
Talk(SAY_LINE2);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
|
||||
events.ScheduleEvent(EVENT_SPEECH_3, 12000);
|
||||
break;
|
||||
case EVENT_SPEECH_3:
|
||||
Talk(SAY_LINE3);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
|
||||
events.ScheduleEvent(EVENT_SPEECH_4, 16000);
|
||||
break;
|
||||
case EVENT_SPEECH_4:
|
||||
me->setFaction(103);
|
||||
if (PlayerGUID && ObjectAccessor::GetUnit(*me, PlayerGUID))
|
||||
AttackStart(ObjectAccessor::GetUnit(*me, PlayerGUID));;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CLEAVE:
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 15000);
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
break;
|
||||
case EVENT_FLAMEBREATH:
|
||||
DoCastVictim(SPELL_FLAMEBREATH);
|
||||
events.ScheduleEvent(EVENT_FLAMEBREATH, urand(8000, 14000));
|
||||
break;
|
||||
case EVENT_FIRENOVA:
|
||||
DoCastVictim(SPELL_FIRENOVA);
|
||||
events.ScheduleEvent(EVENT_FIRENOVA, 15000);
|
||||
break;
|
||||
case EVENT_TAILSWIPE:
|
||||
//Only cast if we are behind
|
||||
/*if (!me->HasInArc(M_PI, me->GetVictim()))
|
||||
{
|
||||
DoCast(me->GetVictim(), SPELL_TAILSWIPE);
|
||||
}*/
|
||||
events.ScheduleEvent(EVENT_TAILSWIPE, 15000);
|
||||
break;
|
||||
case EVENT_BURNINGADRENALINE_CASTER:
|
||||
{
|
||||
Unit* target = NULL;
|
||||
|
||||
uint8 i = 0;
|
||||
while (i < 3) // max 3 tries to get a random target with power_mana
|
||||
{
|
||||
++i;
|
||||
target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true); // not aggro leader
|
||||
if (target && target->getPowerType() == POWER_MANA)
|
||||
i = 3;
|
||||
}
|
||||
if (target) // cast on self (see below)
|
||||
target->CastSpell(target, SPELL_BURNINGADRENALINE, true);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_BURNINGADRENALINE_CASTER, 15000);
|
||||
break;
|
||||
case EVENT_BURNINGADRENALINE_TANK:
|
||||
// have the victim cast the spell on himself otherwise the third effect aura will be applied to Vael instead of the player
|
||||
me->GetVictim()->CastSpell(me->GetVictim(), SPELL_BURNINGADRENALINE, true);
|
||||
events.ScheduleEvent(EVENT_BURNINGADRENALINE_TANK, 45000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Yell if hp lower than 15%
|
||||
if (HealthBelowPct(15) && !HasYelled)
|
||||
{
|
||||
Talk(SAY_HALFLIFE);
|
||||
HasYelled = true;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void sGossipSelect(Player* player, uint32 sender, uint32 action)
|
||||
{
|
||||
if (sender == GOSSIP_ID && action == 0)
|
||||
{
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
BeginSpeech(player);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint64 PlayerGUID;
|
||||
bool HasYelled;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_vaelAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_vaelastrasz()
|
||||
{
|
||||
new boss_vaelastrasz();
|
||||
}
|
||||
@@ -1,360 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "PassiveAI.h"
|
||||
#include "blackwing_lair.h"
|
||||
#include "Player.h"
|
||||
|
||||
/*
|
||||
Blackwing Lair Encounter:
|
||||
1 - boss_razorgore.cpp
|
||||
2 - boss_vaelastrasz.cpp
|
||||
3 - boss_broodlord_lashlayer.cpp
|
||||
4 - boss_firemaw.cpp
|
||||
5 - boss_ebonroc.cpp
|
||||
6 - boss_flamegor.cpp
|
||||
7 - boss_chromaggus.cpp
|
||||
8 - boss_nefarian.cpp
|
||||
*/
|
||||
|
||||
Position const SummonPosition[8] =
|
||||
{
|
||||
{-7661.207520f, -1043.268188f, 407.199554f, 6.280452f},
|
||||
{-7644.145020f, -1065.628052f, 407.204956f, 0.501492f},
|
||||
{-7624.260742f, -1095.196899f, 407.205017f, 0.544694f},
|
||||
{-7608.501953f, -1116.077271f, 407.199921f, 0.816443f},
|
||||
{-7531.841797f, -1063.765381f, 407.199615f, 2.874187f},
|
||||
{-7547.319336f, -1040.971924f, 407.205078f, 3.789175f},
|
||||
{-7568.547852f, -1013.112488f, 407.204926f, 3.773467f},
|
||||
{-7584.175781f, -989.6691289f, 407.199585f, 4.527447f},
|
||||
};
|
||||
|
||||
uint32 const Entry[5] = {12422, 12458, 12416, 12420, 12459};
|
||||
|
||||
class instance_blackwing_lair : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
instance_blackwing_lair() : InstanceMapScript(BRLScriptName, 469) { }
|
||||
|
||||
struct instance_blackwing_lair_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
instance_blackwing_lair_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
SetBossNumber(EncounterCount);
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
// Razorgore
|
||||
EggCount = 0;
|
||||
EggEvent = 0;
|
||||
RazorgoreTheUntamedGUID = 0;
|
||||
RazorgoreDoorGUID = 0;
|
||||
EggList.clear();
|
||||
// Vaelastrasz the Corrupt
|
||||
VaelastraszTheCorruptGUID = 0;
|
||||
VaelastraszDoorGUID = 0;
|
||||
// Broodlord Lashlayer
|
||||
BroodlordLashlayerGUID = 0;
|
||||
BroodlordDoorGUID = 0;
|
||||
// 3 Dragons
|
||||
FiremawGUID = 0;
|
||||
EbonrocGUID = 0;
|
||||
FlamegorGUID = 0;
|
||||
ChrommagusDoorGUID = 0;
|
||||
// Chormaggus
|
||||
ChromaggusGUID = 0;
|
||||
NefarianDoorGUID = 0;
|
||||
// Nefarian
|
||||
LordVictorNefariusGUID = 0;
|
||||
NefarianGUID = 0;
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature)
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_RAZORGORE:
|
||||
RazorgoreTheUntamedGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_BLACKWING_DRAGON:
|
||||
case NPC_BLACKWING_TASKMASTER:
|
||||
case NPC_BLACKWING_LEGIONAIRE:
|
||||
case NPC_BLACKWING_WARLOCK:
|
||||
if (Creature* razor = instance->GetCreature(RazorgoreTheUntamedGUID))
|
||||
razor->AI()->JustSummoned(creature);
|
||||
break;
|
||||
case NPC_VAELASTRAZ:
|
||||
VaelastraszTheCorruptGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_BROODLORD:
|
||||
BroodlordLashlayerGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_FIRENAW:
|
||||
FiremawGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_EBONROC:
|
||||
EbonrocGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_FLAMEGOR:
|
||||
FlamegorGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_CHROMAGGUS:
|
||||
ChromaggusGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_VICTOR_NEFARIUS:
|
||||
LordVictorNefariusGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_NEFARIAN:
|
||||
NefarianGUID = creature->GetGUID();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go)
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case 177807: // Egg
|
||||
if (GetBossState(BOSS_FIREMAW) == DONE)
|
||||
go->SetPhaseMask(2, true);
|
||||
else
|
||||
EggList.push_back(go->GetGUID());
|
||||
break;
|
||||
case 175946: // Door
|
||||
RazorgoreDoorGUID = go->GetGUID();
|
||||
HandleGameObject(0, GetBossState(BOSS_RAZORGORE) == DONE, go);
|
||||
break;
|
||||
case 175185: // Door
|
||||
VaelastraszDoorGUID = go->GetGUID();
|
||||
HandleGameObject(0, GetBossState(BOSS_VAELASTRAZ) == DONE, go);
|
||||
break;
|
||||
case 180424: // Door
|
||||
BroodlordDoorGUID = go->GetGUID();
|
||||
HandleGameObject(0, GetBossState(BOSS_BROODLORD) == DONE, go);
|
||||
break;
|
||||
case 185483: // Door
|
||||
ChrommagusDoorGUID = go->GetGUID();
|
||||
HandleGameObject(0, GetBossState(BOSS_FIREMAW) == DONE && GetBossState(BOSS_EBONROC) == DONE && GetBossState(BOSS_FLAMEGOR) == DONE, go);
|
||||
break;
|
||||
case 181125: // Door
|
||||
NefarianDoorGUID = go->GetGUID();
|
||||
HandleGameObject(0, GetBossState(BOSS_CHROMAGGUS) == DONE, go);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectRemove(GameObject* go)
|
||||
{
|
||||
if (go->GetEntry() == 177807) // Egg
|
||||
EggList.remove(go->GetGUID());
|
||||
}
|
||||
|
||||
bool SetBossState(uint32 type, EncounterState state)
|
||||
{
|
||||
// pussywizard:
|
||||
if (GetBossState(type) == DONE && state != DONE) // prevent undoneing a boss xd
|
||||
return false;
|
||||
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case BOSS_RAZORGORE:
|
||||
HandleGameObject(RazorgoreDoorGUID, state == DONE);
|
||||
if (state == DONE)
|
||||
{
|
||||
for (std::list<uint64>::const_iterator itr = EggList.begin(); itr != EggList.end(); ++itr)
|
||||
if (GameObject* egg = instance->GetGameObject((*itr)))
|
||||
egg->SetPhaseMask(2, true);
|
||||
}
|
||||
SetData(DATA_EGG_EVENT, NOT_STARTED);
|
||||
break;
|
||||
case BOSS_VAELASTRAZ:
|
||||
HandleGameObject(VaelastraszDoorGUID, state == DONE);
|
||||
break;
|
||||
case BOSS_BROODLORD:
|
||||
HandleGameObject(BroodlordDoorGUID, state == DONE);
|
||||
break;
|
||||
case BOSS_FIREMAW:
|
||||
case BOSS_EBONROC:
|
||||
case BOSS_FLAMEGOR:
|
||||
HandleGameObject(ChrommagusDoorGUID, GetBossState(BOSS_FIREMAW) == DONE && GetBossState(BOSS_EBONROC) == DONE && GetBossState(BOSS_FLAMEGOR) == DONE);
|
||||
break;
|
||||
case BOSS_CHROMAGGUS:
|
||||
HandleGameObject(NefarianDoorGUID, state == DONE);
|
||||
break;
|
||||
case BOSS_NEFARIAN:
|
||||
switch (state)
|
||||
{
|
||||
case NOT_STARTED:
|
||||
if (Creature* nefarian = instance->GetCreature(NefarianGUID))
|
||||
nefarian->DespawnOrUnsummon();
|
||||
break;
|
||||
case FAIL:
|
||||
_events.ScheduleEvent(EVENT_RESPAWN_NEFARIUS, 15*IN_MILLISECONDS*MINUTE);
|
||||
SetBossState(BOSS_NEFARIAN, NOT_STARTED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64 GetData64(uint32 id) const
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case DATA_RAZORGORE_THE_UNTAMED: return RazorgoreTheUntamedGUID;
|
||||
case DATA_VAELASTRAZ_THE_CORRUPT: return VaelastraszTheCorruptGUID;
|
||||
case DATA_BROODLORD_LASHLAYER: return BroodlordLashlayerGUID;
|
||||
case DATA_FIRENAW: return FiremawGUID;
|
||||
case DATA_EBONROC: return EbonrocGUID;
|
||||
case DATA_FLAMEGOR: return FlamegorGUID;
|
||||
case DATA_CHROMAGGUS: return ChromaggusGUID;
|
||||
case DATA_LORD_VICTOR_NEFARIUS: return LordVictorNefariusGUID;
|
||||
case DATA_NEFARIAN: return NefarianGUID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data)
|
||||
{
|
||||
if (type == DATA_EGG_EVENT)
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case IN_PROGRESS:
|
||||
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 45*IN_MILLISECONDS);
|
||||
EggEvent = data;
|
||||
EggCount = 0;
|
||||
break;
|
||||
case NOT_STARTED:
|
||||
_events.CancelEvent(EVENT_RAZOR_SPAWN);
|
||||
EggEvent = data;
|
||||
EggCount = 0;
|
||||
break;
|
||||
case SPECIAL:
|
||||
if (++EggCount == 15)
|
||||
{
|
||||
if (Creature* razor = instance->GetCreature(RazorgoreTheUntamedGUID))
|
||||
{
|
||||
SetData(DATA_EGG_EVENT, DONE);
|
||||
razor->RemoveAurasDueToSpell(42013); // MindControl
|
||||
DoRemoveAurasDueToSpellOnPlayers(42013);
|
||||
}
|
||||
_events.ScheduleEvent(EVENT_RAZOR_PHASE_TWO, IN_MILLISECONDS);
|
||||
_events.CancelEvent(EVENT_RAZOR_SPAWN);
|
||||
}
|
||||
if (EggEvent == NOT_STARTED)
|
||||
SetData(DATA_EGG_EVENT, IN_PROGRESS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnUnitDeath(Unit* unit)
|
||||
{
|
||||
//! HACK, needed because of buggy CreatureAI after charm
|
||||
if (unit->GetEntry() == NPC_RAZORGORE && GetBossState(BOSS_RAZORGORE) != DONE)
|
||||
SetBossState(BOSS_RAZORGORE, DONE);
|
||||
}
|
||||
|
||||
void Update(uint32 diff)
|
||||
{
|
||||
if (_events.Empty())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_RAZOR_SPAWN:
|
||||
for (uint8 i = urand(2, 5); i > 0 ; --i)
|
||||
if (Creature* summon = instance->SummonCreature(Entry[urand(0, 4)], SummonPosition[urand(0, 7)]))
|
||||
summon->SetInCombatWithZone();
|
||||
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, urand(12, 17)*IN_MILLISECONDS);
|
||||
break;
|
||||
case EVENT_RAZOR_PHASE_TWO:
|
||||
_events.CancelEvent(EVENT_RAZOR_SPAWN);
|
||||
if (Creature* razor = instance->GetCreature(RazorgoreTheUntamedGUID))
|
||||
razor->AI()->DoAction(ACTION_PHASE_TWO);
|
||||
break;
|
||||
case EVENT_RESPAWN_NEFARIUS:
|
||||
if (Creature* nefarius = instance->GetCreature(LordVictorNefariusGUID))
|
||||
{
|
||||
nefarius->SetPhaseMask(1, true);
|
||||
nefarius->setActive(true);
|
||||
nefarius->Respawn();
|
||||
nefarius->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// Misc
|
||||
EventMap _events;
|
||||
// Razorgore
|
||||
uint8 EggCount;
|
||||
uint32 EggEvent;
|
||||
uint64 RazorgoreTheUntamedGUID;
|
||||
uint64 RazorgoreDoorGUID;
|
||||
std::list<uint64> EggList;
|
||||
|
||||
// Vaelastrasz the Corrupt
|
||||
uint64 VaelastraszTheCorruptGUID;
|
||||
uint64 VaelastraszDoorGUID;
|
||||
|
||||
// Broodlord Lashlayer
|
||||
uint64 BroodlordLashlayerGUID;
|
||||
uint64 BroodlordDoorGUID;
|
||||
|
||||
// 3 Dragons
|
||||
uint64 FiremawGUID;
|
||||
uint64 EbonrocGUID;
|
||||
uint64 FlamegorGUID;
|
||||
uint64 ChrommagusDoorGUID;
|
||||
|
||||
// Chormaggus
|
||||
uint64 ChromaggusGUID;
|
||||
uint64 NefarianDoorGUID;
|
||||
|
||||
// Nefarian
|
||||
uint64 LordVictorNefariusGUID;
|
||||
uint64 NefarianGUID;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const
|
||||
{
|
||||
return new instance_blackwing_lair_InstanceMapScript(map);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_blackwing_lair()
|
||||
{
|
||||
new instance_blackwing_lair();
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Baron_Geddon
|
||||
SD%Complete: 100
|
||||
SDComment:
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Emotes
|
||||
{
|
||||
EMOTE_SERVICE = 0
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_INFERNO = 19695,
|
||||
SPELL_IGNITE_MANA = 19659,
|
||||
SPELL_LIVING_BOMB = 20475,
|
||||
SPELL_ARMAGEDDON = 20479,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_INFERNO = 1,
|
||||
EVENT_IGNITE_MANA = 2,
|
||||
EVENT_LIVING_BOMB = 3,
|
||||
};
|
||||
|
||||
class boss_baron_geddon : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_baron_geddon() : CreatureScript("boss_baron_geddon") { }
|
||||
|
||||
struct boss_baron_geddonAI : public BossAI
|
||||
{
|
||||
boss_baron_geddonAI(Creature* creature) : BossAI(creature, BOSS_BARON_GEDDON)
|
||||
{
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
BossAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_INFERNO, 45000);
|
||||
events.ScheduleEvent(EVENT_IGNITE_MANA, 30000);
|
||||
events.ScheduleEvent(EVENT_LIVING_BOMB, 35000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
// If we are <2% hp cast Armageddon
|
||||
if (!HealthAbovePct(2))
|
||||
{
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
DoCast(me, SPELL_ARMAGEDDON);
|
||||
Talk(EMOTE_SERVICE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_INFERNO:
|
||||
DoCast(me, SPELL_INFERNO);
|
||||
events.ScheduleEvent(EVENT_INFERNO, 45000);
|
||||
break;
|
||||
case EVENT_IGNITE_MANA:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_IGNITE_MANA))
|
||||
DoCast(target, SPELL_IGNITE_MANA);
|
||||
events.ScheduleEvent(EVENT_IGNITE_MANA, 30000);
|
||||
break;
|
||||
case EVENT_LIVING_BOMB:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
|
||||
DoCast(target, SPELL_LIVING_BOMB);
|
||||
events.ScheduleEvent(EVENT_LIVING_BOMB, 35000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_baron_geddonAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_baron_geddon()
|
||||
{
|
||||
new boss_baron_geddon();
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Garr
|
||||
SD%Complete: 50
|
||||
SDComment: Adds NYI
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// Garr
|
||||
SPELL_ANTIMAGIC_PULSE = 19492,
|
||||
SPELL_MAGMA_SHACKLES = 19496,
|
||||
SPELL_ENRAGE = 19516,
|
||||
|
||||
// Adds
|
||||
SPELL_ERUPTION = 19497,
|
||||
SPELL_IMMOLATE = 20294,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_ANTIMAGIC_PULSE = 1,
|
||||
EVENT_MAGMA_SHACKLES = 2,
|
||||
};
|
||||
|
||||
class boss_garr : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_garr() : CreatureScript("boss_garr") { }
|
||||
|
||||
struct boss_garrAI : public BossAI
|
||||
{
|
||||
boss_garrAI(Creature* creature) : BossAI(creature, BOSS_GARR)
|
||||
{
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
BossAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_ANTIMAGIC_PULSE, 25000);
|
||||
events.ScheduleEvent(EVENT_MAGMA_SHACKLES, 15000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ANTIMAGIC_PULSE:
|
||||
DoCast(me, SPELL_ANTIMAGIC_PULSE);
|
||||
events.ScheduleEvent(EVENT_ANTIMAGIC_PULSE, urand(10000, 15000));
|
||||
break;
|
||||
case EVENT_MAGMA_SHACKLES:
|
||||
DoCast(me, SPELL_MAGMA_SHACKLES);
|
||||
events.ScheduleEvent(EVENT_MAGMA_SHACKLES, urand(8000, 12000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_garrAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_firesworn : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_firesworn() : CreatureScript("npc_firesworn") { }
|
||||
|
||||
struct npc_fireswornAI : public ScriptedAI
|
||||
{
|
||||
npc_fireswornAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 immolateTimer;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
immolateTimer = 4000; //These times are probably wrong
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask)
|
||||
{
|
||||
uint32 const health10pct = me->CountPctFromMaxHealth(10);
|
||||
uint32 health = me->GetHealth();
|
||||
if (int32(health) - int32(damage) < int32(health10pct))
|
||||
{
|
||||
damage = 0;
|
||||
DoCastVictim(SPELL_ERUPTION);
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (immolateTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target, SPELL_IMMOLATE);
|
||||
immolateTimer = urand(5000, 10000);
|
||||
}
|
||||
else
|
||||
immolateTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new npc_fireswornAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_garr()
|
||||
{
|
||||
new boss_garr();
|
||||
new npc_firesworn();
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Gehennas
|
||||
SD%Complete: 90
|
||||
SDComment: Adds MC NYI
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_GEHENNAS_CURSE = 19716,
|
||||
SPELL_RAIN_OF_FIRE = 19717,
|
||||
SPELL_SHADOW_BOLT = 19728,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_GEHENNAS_CURSE = 1,
|
||||
EVENT_RAIN_OF_FIRE = 2,
|
||||
EVENT_SHADOW_BOLT = 3,
|
||||
};
|
||||
|
||||
class boss_gehennas : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_gehennas() : CreatureScript("boss_gehennas") { }
|
||||
|
||||
struct boss_gehennasAI : public BossAI
|
||||
{
|
||||
boss_gehennasAI(Creature* creature) : BossAI(creature, BOSS_GEHENNAS)
|
||||
{
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
BossAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_GEHENNAS_CURSE, 12000);
|
||||
events.ScheduleEvent(EVENT_RAIN_OF_FIRE, 10000);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 6000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_GEHENNAS_CURSE:
|
||||
DoCastVictim(SPELL_GEHENNAS_CURSE);
|
||||
events.ScheduleEvent(EVENT_GEHENNAS_CURSE, urand(22000, 30000));
|
||||
break;
|
||||
case EVENT_RAIN_OF_FIRE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target, SPELL_RAIN_OF_FIRE);
|
||||
events.ScheduleEvent(EVENT_RAIN_OF_FIRE, urand(4000, 12000));
|
||||
break;
|
||||
case EVENT_SHADOW_BOLT:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
|
||||
DoCast(target, SPELL_SHADOW_BOLT);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 7000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_gehennasAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_gehennas()
|
||||
{
|
||||
new boss_gehennas();
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Golemagg
|
||||
SD%Complete: 90
|
||||
SDComment: Timers need to be confirmed, Golemagg's Trust need to be checked
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Texts
|
||||
{
|
||||
EMOTE_LOWHP = 0,
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// Golemagg
|
||||
SPELL_MAGMASPLASH = 13879,
|
||||
SPELL_PYROBLAST = 20228,
|
||||
SPELL_EARTHQUAKE = 19798,
|
||||
SPELL_ENRAGE = 19953,
|
||||
SPELL_GOLEMAGG_TRUST = 20553,
|
||||
|
||||
// Core Rager
|
||||
SPELL_MANGLE = 19820
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_PYROBLAST = 1,
|
||||
EVENT_EARTHQUAKE = 2,
|
||||
};
|
||||
|
||||
class boss_golemagg : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_golemagg() : CreatureScript("boss_golemagg") { }
|
||||
|
||||
struct boss_golemaggAI : public BossAI
|
||||
{
|
||||
boss_golemaggAI(Creature* creature) : BossAI(creature, BOSS_GOLEMAGG_THE_INCINERATOR)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
BossAI::Reset();
|
||||
DoCast(me, SPELL_MAGMASPLASH, true);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
BossAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_PYROBLAST, 7000);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask)
|
||||
{
|
||||
if (!HealthBelowPct(10) || me->HasAura(SPELL_ENRAGE))
|
||||
return;
|
||||
|
||||
DoCast(me, SPELL_ENRAGE, true);
|
||||
events.ScheduleEvent(EVENT_EARTHQUAKE, 3000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_PYROBLAST:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target, SPELL_PYROBLAST);
|
||||
events.ScheduleEvent(EVENT_PYROBLAST, 7000);
|
||||
break;
|
||||
case EVENT_EARTHQUAKE:
|
||||
DoCastVictim(SPELL_EARTHQUAKE);
|
||||
events.ScheduleEvent(EVENT_EARTHQUAKE, 3000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_golemaggAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_core_rager : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_core_rager() : CreatureScript("npc_core_rager") { }
|
||||
|
||||
struct npc_core_ragerAI : public ScriptedAI
|
||||
{
|
||||
npc_core_ragerAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
mangleTimer = 7*IN_MILLISECONDS; // These times are probably wrong
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask)
|
||||
{
|
||||
if (HealthAbovePct(50) || !instance)
|
||||
return;
|
||||
|
||||
if (Creature* pGolemagg = instance->instance->GetCreature(instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR)))
|
||||
{
|
||||
if (pGolemagg->IsAlive())
|
||||
{
|
||||
me->AddAura(SPELL_GOLEMAGG_TRUST, me);
|
||||
Talk(EMOTE_LOWHP);
|
||||
me->SetFullHealth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
// Mangle
|
||||
if (mangleTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_MANGLE);
|
||||
mangleTimer = 10*IN_MILLISECONDS;
|
||||
}
|
||||
else
|
||||
mangleTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
InstanceScript* instance;
|
||||
uint32 mangleTimer;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<npc_core_ragerAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_golemagg()
|
||||
{
|
||||
new boss_golemagg();
|
||||
new npc_core_rager();
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Lucifron
|
||||
SD%Complete: 100
|
||||
SDComment:
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_IMPENDING_DOOM = 19702,
|
||||
SPELL_LUCIFRON_CURSE = 19703,
|
||||
SPELL_SHADOW_SHOCK = 20603,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_IMPENDING_DOOM = 1,
|
||||
EVENT_LUCIFRON_CURSE = 2,
|
||||
EVENT_SHADOW_SHOCK = 3,
|
||||
};
|
||||
|
||||
class boss_lucifron : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_lucifron() : CreatureScript("boss_lucifron") { }
|
||||
|
||||
struct boss_lucifronAI : public BossAI
|
||||
{
|
||||
boss_lucifronAI(Creature* creature) : BossAI(creature, BOSS_LUCIFRON)
|
||||
{
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
BossAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_IMPENDING_DOOM, 10000);
|
||||
events.ScheduleEvent(EVENT_LUCIFRON_CURSE, 20000);
|
||||
events.ScheduleEvent(EVENT_SHADOW_SHOCK, 6000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_IMPENDING_DOOM:
|
||||
DoCastVictim(SPELL_IMPENDING_DOOM);
|
||||
events.ScheduleEvent(EVENT_IMPENDING_DOOM, 20000);
|
||||
break;
|
||||
case EVENT_LUCIFRON_CURSE:
|
||||
DoCastVictim(SPELL_LUCIFRON_CURSE);
|
||||
events.ScheduleEvent(EVENT_LUCIFRON_CURSE, 15000);
|
||||
break;
|
||||
case EVENT_SHADOW_SHOCK:
|
||||
DoCastVictim(SPELL_SHADOW_SHOCK);
|
||||
events.ScheduleEvent(EVENT_SHADOW_SHOCK, 6000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_lucifronAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_lucifron()
|
||||
{
|
||||
new boss_lucifron();
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Magmadar
|
||||
SD%Complete: 75
|
||||
SDComment: Conflag on ground nyi
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Texts
|
||||
{
|
||||
EMOTE_FRENZY = 0
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FRENZY = 19451,
|
||||
SPELL_MAGMA_SPIT = 19449,
|
||||
SPELL_PANIC = 19408,
|
||||
SPELL_LAVA_BOMB = 19428,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_FRENZY = 1,
|
||||
EVENT_PANIC = 2,
|
||||
EVENT_LAVA_BOMB = 3,
|
||||
};
|
||||
|
||||
class boss_magmadar : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_magmadar() : CreatureScript("boss_magmadar") { }
|
||||
|
||||
struct boss_magmadarAI : public BossAI
|
||||
{
|
||||
boss_magmadarAI(Creature* creature) : BossAI(creature, BOSS_MAGMADAR)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
BossAI::Reset();
|
||||
DoCast(me, SPELL_MAGMA_SPIT, true);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
BossAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_FRENZY, 30000);
|
||||
events.ScheduleEvent(EVENT_PANIC, 20000);
|
||||
events.ScheduleEvent(EVENT_LAVA_BOMB, 12000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_FRENZY:
|
||||
Talk(EMOTE_FRENZY);
|
||||
DoCast(me, SPELL_FRENZY);
|
||||
events.ScheduleEvent(EVENT_FRENZY, 15000);
|
||||
break;
|
||||
case EVENT_PANIC:
|
||||
DoCastVictim(SPELL_PANIC);
|
||||
events.ScheduleEvent(EVENT_PANIC, 35000);
|
||||
break;
|
||||
case EVENT_LAVA_BOMB:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_LAVA_BOMB))
|
||||
DoCast(target, SPELL_LAVA_BOMB);
|
||||
events.ScheduleEvent(EVENT_LAVA_BOMB, 12000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_magmadarAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_magmadar()
|
||||
{
|
||||
new boss_magmadar();
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Majordomo_Executus
|
||||
SD%Complete: 30
|
||||
SDComment: Correct spawning and Event NYI
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "molten_core.h"
|
||||
#include "Player.h"
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SPAWN = 1,
|
||||
SAY_SLAY = 2,
|
||||
SAY_SPECIAL = 3,
|
||||
SAY_DEFEAT = 4,
|
||||
|
||||
SAY_SUMMON_MAJ = 5,
|
||||
SAY_ARRIVAL2_MAJ = 6
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_MAGIC_REFLECTION = 20619,
|
||||
SPELL_DAMAGE_REFLECTION = 21075,
|
||||
SPELL_BLAST_WAVE = 20229,
|
||||
SPELL_AEGIS_OF_RAGNAROS = 20620,
|
||||
SPELL_TELEPORT = 20618,
|
||||
SPELL_SUMMON_RAGNAROS = 19774,
|
||||
};
|
||||
|
||||
#define GOSSIP_HELLO 4995
|
||||
#define GOSSIP_SELECT "Tell me more."
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_MAGIC_REFLECTION = 1,
|
||||
EVENT_DAMAGE_REFLECTION = 2,
|
||||
EVENT_BLAST_WAVE = 3,
|
||||
EVENT_TELEPORT = 4,
|
||||
|
||||
EVENT_OUTRO_1 = 5,
|
||||
EVENT_OUTRO_2 = 6,
|
||||
EVENT_OUTRO_3 = 7,
|
||||
};
|
||||
|
||||
class boss_majordomo : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_majordomo() : CreatureScript("boss_majordomo") { }
|
||||
|
||||
struct boss_majordomoAI : public BossAI
|
||||
{
|
||||
boss_majordomoAI(Creature* creature) : BossAI(creature, BOSS_MAJORDOMO_EXECUTUS)
|
||||
{
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
if (urand(0, 99) < 25)
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who)
|
||||
{
|
||||
BossAI::EnterCombat(who);
|
||||
Talk(SAY_AGGRO);
|
||||
events.ScheduleEvent(EVENT_MAGIC_REFLECTION, 30000);
|
||||
events.ScheduleEvent(EVENT_DAMAGE_REFLECTION, 15000);
|
||||
events.ScheduleEvent(EVENT_BLAST_WAVE, 10000);
|
||||
events.ScheduleEvent(EVENT_TELEPORT, 20000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (instance->GetBossState(BOSS_MAJORDOMO_EXECUTUS) != DONE)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (!me->FindNearestCreature(NPC_FLAMEWAKER_HEALER, 100.0f) && !me->FindNearestCreature(NPC_FLAMEWAKER_ELITE, 100.0f))
|
||||
{
|
||||
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry(), me);
|
||||
me->setFaction(35);
|
||||
EnterEvadeMode();
|
||||
Talk(SAY_DEFEAT);
|
||||
_JustDied();
|
||||
events.ScheduleEvent(EVENT_OUTRO_1, 32000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
if (HealthBelowPct(50))
|
||||
DoCast(me, SPELL_AEGIS_OF_RAGNAROS, true);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_MAGIC_REFLECTION:
|
||||
DoCast(me, SPELL_MAGIC_REFLECTION);
|
||||
events.ScheduleEvent(EVENT_MAGIC_REFLECTION, 30000);
|
||||
break;
|
||||
case EVENT_DAMAGE_REFLECTION:
|
||||
DoCast(me, SPELL_DAMAGE_REFLECTION);
|
||||
events.ScheduleEvent(EVENT_DAMAGE_REFLECTION, 30000);
|
||||
break;
|
||||
case EVENT_BLAST_WAVE:
|
||||
DoCastVictim(SPELL_BLAST_WAVE);
|
||||
events.ScheduleEvent(EVENT_BLAST_WAVE, 10000);
|
||||
break;
|
||||
case EVENT_TELEPORT:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
|
||||
DoCast(target, SPELL_TELEPORT);
|
||||
events.ScheduleEvent(EVENT_TELEPORT, 20000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
else
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_OUTRO_1:
|
||||
me->NearTeleportTo(RagnarosTelePos.GetPositionX(), RagnarosTelePos.GetPositionY(), RagnarosTelePos.GetPositionZ(), RagnarosTelePos.GetOrientation());
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
break;
|
||||
case EVENT_OUTRO_2:
|
||||
instance->instance->SummonCreature(NPC_RAGNAROS, RagnarosSummonPos);
|
||||
break;
|
||||
case EVENT_OUTRO_3:
|
||||
Talk(SAY_ARRIVAL2_MAJ);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 action)
|
||||
{
|
||||
if (action == ACTION_START_RAGNAROS && events.GetNextEventTime(EVENT_OUTRO_2) == 0)
|
||||
{
|
||||
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
Talk(SAY_SUMMON_MAJ);
|
||||
events.ScheduleEvent(EVENT_OUTRO_2, 8000);
|
||||
events.ScheduleEvent(EVENT_OUTRO_3, 24000);
|
||||
}
|
||||
else if (action == ACTION_START_RAGNAROS_ALT)
|
||||
{
|
||||
me->setFaction(35);
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature)
|
||||
{
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
|
||||
player->SEND_GOSSIP_MENU(GOSSIP_HELLO, creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 /*action*/)
|
||||
{
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
creature->AI()->DoAction(ACTION_START_RAGNAROS);
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_majordomoAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_majordomo()
|
||||
{
|
||||
new boss_majordomo();
|
||||
}
|
||||
@@ -1,354 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Ragnaros
|
||||
SD%Complete: 95
|
||||
SDComment: some spells doesnt work correctly
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_SUMMON_MAJ = 0,
|
||||
SAY_ARRIVAL1_RAG = 1,
|
||||
SAY_ARRIVAL2_MAJ = 2,
|
||||
SAY_ARRIVAL3_RAG = 3,
|
||||
SAY_ARRIVAL5_RAG = 4,
|
||||
SAY_REINFORCEMENTS1 = 5,
|
||||
SAY_REINFORCEMENTS2 = 6,
|
||||
SAY_HAND = 7,
|
||||
SAY_WRATH = 8,
|
||||
SAY_KILL = 9,
|
||||
SAY_MAGMABURST = 10
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_HAND_OF_RAGNAROS = 19780,
|
||||
SPELL_WRATH_OF_RAGNAROS = 20566,
|
||||
SPELL_LAVA_BURST = 21158,
|
||||
SPELL_MAGMA_BLAST = 20565, // Ranged attack
|
||||
SPELL_SONS_OF_FLAME_DUMMY = 21108, // Server side effect
|
||||
SPELL_RAGSUBMERGE = 21107, // Stealth aura
|
||||
SPELL_RAGEMERGE = 20568,
|
||||
SPELL_MELT_WEAPON = 21388,
|
||||
SPELL_ELEMENTAL_FIRE = 20564,
|
||||
SPELL_ERRUPTION = 17731
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_ERUPTION = 1,
|
||||
EVENT_WRATH_OF_RAGNAROS = 2,
|
||||
EVENT_HAND_OF_RAGNAROS = 3,
|
||||
EVENT_LAVA_BURST = 4,
|
||||
EVENT_ELEMENTAL_FIRE = 5,
|
||||
EVENT_MAGMA_BLAST = 6,
|
||||
EVENT_SUBMERGE = 7,
|
||||
|
||||
EVENT_INTRO_1 = 8,
|
||||
EVENT_INTRO_2 = 9,
|
||||
EVENT_INTRO_3 = 10,
|
||||
EVENT_INTRO_4 = 11,
|
||||
EVENT_INTRO_5 = 12
|
||||
};
|
||||
|
||||
class boss_ragnaros : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_ragnaros() : CreatureScript("boss_ragnaros") { }
|
||||
|
||||
struct boss_ragnarosAI : public BossAI
|
||||
{
|
||||
boss_ragnarosAI(Creature* creature) : BossAI(creature, BOSS_RAGNAROS)
|
||||
{
|
||||
_introState = 0;
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
BossAI::Reset();
|
||||
_emergeTimer = 90000;
|
||||
_hasYelledMagmaBurst = false;
|
||||
_hasSubmergedOnce = false;
|
||||
_isBanished = false;
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
BossAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_ERUPTION, 15000);
|
||||
events.ScheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30000);
|
||||
events.ScheduleEvent(EVENT_HAND_OF_RAGNAROS, 25000);
|
||||
events.ScheduleEvent(EVENT_LAVA_BURST, 10000);
|
||||
events.ScheduleEvent(EVENT_ELEMENTAL_FIRE, 3000);
|
||||
events.ScheduleEvent(EVENT_MAGMA_BLAST, 2000);
|
||||
events.ScheduleEvent(EVENT_SUBMERGE, 180000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
if (urand(0, 99) < 25)
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* target)
|
||||
{
|
||||
if (target && me->Attack(target, true))
|
||||
DoStartNoMovement(target);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (_introState != 2)
|
||||
{
|
||||
if (!_introState)
|
||||
{
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
|
||||
events.ScheduleEvent(EVENT_INTRO_1, 4000);
|
||||
events.ScheduleEvent(EVENT_INTRO_2, 23000);
|
||||
events.ScheduleEvent(EVENT_INTRO_3, 42000);
|
||||
events.ScheduleEvent(EVENT_INTRO_4, 43000);
|
||||
events.ScheduleEvent(EVENT_INTRO_5, 53000);
|
||||
_introState = 1;
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_INTRO_1:
|
||||
Talk(SAY_ARRIVAL1_RAG);
|
||||
break;
|
||||
case EVENT_INTRO_2:
|
||||
Talk(SAY_ARRIVAL3_RAG);
|
||||
break;
|
||||
case EVENT_INTRO_3:
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H);
|
||||
break;
|
||||
case EVENT_INTRO_4:
|
||||
Talk(SAY_ARRIVAL5_RAG);
|
||||
if (Creature* executus = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MAJORDOMO_EXECUTUS)))
|
||||
Unit::Kill(me, executus);
|
||||
break;
|
||||
case EVENT_INTRO_5:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
_introState = 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_isBanished && ((_emergeTimer <= diff) || (instance->GetData(DATA_RAGNAROS_ADDS)) > 8))
|
||||
{
|
||||
//Become unbanished again
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->setFaction(14);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
AttackStart(target);
|
||||
instance->SetData(DATA_RAGNAROS_ADDS, 0);
|
||||
|
||||
//DoCast(me, SPELL_RAGEMERGE); //"phase spells" didnt worked correctly so Ive commented them and wrote solution witch doesnt need core support
|
||||
_isBanished = false;
|
||||
}
|
||||
else if (_isBanished)
|
||||
{
|
||||
_emergeTimer -= diff;
|
||||
//Do nothing while banished
|
||||
return;
|
||||
}
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ERUPTION:
|
||||
DoCastVictim(SPELL_ERRUPTION);
|
||||
events.ScheduleEvent(EVENT_ERUPTION, urand(20000, 45000));
|
||||
break;
|
||||
case EVENT_WRATH_OF_RAGNAROS:
|
||||
DoCastVictim(SPELL_WRATH_OF_RAGNAROS);
|
||||
if (urand(0, 1))
|
||||
Talk(SAY_WRATH);
|
||||
events.ScheduleEvent(EVENT_WRATH_OF_RAGNAROS, 25000);
|
||||
break;
|
||||
case EVENT_HAND_OF_RAGNAROS:
|
||||
DoCast(me, SPELL_HAND_OF_RAGNAROS);
|
||||
if (urand(0, 1))
|
||||
Talk(SAY_HAND);
|
||||
events.ScheduleEvent(EVENT_HAND_OF_RAGNAROS, 20000);
|
||||
break;
|
||||
case EVENT_LAVA_BURST:
|
||||
DoCastVictim(SPELL_LAVA_BURST);
|
||||
events.ScheduleEvent(EVENT_LAVA_BURST, 10000);
|
||||
break;
|
||||
case EVENT_ELEMENTAL_FIRE:
|
||||
DoCastVictim(SPELL_ELEMENTAL_FIRE);
|
||||
events.ScheduleEvent(EVENT_ELEMENTAL_FIRE, urand(10000, 14000));
|
||||
break;
|
||||
case EVENT_MAGMA_BLAST:
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
DoCastVictim(SPELL_MAGMA_BLAST);
|
||||
if (!_hasYelledMagmaBurst)
|
||||
{
|
||||
//Say our dialog
|
||||
Talk(SAY_MAGMABURST);
|
||||
_hasYelledMagmaBurst = true;
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAGMA_BLAST, 2500);
|
||||
break;
|
||||
case EVENT_SUBMERGE:
|
||||
{
|
||||
if (!_isBanished)
|
||||
{
|
||||
//Creature spawning and ragnaros becomming unattackable
|
||||
//is not very well supported in the core //no it really isnt
|
||||
//so added normaly spawning and banish workaround and attack again after 90 secs.
|
||||
me->AttackStop();
|
||||
DoResetThreat();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
//Root self
|
||||
//DoCast(me, 23973);
|
||||
me->setFaction(35);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
|
||||
instance->SetData(DATA_RAGNAROS_ADDS, 0);
|
||||
|
||||
if (!_hasSubmergedOnce)
|
||||
{
|
||||
Talk(SAY_REINFORCEMENTS1);
|
||||
|
||||
// summon 8 elementals
|
||||
for (uint8 i = 0; i < 8; ++i)
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
if (Creature* summoned = me->SummonCreature(12143, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 900000))
|
||||
summoned->AI()->AttackStart(target);
|
||||
|
||||
_hasSubmergedOnce = true;
|
||||
_isBanished = true;
|
||||
//DoCast(me, SPELL_RAGSUBMERGE);
|
||||
_emergeTimer = 90000;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Talk(SAY_REINFORCEMENTS2);
|
||||
|
||||
for (uint8 i = 0; i < 8; ++i)
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
if (Creature* summoned = me->SummonCreature(12143, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 900000))
|
||||
summoned->AI()->AttackStart(target);
|
||||
|
||||
_isBanished = true;
|
||||
//DoCast(me, SPELL_RAGSUBMERGE);
|
||||
_emergeTimer = 90000;
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_SUBMERGE, 180000);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _emergeTimer;
|
||||
uint8 _introState;
|
||||
bool _hasYelledMagmaBurst;
|
||||
bool _hasSubmergedOnce;
|
||||
bool _isBanished;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_ragnarosAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_son_of_flame : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_son_of_flame() : CreatureScript("npc_SonOfFlame") { }
|
||||
|
||||
struct npc_son_of_flameAI : public ScriptedAI //didnt work correctly in EAI for me...
|
||||
{
|
||||
npc_son_of_flameAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = me->GetInstanceScript();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
instance->SetData(DATA_RAGNAROS_ADDS, 1);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
InstanceScript* instance;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<npc_son_of_flameAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_ragnaros()
|
||||
{
|
||||
new boss_ragnaros();
|
||||
new npc_son_of_flame();
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_ARCANE_EXPLOSION = 19712,
|
||||
SPELL_SHAZZRAH_CURSE = 19713,
|
||||
SPELL_MAGIC_GROUNDING = 19714,
|
||||
SPELL_COUNTERSPELL = 19715,
|
||||
SPELL_SHAZZRAH_GATE_DUMMY = 23138, // Teleports to and attacks a random target.
|
||||
SPELL_SHAZZRAH_GATE = 23139,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_ARCANE_EXPLOSION = 1,
|
||||
EVENT_ARCANE_EXPLOSION_TRIGGERED = 2,
|
||||
EVENT_SHAZZRAH_CURSE = 3,
|
||||
EVENT_MAGIC_GROUNDING = 4,
|
||||
EVENT_COUNTERSPELL = 5,
|
||||
EVENT_SHAZZRAH_GATE = 6,
|
||||
};
|
||||
|
||||
class boss_shazzrah : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_shazzrah() : CreatureScript("boss_shazzrah") { }
|
||||
|
||||
struct boss_shazzrahAI : public BossAI
|
||||
{
|
||||
boss_shazzrahAI(Creature* creature) : BossAI(creature, BOSS_SHAZZRAH) { }
|
||||
|
||||
void EnterCombat(Unit* target)
|
||||
{
|
||||
BossAI::EnterCombat(target);
|
||||
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 6000);
|
||||
events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, 10000);
|
||||
events.ScheduleEvent(EVENT_MAGIC_GROUNDING, 24000);
|
||||
events.ScheduleEvent(EVENT_COUNTERSPELL, 15000);
|
||||
events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 45000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ARCANE_EXPLOSION:
|
||||
DoCastVictim(SPELL_ARCANE_EXPLOSION);
|
||||
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(4000, 7000));
|
||||
break;
|
||||
// Triggered subsequent to using "Gate of Shazzrah".
|
||||
case EVENT_ARCANE_EXPLOSION_TRIGGERED:
|
||||
DoCastVictim(SPELL_ARCANE_EXPLOSION);
|
||||
break;
|
||||
case EVENT_SHAZZRAH_CURSE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_SHAZZRAH_CURSE))
|
||||
DoCast(target, SPELL_SHAZZRAH_CURSE);
|
||||
events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, urand(25000, 30000));
|
||||
break;
|
||||
case EVENT_MAGIC_GROUNDING:
|
||||
DoCast(me, SPELL_MAGIC_GROUNDING);
|
||||
events.ScheduleEvent(EVENT_MAGIC_GROUNDING, 35000);
|
||||
break;
|
||||
case EVENT_COUNTERSPELL:
|
||||
DoCastVictim(SPELL_COUNTERSPELL);
|
||||
events.ScheduleEvent(EVENT_COUNTERSPELL, urand(16000, 20000));
|
||||
break;
|
||||
case EVENT_SHAZZRAH_GATE:
|
||||
DoResetThreat();
|
||||
DoCastAOE(SPELL_SHAZZRAH_GATE_DUMMY);
|
||||
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION_TRIGGERED, 2000);
|
||||
events.RescheduleEvent(EVENT_ARCANE_EXPLOSION, urand(3000, 6000));
|
||||
events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 45000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_shazzrahAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 23138 - Gate of Shazzrah
|
||||
class spell_shazzrah_gate_dummy : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_shazzrah_gate_dummy() : SpellScriptLoader("spell_shazzrah_gate_dummy") { }
|
||||
|
||||
class spell_shazzrah_gate_dummy_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_shazzrah_gate_dummy_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/)
|
||||
{
|
||||
if (!sSpellMgr->GetSpellInfo(SPELL_SHAZZRAH_GATE))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
if (targets.empty())
|
||||
return;
|
||||
|
||||
WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
|
||||
targets.clear();
|
||||
targets.push_back(target);
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
target->CastSpell(GetCaster(), SPELL_SHAZZRAH_GATE, true);
|
||||
if (Creature* creature = GetCaster()->ToCreature())
|
||||
creature->AI()->AttackStart(target); // Attack the target which caster will teleport to.
|
||||
}
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_shazzrah_gate_dummy_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_shazzrah_gate_dummy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const
|
||||
{
|
||||
return new spell_shazzrah_gate_dummy_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_shazzrah()
|
||||
{
|
||||
new boss_shazzrah();
|
||||
new spell_shazzrah_gate_dummy();
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Sulfuron_Harbringer
|
||||
SD%Complete: 80
|
||||
SDComment: Adds NYI
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "molten_core.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// Sulfuron Harbringer
|
||||
SPELL_DARK_STRIKE = 19777,
|
||||
SPELL_DEMORALIZING_SHOUT = 19778,
|
||||
SPELL_INSPIRE = 19779,
|
||||
SPELL_KNOCKDOWN = 19780,
|
||||
SPELL_FLAMESPEAR = 19781,
|
||||
|
||||
// Adds
|
||||
SPELL_HEAL = 19775,
|
||||
SPELL_SHADOWWORDPAIN = 19776,
|
||||
SPELL_IMMOLATE = 20294,
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_DARK_STRIKE = 1,
|
||||
EVENT_DEMORALIZING_SHOUT = 2,
|
||||
EVENT_INSPIRE = 3,
|
||||
EVENT_KNOCKDOWN = 4,
|
||||
EVENT_FLAMESPEAR = 5,
|
||||
|
||||
EVENT_HEAL = 6,
|
||||
EVENT_SHADOW_WORD_PAIN = 7,
|
||||
EVENT_IMMOLATE = 8,
|
||||
};
|
||||
|
||||
class boss_sulfuron : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_sulfuron() : CreatureScript("boss_sulfuron") { }
|
||||
|
||||
struct boss_sulfuronAI : public BossAI
|
||||
{
|
||||
boss_sulfuronAI(Creature* creature) : BossAI(creature, BOSS_SULFURON_HARBINGER)
|
||||
{
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
BossAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_DARK_STRIKE, 10000);
|
||||
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 15000);
|
||||
events.ScheduleEvent(EVENT_INSPIRE, 13000);
|
||||
events.ScheduleEvent(EVENT_KNOCKDOWN, 6000);
|
||||
events.ScheduleEvent(EVENT_FLAMESPEAR, 2000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_DARK_STRIKE:
|
||||
DoCast(me, SPELL_DARK_STRIKE);
|
||||
events.ScheduleEvent(EVENT_DARK_STRIKE, urand(15000, 18000));
|
||||
break;
|
||||
case EVENT_DEMORALIZING_SHOUT:
|
||||
DoCastVictim(SPELL_DEMORALIZING_SHOUT);
|
||||
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, urand(15000, 20000));
|
||||
break;
|
||||
case EVENT_INSPIRE:
|
||||
{
|
||||
std::list<Creature*> healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE);
|
||||
if (!healers.empty())
|
||||
DoCast(Trinity::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE);
|
||||
|
||||
DoCast(me, SPELL_INSPIRE);
|
||||
events.ScheduleEvent(EVENT_INSPIRE, urand(20000, 26000));
|
||||
break;
|
||||
}
|
||||
case EVENT_KNOCKDOWN:
|
||||
DoCastVictim(SPELL_KNOCKDOWN);
|
||||
events.ScheduleEvent(EVENT_KNOCKDOWN, urand(12000, 15000));
|
||||
break;
|
||||
case EVENT_FLAMESPEAR:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
|
||||
DoCast(target, SPELL_FLAMESPEAR);
|
||||
events.ScheduleEvent(EVENT_FLAMESPEAR, urand(12000, 16000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_sulfuronAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_flamewaker_priest : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_flamewaker_priest() : CreatureScript("npc_flamewaker_priest") { }
|
||||
|
||||
struct npc_flamewaker_priestAI : public ScriptedAI
|
||||
{
|
||||
npc_flamewaker_priestAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
events.Reset();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
events.Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* victim)
|
||||
{
|
||||
ScriptedAI::EnterCombat(victim);
|
||||
events.ScheduleEvent(EVENT_HEAL, urand(15000, 30000));
|
||||
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 2000);
|
||||
events.ScheduleEvent(EVENT_IMMOLATE, 8000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_HEAL:
|
||||
if (Unit* target = DoSelectLowestHpFriendly(60.0f, 1))
|
||||
DoCast(target, SPELL_HEAL);
|
||||
events.ScheduleEvent(EVENT_HEAL, urand(15000, 20000));
|
||||
break;
|
||||
case EVENT_SHADOW_WORD_PAIN:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_SHADOWWORDPAIN))
|
||||
DoCast(target, SPELL_SHADOWWORDPAIN);
|
||||
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(18000, 26000));
|
||||
break;
|
||||
case EVENT_IMMOLATE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_IMMOLATE))
|
||||
DoCast(target, SPELL_IMMOLATE);
|
||||
events.ScheduleEvent(EVENT_IMMOLATE, urand(15000, 25000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new npc_flamewaker_priestAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_sulfuron()
|
||||
{
|
||||
new boss_sulfuron();
|
||||
new npc_flamewaker_priest();
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Instance_Molten_Core
|
||||
SD%Complete: 0
|
||||
SDComment: Place Holder
|
||||
SDCategory: Molten Core
|
||||
EndScriptData */
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "molten_core.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
Position const SummonPositions[10] =
|
||||
{
|
||||
{737.850f, -1145.35f, -120.288f, 4.71368f},
|
||||
{744.162f, -1151.63f, -119.726f, 4.58204f},
|
||||
{751.247f, -1152.82f, -119.744f, 4.49673f},
|
||||
{759.206f, -1155.09f, -120.051f, 4.30104f},
|
||||
{755.973f, -1152.33f, -120.029f, 4.25588f},
|
||||
{731.712f, -1147.56f, -120.195f, 4.95955f},
|
||||
{726.499f, -1149.80f, -120.156f, 5.24055f},
|
||||
{722.408f, -1152.41f, -120.029f, 5.33087f},
|
||||
{718.994f, -1156.36f, -119.805f, 5.75738f},
|
||||
{838.510f, -829.840f, -232.000f, 2.00000f},
|
||||
};
|
||||
|
||||
class instance_molten_core : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
instance_molten_core() : InstanceMapScript("instance_molten_core", 409) { }
|
||||
|
||||
struct instance_molten_core_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
instance_molten_core_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
SetBossNumber(MAX_ENCOUNTER);
|
||||
_golemaggTheIncineratorGUID = 0;
|
||||
_majordomoExecutusGUID = 0;
|
||||
_cacheOfTheFirelordGUID = 0;
|
||||
_executusSchedule = NULL;
|
||||
_deadBossCount = 0;
|
||||
_ragnarosAddDeaths = 0;
|
||||
_isLoading = false;
|
||||
_summonedExecutus = false;
|
||||
}
|
||||
|
||||
~instance_molten_core_InstanceMapScript()
|
||||
{
|
||||
delete _executusSchedule;
|
||||
}
|
||||
|
||||
void OnPlayerEnter(Player* /*player*/)
|
||||
{
|
||||
if (_executusSchedule)
|
||||
{
|
||||
SummonMajordomoExecutus(*_executusSchedule);
|
||||
delete _executusSchedule;
|
||||
_executusSchedule = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature)
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_GOLEMAGG_THE_INCINERATOR:
|
||||
_golemaggTheIncineratorGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_MAJORDOMO_EXECUTUS:
|
||||
_majordomoExecutusGUID = creature->GetGUID();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go)
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_CACHE_OF_THE_FIRELORD:
|
||||
_cacheOfTheFirelordGUID = go->GetGUID();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data)
|
||||
{
|
||||
if (type == DATA_RAGNAROS_ADDS)
|
||||
{
|
||||
if (data == 1)
|
||||
++_ragnarosAddDeaths;
|
||||
else if (data == 0)
|
||||
_ragnarosAddDeaths = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DATA_RAGNAROS_ADDS:
|
||||
return _ragnarosAddDeaths;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64 GetData64(uint32 type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BOSS_GOLEMAGG_THE_INCINERATOR:
|
||||
return _golemaggTheIncineratorGUID;
|
||||
case BOSS_MAJORDOMO_EXECUTUS:
|
||||
return _majordomoExecutusGUID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SetBossState(uint32 bossId, EncounterState state)
|
||||
{
|
||||
if (!InstanceScript::SetBossState(bossId, state))
|
||||
return false;
|
||||
|
||||
if (state == DONE && bossId < BOSS_MAJORDOMO_EXECUTUS)
|
||||
++_deadBossCount;
|
||||
|
||||
if (_isLoading)
|
||||
return true;
|
||||
|
||||
if (_deadBossCount == 8)
|
||||
SummonMajordomoExecutus(false);
|
||||
|
||||
if (bossId == BOSS_MAJORDOMO_EXECUTUS && state == DONE)
|
||||
DoRespawnGameObject(_cacheOfTheFirelordGUID, 7 * DAY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SummonMajordomoExecutus(bool done)
|
||||
{
|
||||
if (_summonedExecutus)
|
||||
return;
|
||||
|
||||
_summonedExecutus = true;
|
||||
if (!done)
|
||||
{
|
||||
instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, SummonPositions[0]);
|
||||
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[1]);
|
||||
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[2]);
|
||||
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[3]);
|
||||
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[4]);
|
||||
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[5]);
|
||||
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[6]);
|
||||
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[7]);
|
||||
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[8]);
|
||||
}
|
||||
else if (TempSummon* summon = instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, RagnarosTelePos))
|
||||
summon->AI()->DoAction(ACTION_START_RAGNAROS_ALT);
|
||||
}
|
||||
|
||||
std::string GetSaveData()
|
||||
{
|
||||
OUT_SAVE_INST_DATA;
|
||||
|
||||
std::ostringstream saveStream;
|
||||
saveStream << "M C " << GetBossSaveData();
|
||||
|
||||
OUT_SAVE_INST_DATA_COMPLETE;
|
||||
return saveStream.str();
|
||||
}
|
||||
|
||||
void Load(char const* data)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
OUT_LOAD_INST_DATA_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
_isLoading = true;
|
||||
OUT_LOAD_INST_DATA(data);
|
||||
|
||||
char dataHead1, dataHead2;
|
||||
|
||||
std::istringstream loadStream(data);
|
||||
loadStream >> dataHead1 >> dataHead2;
|
||||
|
||||
if (dataHead1 == 'M' && dataHead2 == 'C')
|
||||
{
|
||||
EncounterState states[MAX_ENCOUNTER];
|
||||
uint8 executusCounter = 0;
|
||||
|
||||
// need 2 loops to check spawning executus/ragnaros
|
||||
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
|
||||
{
|
||||
uint32 tmpState;
|
||||
loadStream >> tmpState;
|
||||
if (tmpState == IN_PROGRESS || tmpState > TO_BE_DECIDED)
|
||||
tmpState = NOT_STARTED;
|
||||
states[i] = EncounterState(tmpState);
|
||||
|
||||
if (tmpState == DONE && i < BOSS_MAJORDOMO_EXECUTUS)
|
||||
++executusCounter;
|
||||
}
|
||||
|
||||
if (executusCounter >= 8 && states[BOSS_RAGNAROS] != DONE)
|
||||
_executusSchedule = new bool(states[BOSS_MAJORDOMO_EXECUTUS] == DONE);
|
||||
|
||||
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
|
||||
SetBossState(i, states[i]);
|
||||
}
|
||||
else
|
||||
OUT_LOAD_INST_DATA_FAIL;
|
||||
|
||||
OUT_LOAD_INST_DATA_COMPLETE;
|
||||
_isLoading = false;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64 _golemaggTheIncineratorGUID;
|
||||
uint64 _majordomoExecutusGUID;
|
||||
uint64 _cacheOfTheFirelordGUID;
|
||||
bool* _executusSchedule;
|
||||
uint8 _deadBossCount;
|
||||
uint8 _ragnarosAddDeaths;
|
||||
bool _isLoading;
|
||||
bool _summonedExecutus;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const
|
||||
{
|
||||
return new instance_molten_core_InstanceMapScript(map);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_molten_core()
|
||||
{
|
||||
new instance_molten_core();
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DEF_MOLTEN_CORE_H
|
||||
#define DEF_MOLTEN_CORE_H
|
||||
|
||||
enum Encounters
|
||||
{
|
||||
BOSS_LUCIFRON = 0,
|
||||
BOSS_MAGMADAR = 1,
|
||||
BOSS_GEHENNAS = 2,
|
||||
BOSS_GARR = 3,
|
||||
BOSS_SHAZZRAH = 4,
|
||||
BOSS_BARON_GEDDON = 5,
|
||||
BOSS_SULFURON_HARBINGER = 6,
|
||||
BOSS_GOLEMAGG_THE_INCINERATOR = 7,
|
||||
BOSS_MAJORDOMO_EXECUTUS = 8,
|
||||
BOSS_RAGNAROS = 9,
|
||||
MAX_ENCOUNTER,
|
||||
};
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_START_RAGNAROS = 0,
|
||||
ACTION_START_RAGNAROS_ALT = 1,
|
||||
};
|
||||
|
||||
Position const RagnarosTelePos = {829.159f, -815.773f, -228.972f, 5.30500f};
|
||||
Position const RagnarosSummonPos = {838.510f, -829.840f, -232.000f, 2.00000f};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_LUCIFRON = 12118,
|
||||
NPC_MAGMADAR = 11982,
|
||||
NPC_GEHENNAS = 12259,
|
||||
NPC_GARR = 12057,
|
||||
NPC_SHAZZRAH = 12264,
|
||||
NPC_BARON_GEDDON = 12056,
|
||||
NPC_SULFURON_HARBINGER = 12098,
|
||||
NPC_GOLEMAGG_THE_INCINERATOR = 11988,
|
||||
NPC_MAJORDOMO_EXECUTUS = 12018,
|
||||
NPC_RAGNAROS = 11502,
|
||||
NPC_FLAMEWAKER_HEALER = 11663,
|
||||
NPC_FLAMEWAKER_ELITE = 11664,
|
||||
};
|
||||
|
||||
enum GameObjects
|
||||
{
|
||||
GO_CACHE_OF_THE_FIRELORD = 179703,
|
||||
};
|
||||
|
||||
enum Data
|
||||
{
|
||||
DATA_RAGNAROS_ADDS = 0,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,169 +0,0 @@
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
set(scripts_STAT_SRCS
|
||||
${scripts_STAT_SRCS}
|
||||
EasternKingdoms/zone_ghostlands.cpp
|
||||
EasternKingdoms/zone_eversong_woods.cpp
|
||||
EasternKingdoms/AlteracValley/boss_galvangar.cpp
|
||||
EasternKingdoms/AlteracValley/boss_balinda.cpp
|
||||
EasternKingdoms/AlteracValley/boss_drekthar.cpp
|
||||
EasternKingdoms/AlteracValley/boss_vanndar.cpp
|
||||
EasternKingdoms/AlteracValley/alterac_valley.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_gorosh_the_dervish.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_anubshiah.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_general_angerforge.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_grizzle.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_ambassador_flamelash.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_moira_bronzebeard.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.h
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_magmus.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_firemaw.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_broodlord_lashlayer.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_ebonroc.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_flamegor.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_pyroguard_emberseer.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_drakkisath.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_warmaster_voone.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_mother_smolderweb.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_quartermaster_zigris.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_halycon.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_overlord_wyrmthalak.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_shadow_hunter_voshgajin.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gyth.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_rend_blackhand.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_highlord_omokk.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_the_beast.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gizrul_the_slavener.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_urok_doomhowl.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_lord_valthalak.cpp
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h
|
||||
EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_gehennas.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_lucifron.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_garr.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_sulfuron_harbinger.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp
|
||||
EasternKingdoms/BlackrockMountain/MoltenCore/boss_shazzrah.cpp
|
||||
EasternKingdoms/Scholomance/scholomance.h
|
||||
EasternKingdoms/Scholomance/instance_scholomance.cpp
|
||||
EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp
|
||||
EasternKingdoms/zone_isle_of_queldanas.cpp
|
||||
EasternKingdoms/ZulGurub/boss_hakkar.cpp
|
||||
EasternKingdoms/ZulGurub/boss_mandokir.cpp
|
||||
EasternKingdoms/ZulGurub/boss_marli.cpp
|
||||
EasternKingdoms/ZulGurub/boss_hazzarah.cpp
|
||||
EasternKingdoms/ZulGurub/boss_jeklik.cpp
|
||||
EasternKingdoms/ZulGurub/boss_grilek.cpp
|
||||
EasternKingdoms/ZulGurub/zulgurub.h
|
||||
EasternKingdoms/ZulGurub/boss_renataki.cpp
|
||||
EasternKingdoms/ZulGurub/boss_arlokk.cpp
|
||||
EasternKingdoms/ZulGurub/boss_gahzranka.cpp
|
||||
EasternKingdoms/ZulGurub/boss_venoxis.cpp
|
||||
EasternKingdoms/ZulGurub/instance_zulgurub.cpp
|
||||
EasternKingdoms/ZulGurub/boss_jindo.cpp
|
||||
EasternKingdoms/ZulGurub/boss_wushoolay.cpp
|
||||
EasternKingdoms/ZulGurub/boss_thekal.cpp
|
||||
EasternKingdoms/zone_wetlands.cpp
|
||||
EasternKingdoms/zone_arathi_highlands.cpp
|
||||
EasternKingdoms/Gnomeregan/instance_gnomeregan.cpp
|
||||
EasternKingdoms/zone_redridge_mountains.cpp
|
||||
EasternKingdoms/zone_ironforge.cpp
|
||||
EasternKingdoms/ScarletEnclave/chapter2.cpp
|
||||
EasternKingdoms/ScarletEnclave/chapter5.cpp
|
||||
EasternKingdoms/ScarletEnclave/chapter1.cpp
|
||||
EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp
|
||||
EasternKingdoms/zone_eastern_plaguelands.cpp
|
||||
EasternKingdoms/Stratholme/instance_stratholme.cpp
|
||||
EasternKingdoms/Stratholme/stratholme.h
|
||||
EasternKingdoms/zone_tirisfal_glades.cpp
|
||||
EasternKingdoms/SunkenTemple/sunken_temple.h
|
||||
EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp
|
||||
EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
|
||||
EasternKingdoms/MagistersTerrace/magisters_terrace.h
|
||||
EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp
|
||||
EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp
|
||||
EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp
|
||||
EasternKingdoms/MagistersTerrace/boss_vexallus.cpp
|
||||
EasternKingdoms/Uldaman/uldaman.h
|
||||
EasternKingdoms/Uldaman/instance_uldaman.cpp
|
||||
EasternKingdoms/zone_swamp_of_sorrows.cpp
|
||||
EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp
|
||||
EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp
|
||||
EasternKingdoms/SunwellPlateau/sunwell_plateau.h
|
||||
EasternKingdoms/SunwellPlateau/boss_muru.cpp
|
||||
EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp
|
||||
EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp
|
||||
EasternKingdoms/SunwellPlateau/boss_brutallus.cpp
|
||||
EasternKingdoms/SunwellPlateau/boss_felmyst.cpp
|
||||
EasternKingdoms/zone_stranglethorn_vale.cpp
|
||||
EasternKingdoms/Deadmines/boss_mr_smite.cpp
|
||||
EasternKingdoms/Deadmines/instance_deadmines.cpp
|
||||
EasternKingdoms/Deadmines/deadmines.h
|
||||
EasternKingdoms/zone_duskwood.cpp
|
||||
EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp
|
||||
EasternKingdoms/zone_undercity.cpp
|
||||
EasternKingdoms/zone_loch_modan.cpp
|
||||
EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp
|
||||
EasternKingdoms/ShadowfangKeep/shadowfang_keep.h
|
||||
EasternKingdoms/zone_burning_steppes.cpp
|
||||
EasternKingdoms/zone_blasted_lands.cpp
|
||||
EasternKingdoms/zone_stormwind_city.cpp
|
||||
EasternKingdoms/ZulAman/boss_halazzi.cpp
|
||||
EasternKingdoms/ZulAman/boss_hexlord.cpp
|
||||
EasternKingdoms/ZulAman/boss_zuljin.cpp
|
||||
EasternKingdoms/ZulAman/boss_akilzon.cpp
|
||||
EasternKingdoms/ZulAman/instance_zulaman.cpp
|
||||
EasternKingdoms/ZulAman/boss_janalai.cpp
|
||||
EasternKingdoms/ZulAman/boss_nalorakk.cpp
|
||||
EasternKingdoms/ZulAman/zulaman.cpp
|
||||
EasternKingdoms/ZulAman/zulaman.h
|
||||
EasternKingdoms/zone_hinterlands.cpp
|
||||
EasternKingdoms/zone_western_plaguelands.cpp
|
||||
EasternKingdoms/zone_alterac_mountains.cpp
|
||||
EasternKingdoms/zone_westfall.cpp
|
||||
EasternKingdoms/zone_silverpine_forest.cpp
|
||||
EasternKingdoms/Karazhan/instance_karazhan.cpp
|
||||
EasternKingdoms/Karazhan/boss_nightbane.cpp
|
||||
EasternKingdoms/Karazhan/karazhan.cpp
|
||||
EasternKingdoms/Karazhan/boss_curator.cpp
|
||||
EasternKingdoms/Karazhan/boss_shade_of_aran.cpp
|
||||
EasternKingdoms/Karazhan/boss_netherspite.cpp
|
||||
EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp
|
||||
EasternKingdoms/Karazhan/boss_midnight.cpp
|
||||
EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp
|
||||
EasternKingdoms/Karazhan/bosses_opera.cpp
|
||||
EasternKingdoms/Karazhan/boss_moroes.cpp
|
||||
EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp
|
||||
EasternKingdoms/Karazhan/boss_servant_quarters.cpp
|
||||
EasternKingdoms/Karazhan/karazhan.h
|
||||
EasternKingdoms/TheStockade/instance_the_stockade.cpp
|
||||
)
|
||||
|
||||
AC_ADD_SCRIPT_LOADER("EasternKingdoms" "ScriptLoader.h")
|
||||
|
||||
message(" -> Prepared: Eastern Kingdoms")
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
enum Spels
|
||||
{
|
||||
SPELL_SMITE_STOMP = 6432,
|
||||
SPELL_SMITE_SLAM = 6435,
|
||||
|
||||
EQUIP_SWORD = 1,
|
||||
EQUIP_TWO_SWORDS = 2,
|
||||
EQUIP_MACE = 3,
|
||||
|
||||
EVENT_CHECK_HEALTH1 = 1,
|
||||
EVENT_CHECK_HEALTH2 = 2,
|
||||
EVENT_SMITE_SLAM = 3,
|
||||
EVENT_SWAP_WEAPON1 = 4,
|
||||
EVENT_SWAP_WEAPON2 = 5,
|
||||
EVENT_RESTORE_COMBAT = 6,
|
||||
EVENT_KNEEL = 7,
|
||||
|
||||
SAY_SWAP1 = 2,
|
||||
SAY_SWAP2 = 3
|
||||
};
|
||||
|
||||
class boss_mr_smite : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_mr_smite() : CreatureScript("boss_mr_smite") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_mr_smiteAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_mr_smiteAI : public ScriptedAI
|
||||
{
|
||||
boss_mr_smiteAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
}
|
||||
|
||||
EventMap events;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
me->LoadEquipment(EQUIP_SWORD);
|
||||
me->SetCanDualWield(false);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH1, 500);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 500);
|
||||
events.ScheduleEvent(EVENT_SMITE_SLAM, 3000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SMITE_SLAM:
|
||||
me->CastSpell(me->GetVictim(), SPELL_SMITE_SLAM, false);
|
||||
events.ScheduleEvent(EVENT_SMITE_SLAM, 15000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH1:
|
||||
if (me->HealthBelowPct(67))
|
||||
{
|
||||
me->CastSpell(me, SPELL_SMITE_STOMP, false);
|
||||
events.DelayEvents(10000);
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MovePoint(EQUIP_TWO_SWORDS, 1.859f, -780.72f, 9.831f);
|
||||
Talk(SAY_SWAP1);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH1, 500);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH2:
|
||||
if (me->HealthBelowPct(34))
|
||||
{
|
||||
me->CastSpell(me, SPELL_SMITE_STOMP, false);
|
||||
events.DelayEvents(10000);
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MovePoint(EQUIP_MACE, 1.859f, -780.72f, 9.831f);
|
||||
Talk(SAY_SWAP2);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 500);
|
||||
break;
|
||||
case EVENT_SWAP_WEAPON1:
|
||||
me->LoadEquipment(EQUIP_TWO_SWORDS);
|
||||
me->SetCanDualWield(true);
|
||||
break;
|
||||
case EVENT_SWAP_WEAPON2:
|
||||
me->LoadEquipment(EQUIP_MACE);
|
||||
me->SetCanDualWield(false);
|
||||
break;
|
||||
case EVENT_RESTORE_COMBAT:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
if (me->GetVictim())
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
me->SetTarget(me->GetVictim()->GetGUID());
|
||||
}
|
||||
break;
|
||||
case EVENT_KNEEL:
|
||||
me->SendMeleeAttackStop(me->GetVictim());
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 point)
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
me->SetTarget(0);
|
||||
me->SetFacingTo(5.558f);
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
events.ScheduleEvent(point == EQUIP_TWO_SWORDS ? EVENT_SWAP_WEAPON1 : EVENT_SWAP_WEAPON2, 1500);
|
||||
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 3000);
|
||||
events.ScheduleEvent(EVENT_KNEEL, 0);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_mr_smite()
|
||||
{
|
||||
new boss_mr_smite();
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#ifndef DEF_DEADMINES_H
|
||||
#define DEF_DEADMINES_H
|
||||
|
||||
enum DataTypes
|
||||
{
|
||||
TYPE_RHAHK_ZOR = 0,
|
||||
TYPE_CANNON = 1,
|
||||
MAX_ENCOUNTERS = 2
|
||||
};
|
||||
|
||||
enum GameObjects
|
||||
{
|
||||
GO_FACTORY_DOOR = 13965,
|
||||
GO_IRON_CLAD_DOOR = 16397
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "deadmines.h"
|
||||
|
||||
class instance_deadmines : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
instance_deadmines() : InstanceMapScript("instance_deadmines", 36) { }
|
||||
|
||||
struct instance_deadmines_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
instance_deadmines_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
memset(&_encounters, 0, sizeof(_encounters));
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* gameobject)
|
||||
{
|
||||
switch (gameobject->GetEntry())
|
||||
{
|
||||
case GO_FACTORY_DOOR:
|
||||
if (_encounters[TYPE_RHAHK_ZOR] == DONE)
|
||||
HandleGameObject(0, true, gameobject);
|
||||
break;
|
||||
case GO_IRON_CLAD_DOOR:
|
||||
if (_encounters[TYPE_CANNON] == DONE)
|
||||
HandleGameObject(0, true, gameobject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_RHAHK_ZOR:
|
||||
case TYPE_CANNON:
|
||||
_encounters[type] = data;
|
||||
break;
|
||||
}
|
||||
|
||||
if (data == DONE)
|
||||
SaveToDB();
|
||||
}
|
||||
|
||||
std::string GetSaveData()
|
||||
{
|
||||
std::ostringstream saveStream;
|
||||
saveStream << "D E " << _encounters[0] << ' ' << _encounters[1];
|
||||
return saveStream.str();
|
||||
}
|
||||
|
||||
void Load(const char* in)
|
||||
{
|
||||
if (!in)
|
||||
return;
|
||||
|
||||
char dataHead1, dataHead2;
|
||||
std::istringstream loadStream(in);
|
||||
loadStream >> dataHead1 >> dataHead2;
|
||||
if (dataHead1 == 'D' && dataHead2 == 'E')
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i)
|
||||
{
|
||||
loadStream >> _encounters[i];
|
||||
if (_encounters[i] == IN_PROGRESS)
|
||||
_encounters[i] = NOT_STARTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _encounters[MAX_ENCOUNTERS];
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const
|
||||
{
|
||||
return new instance_deadmines_InstanceMapScript(map);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_deadmines()
|
||||
{
|
||||
new instance_deadmines();
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
|
||||
class instance_gnomeregan : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
instance_gnomeregan() : InstanceMapScript("instance_gnomeregan", 90) { }
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const
|
||||
{
|
||||
return new instance_gnomeregan_InstanceMapScript(map);
|
||||
}
|
||||
|
||||
struct instance_gnomeregan_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
instance_gnomeregan_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
enum eKernobee
|
||||
{
|
||||
QUEST_A_FINE_MESS = 2904,
|
||||
};
|
||||
|
||||
class npc_kernobee : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_kernobee() : CreatureScript("npc_kernobee") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new npc_kernobeeAI(creature);
|
||||
}
|
||||
|
||||
bool OnQuestAccept(Player* player, Creature* creature, const Quest* quest)
|
||||
{
|
||||
if (quest->GetQuestId() == QUEST_A_FINE_MESS)
|
||||
{
|
||||
creature->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
creature->AI()->SetGUID(player->GetGUID(), 0);
|
||||
creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, M_PI, MOTION_SLOT_CONTROLLED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct npc_kernobeeAI : public PassiveAI
|
||||
{
|
||||
npc_kernobeeAI(Creature* creature) : PassiveAI(creature)
|
||||
{
|
||||
playerGUID = 0;
|
||||
checkTimer = 0;
|
||||
}
|
||||
|
||||
uint32 checkTimer;
|
||||
uint64 playerGUID;
|
||||
|
||||
void SetGUID(uint64 guid, int32)
|
||||
{
|
||||
playerGUID = guid;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
checkTimer += diff;
|
||||
if (checkTimer >= 2000)
|
||||
{
|
||||
checkTimer = 0;
|
||||
if (me->GetDistance(-332.2f, -2.8f, -152.8f) < 5.0f)
|
||||
{
|
||||
if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID))
|
||||
player->GroupEventHappens(QUEST_A_FINE_MESS, me);
|
||||
me->DespawnOrUnsummon(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class spell_gnomeregan_radiation_bolt : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_gnomeregan_radiation_bolt() : SpellScriptLoader("spell_gnomeregan_radiation_bolt") { }
|
||||
|
||||
class spell_gnomeregan_radiation_bolt_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gnomeregan_radiation_bolt_SpellScript);
|
||||
|
||||
void HandleTriggerSpell(SpellEffIndex effIndex)
|
||||
{
|
||||
if (roll_chance_i(80))
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
OnEffectHit += SpellEffectFn(spell_gnomeregan_radiation_bolt_SpellScript::HandleTriggerSpell, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const
|
||||
{
|
||||
return new spell_gnomeregan_radiation_bolt_SpellScript;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_gnomeregan()
|
||||
{
|
||||
new instance_gnomeregan();
|
||||
new npc_kernobee();
|
||||
new spell_gnomeregan_radiation_bolt();
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "karazhan.h"
|
||||
|
||||
enum Curator
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SUMMON = 1,
|
||||
SAY_EVOCATE = 2,
|
||||
SAY_ENRAGE = 3,
|
||||
SAY_KILL = 4,
|
||||
SAY_DEATH = 5,
|
||||
|
||||
SPELL_HATEFUL_BOLT = 30383,
|
||||
SPELL_EVOCATION = 30254,
|
||||
SPELL_ARCANE_INFUSION = 30403,
|
||||
SPELL_ASTRAL_DECONSTRUCTION = 30407,
|
||||
|
||||
SPELL_SUMMON_ASTRAL_FLARE1 = 30236,
|
||||
SPELL_SUMMON_ASTRAL_FLARE2 = 30239,
|
||||
SPELL_SUMMON_ASTRAL_FLARE3 = 30240,
|
||||
SPELL_SUMMON_ASTRAL_FLARE4 = 30241,
|
||||
|
||||
EVENT_KILL_TALK = 1,
|
||||
EVENT_SPELL_HATEFUL_BOLT = 2,
|
||||
EVENT_SPELL_EVOCATION = 3,
|
||||
EVENT_SPELL_ASTRAL_FLARE = 4,
|
||||
EVENT_SPELL_BERSERK = 5,
|
||||
EVENT_CHECK_HEALTH = 6
|
||||
};
|
||||
|
||||
class boss_curator : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_curator() : CreatureScript("boss_curator") { }
|
||||
|
||||
struct boss_curatorAI : public BossAI
|
||||
{
|
||||
boss_curatorAI(Creature* creature) : BossAI(creature, TYPE_CURATOR) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_MANA_LEECH, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_POWER_BURN, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_BURN, true);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim)
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer)
|
||||
{
|
||||
BossAI::JustDied(killer);
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who)
|
||||
{
|
||||
BossAI::EnterCombat(who);
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_HATEFUL_BOLT, 10000);
|
||||
events.ScheduleEvent(EVENT_SPELL_ASTRAL_FLARE, 6000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
if (Unit* target = summon->SelectNearbyTarget(NULL, 40.0f))
|
||||
{
|
||||
summon->AI()->AttackStart(target);
|
||||
summon->AddThreat(target, 1000.0f);
|
||||
}
|
||||
|
||||
summon->SetInCombatWithZone();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(16))
|
||||
{
|
||||
events.CancelEvent(EVENT_SPELL_ASTRAL_FLARE);
|
||||
me->CastSpell(me, SPELL_ARCANE_INFUSION, true);
|
||||
Talk(SAY_ENRAGE);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
break;
|
||||
case EVENT_SPELL_BERSERK:
|
||||
Talk(SAY_ENRAGE);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
me->CastSpell(me, SPELL_ASTRAL_DECONSTRUCTION, true);
|
||||
break;
|
||||
case EVENT_SPELL_HATEFUL_BOLT:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, urand(1, 2), 40.0f))
|
||||
me->CastSpell(target, SPELL_HATEFUL_BOLT, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_HATEFUL_BOLT, urand(5000, 7500) * (events.GetNextEventTime(EVENT_SPELL_BERSERK) == 0 ? 1 : 2));
|
||||
break;
|
||||
case EVENT_SPELL_ASTRAL_FLARE:
|
||||
{
|
||||
me->CastSpell(me, RAND(SPELL_SUMMON_ASTRAL_FLARE1, SPELL_SUMMON_ASTRAL_FLARE2, SPELL_SUMMON_ASTRAL_FLARE3, SPELL_SUMMON_ASTRAL_FLARE4), false);
|
||||
int32 mana = CalculatePct(me->GetMaxPower(POWER_MANA), 10);
|
||||
me->ModifyPower(POWER_MANA, -mana);
|
||||
if (me->GetPowerPct(POWER_MANA) < 10.0f)
|
||||
{
|
||||
Talk(SAY_EVOCATE);
|
||||
me->CastSpell(me, SPELL_EVOCATION, false);
|
||||
|
||||
events.DelayEvents(20000);
|
||||
events.ScheduleEvent(EVENT_SPELL_ASTRAL_FLARE, 20000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (roll_chance_i(50))
|
||||
Talk(SAY_SUMMON);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_ASTRAL_FLARE, 10000);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_curatorAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_curator()
|
||||
{
|
||||
new boss_curator();
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "karazhan.h"
|
||||
|
||||
enum MaidenOfVirtue
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_REPENTANCE = 2,
|
||||
SAY_DEATH = 3,
|
||||
|
||||
SPELL_REPENTANCE = 29511,
|
||||
SPELL_HOLY_FIRE = 29522,
|
||||
SPELL_HOLY_WRATH = 32445,
|
||||
SPELL_HOLY_GROUND = 29523,
|
||||
SPELL_BERSERK = 26662,
|
||||
|
||||
EVENT_SPELL_REPENTANCE = 1,
|
||||
EVENT_SPELL_HOLY_FIRE = 2,
|
||||
EVENT_SPELL_HOLY_WRATH = 3,
|
||||
EVENT_SPELL_ENRAGE = 4,
|
||||
EVENT_KILL_TALK = 5
|
||||
};
|
||||
|
||||
class boss_maiden_of_virtue : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_maiden_of_virtue() : CreatureScript("boss_maiden_of_virtue") { }
|
||||
|
||||
struct boss_maiden_of_virtueAI : public BossAI
|
||||
{
|
||||
boss_maiden_of_virtueAI(Creature* creature) : BossAI(creature, TYPE_MAIDEN) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
BossAI::Reset();
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer)
|
||||
{
|
||||
BossAI::JustDied(killer);
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who)
|
||||
{
|
||||
BossAI::EnterCombat(who);
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
me->CastSpell(me, SPELL_HOLY_GROUND, true);
|
||||
events.ScheduleEvent(EVENT_SPELL_REPENTANCE, 25000);
|
||||
events.ScheduleEvent(EVENT_SPELL_HOLY_FIRE, 8000);
|
||||
events.ScheduleEvent(EVENT_SPELL_HOLY_WRATH, 15000);
|
||||
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 600000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_REPENTANCE:
|
||||
me->CastSpell(me, SPELL_REPENTANCE, true);
|
||||
events.ScheduleEvent(EVENT_SPELL_REPENTANCE, urand(25000, 35000));
|
||||
break;
|
||||
case EVENT_SPELL_HOLY_FIRE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true))
|
||||
me->CastSpell(target, SPELL_HOLY_FIRE, true);
|
||||
events.ScheduleEvent(EVENT_SPELL_HOLY_FIRE, urand(8000, 18000));
|
||||
break;
|
||||
case EVENT_SPELL_HOLY_WRATH:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true))
|
||||
me->CastSpell(target, SPELL_HOLY_WRATH, true);
|
||||
events.ScheduleEvent(EVENT_SPELL_HOLY_WRATH, urand(20000, 25000));
|
||||
break;
|
||||
case EVENT_SPELL_ENRAGE:
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_maiden_of_virtueAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_maiden_of_virtue()
|
||||
{
|
||||
new boss_maiden_of_virtue();
|
||||
}
|
||||
@@ -1,451 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "karazhan.h"
|
||||
|
||||
enum eSay
|
||||
{
|
||||
SAY_ATTUMEN1_APPEAR = 0,
|
||||
SAY_ATTUMEN1_MOUNT = 2,
|
||||
|
||||
SAY_ATTUMEN2_DEATH = 0,
|
||||
|
||||
SAY_ATTUMEN_KILL = 1,
|
||||
SAY_ATTUMEN_DISARM = 3,
|
||||
SAY_ATTUMEN_RANDOM = 4,
|
||||
SAY_ATTUMEN_MIDNIGHT_KILL = 5,
|
||||
|
||||
SAY_MIDNIGHT_EMOTE = 0
|
||||
};
|
||||
|
||||
enum eSpells
|
||||
{
|
||||
// Midnight
|
||||
SPELL_KNOCKDOWN = 29711,
|
||||
SPELL_SUMMON_ATTUMEN = 29714,
|
||||
SPELL_SUMMON_ATTUMEN_MOUNTED = 29799,
|
||||
|
||||
// Attumen
|
||||
SPELL_SHADOW_CLEAVE = 29832,
|
||||
SPELL_INTANGIBLE_PRESENCE = 29833,
|
||||
SPELL_SPAWN_SMOKE1 = 29802,
|
||||
|
||||
// Attumen 2
|
||||
SPELL_CHARGE_MIDNIGHT = 29847,
|
||||
SPELL_SPAWN_SMOKE2 = 10389,
|
||||
|
||||
// Generic
|
||||
SPELL_MOUNT_TARGET_ATTUMEN = 29769,
|
||||
SPELL_MOUNT_TARGET_MIDNIGHT = 29770
|
||||
};
|
||||
|
||||
enum eEvents
|
||||
{
|
||||
EVENT_CHECK_HEALTH_95 = 1,
|
||||
EVENT_CHECK_HEALTH_25 = 2,
|
||||
EVENT_SPELL_KNOCKDOWN = 3,
|
||||
EVENT_SUMMON_ATTUMEN_MOUNTED = 4,
|
||||
|
||||
EVENT_SPELL_SHADOW_CLEAVE = 10,
|
||||
EVENT_SPELL_INTANGIBLE_PRESENCE = 11,
|
||||
EVENT_RANDOM_YELL = 12,
|
||||
|
||||
EVENT_SPELL_CHARGE = 20,
|
||||
|
||||
EVENT_KILL_TALK = 30
|
||||
};
|
||||
|
||||
enum eMisc
|
||||
{
|
||||
POINT_MOVE_TO_MIDNIGHT = 1,
|
||||
DATA_ATTUMEN_READY = 1
|
||||
};
|
||||
|
||||
class boss_midnight : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_midnight() : CreatureScript("boss_midnight") { }
|
||||
|
||||
struct boss_midnightAI : public BossAI
|
||||
{
|
||||
boss_midnightAI(Creature* creature) : BossAI(creature, TYPE_ATTUMEN) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->SetVisible(true);
|
||||
_healthPct = 100.0f;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who)
|
||||
{
|
||||
BossAI::EnterCombat(who);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH_95, 0);
|
||||
events.ScheduleEvent(EVENT_SPELL_KNOCKDOWN, 6000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
if (Creature* attumen = summons.GetCreatureWithEntry(NPC_ATTUMEN_THE_HUNTSMAN))
|
||||
attumen->AI()->Talk(SAY_ATTUMEN_MIDNIGHT_KILL);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
summon->SetInCombatWithZone();
|
||||
|
||||
if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED)
|
||||
{
|
||||
summon->SetHealth(summon->CountPctFromMaxHealth(_healthPct));
|
||||
summon->CastSpell(summon, SPELL_SPAWN_SMOKE2, true);
|
||||
}
|
||||
else
|
||||
summon->CastSpell(summon, SPELL_SPAWN_SMOKE1, true);
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 /*data*/)
|
||||
{
|
||||
if (type == DATA_ATTUMEN_READY)
|
||||
events.ScheduleEvent(EVENT_SUMMON_ATTUMEN_MOUNTED, 0);
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/)
|
||||
{
|
||||
if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED)
|
||||
{
|
||||
summons.clear();
|
||||
Unit::Kill(me, me);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_CHECK_HEALTH_95:
|
||||
if (me->HealthBelowPct(96))
|
||||
{
|
||||
me->CastSpell(me, SPELL_SUMMON_ATTUMEN, true);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH_25, 0);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH_95, 500);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH_25:
|
||||
if (me->HealthBelowPct(25))
|
||||
{
|
||||
Talk(SAY_MIDNIGHT_EMOTE);
|
||||
me->CastSpell(me, SPELL_MOUNT_TARGET_ATTUMEN, true);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH_25, 500);
|
||||
break;
|
||||
case EVENT_SPELL_KNOCKDOWN:
|
||||
me->CastSpell(me->GetVictim(), SPELL_KNOCKDOWN, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_KNOCKDOWN, 20000);
|
||||
break;
|
||||
case EVENT_SUMMON_ATTUMEN_MOUNTED:
|
||||
if (Creature* attumen = summons.GetCreatureWithEntry(NPC_ATTUMEN_THE_HUNTSMAN))
|
||||
{
|
||||
_healthPct = std::max<float>(me->GetHealthPct(), attumen->GetHealthPct());
|
||||
attumen->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
me->CastSpell(me, SPELL_SUMMON_ATTUMEN_MOUNTED, true);
|
||||
me->SetVisible(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->IsVisible())
|
||||
DoMeleeAttackIfReady();
|
||||
EnterEvadeIfOutOfCombatArea();
|
||||
}
|
||||
|
||||
bool CheckEvadeIfOutOfCombatArea() const
|
||||
{
|
||||
return me->GetHomePosition().GetExactDist2d(me) > 50.0f || me->GetPositionZ() > 60.0f;
|
||||
}
|
||||
|
||||
private:
|
||||
float _healthPct;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_midnightAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_attumen : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_attumen() : CreatureScript("boss_attumen") { }
|
||||
|
||||
struct boss_attumenAI : public ScriptedAI
|
||||
{
|
||||
boss_attumenAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_events.Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
Talk(SAY_ATTUMEN1_APPEAR);
|
||||
_events.ScheduleEvent(EVENT_CHECK_HEALTH_25, 0);
|
||||
_events.ScheduleEvent(EVENT_SPELL_SHADOW_CLEAVE, 6000);
|
||||
_events.ScheduleEvent(EVENT_SPELL_INTANGIBLE_PRESENCE, 15000);
|
||||
_events.ScheduleEvent(EVENT_RANDOM_YELL, urand(25000, 45000));
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
if (_events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
_events.ScheduleEvent(EVENT_KILL_TALK, 5000);
|
||||
Talk(SAY_ATTUMEN_KILL);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHit(Unit* caster, const SpellInfo* spellInfo)
|
||||
{
|
||||
if (spellInfo->Mechanic == MECHANIC_DISARM && _events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
_events.ScheduleEvent(EVENT_KILL_TALK, 5000);
|
||||
Talk(SAY_ATTUMEN_DISARM);
|
||||
}
|
||||
else if (spellInfo->Id == SPELL_MOUNT_TARGET_ATTUMEN)
|
||||
{
|
||||
me->CastSpell(me, SPELL_MOUNT_TARGET_MIDNIGHT, true);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit* target, const SpellInfo* spellInfo)
|
||||
{
|
||||
if (spellInfo->Id == SPELL_MOUNT_TARGET_MIDNIGHT)
|
||||
{
|
||||
Talk(SAY_ATTUMEN1_MOUNT);
|
||||
_events.Reset();
|
||||
me->GetMotionMaster()->MovePoint(POINT_MOVE_TO_MIDNIGHT, target->GetPositionX() + 2.0f*cos(target->GetAngle(me)), target->GetPositionY() + 2.0f*sin(target->GetAngle(me)), target->GetPositionZ()+0.2f, true, true, MOTION_SLOT_CONTROLLED);
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 point)
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && point == POINT_MOVE_TO_MIDNIGHT)
|
||||
{
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
if (Unit* midnight = summon->GetSummoner())
|
||||
midnight->GetAI()->SetData(DATA_ATTUMEN_READY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (_events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_SHADOW_CLEAVE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHADOW_CLEAVE, false);
|
||||
_events.ScheduleEvent(EVENT_SPELL_SHADOW_CLEAVE, urand(9000, 14000));
|
||||
break;
|
||||
case EVENT_SPELL_INTANGIBLE_PRESENCE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_INTANGIBLE_PRESENCE, false);
|
||||
_events.ScheduleEvent(EVENT_SPELL_INTANGIBLE_PRESENCE, 30000);
|
||||
break;
|
||||
case EVENT_RANDOM_YELL:
|
||||
Talk(SAY_ATTUMEN_RANDOM);
|
||||
_events.ScheduleEvent(EVENT_RANDOM_YELL, urand(30000, 70000));
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH_25:
|
||||
if (me->HealthBelowPct(25))
|
||||
{
|
||||
me->CastSpell(me, SPELL_MOUNT_TARGET_MIDNIGHT, true);
|
||||
break;
|
||||
}
|
||||
_events.ScheduleEvent(EVENT_CHECK_HEALTH_25, 500);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap _events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_attumenAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_attumen_midnight : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_attumen_midnight() : CreatureScript("boss_attumen_midnight") { }
|
||||
|
||||
struct boss_attumen_midnightAI : public ScriptedAI
|
||||
{
|
||||
boss_attumen_midnightAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_events.Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
_events.ScheduleEvent(EVENT_SPELL_SHADOW_CLEAVE, 6000);
|
||||
_events.ScheduleEvent(EVENT_SPELL_INTANGIBLE_PRESENCE, 15000);
|
||||
_events.ScheduleEvent(EVENT_RANDOM_YELL, urand(25000, 45000));
|
||||
_events.ScheduleEvent(EVENT_SPELL_CHARGE, 20000);
|
||||
_events.ScheduleEvent(EVENT_SPELL_KNOCKDOWN, 11000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
if (_events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
_events.ScheduleEvent(EVENT_KILL_TALK, 5000);
|
||||
Talk(SAY_ATTUMEN_KILL);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
Talk(SAY_ATTUMEN2_DEATH);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* caster, const SpellInfo* spellInfo)
|
||||
{
|
||||
if (spellInfo->Mechanic == MECHANIC_DISARM && _events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
_events.ScheduleEvent(EVENT_KILL_TALK, 5000);
|
||||
Talk(SAY_ATTUMEN_DISARM);
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 point)
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && point == POINT_MOVE_TO_MIDNIGHT)
|
||||
{
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
if (Unit* midnight = summon->GetSummoner())
|
||||
midnight->GetAI()->SetData(DATA_ATTUMEN_READY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (_events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_SHADOW_CLEAVE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHADOW_CLEAVE, false);
|
||||
_events.ScheduleEvent(EVENT_SPELL_SHADOW_CLEAVE, urand(9000, 14000));
|
||||
break;
|
||||
case EVENT_SPELL_INTANGIBLE_PRESENCE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_INTANGIBLE_PRESENCE, false);
|
||||
_events.ScheduleEvent(EVENT_SPELL_INTANGIBLE_PRESENCE, 30000);
|
||||
break;
|
||||
case EVENT_RANDOM_YELL:
|
||||
Talk(SAY_ATTUMEN_RANDOM);
|
||||
_events.ScheduleEvent(EVENT_RANDOM_YELL, urand(30000, 70000));
|
||||
break;
|
||||
case EVENT_SPELL_CHARGE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_FARTHEST, 0, 24.0f, true))
|
||||
me->CastSpell(target, SPELL_CHARGE_MIDNIGHT, false);
|
||||
_events.ScheduleEvent(EVENT_SPELL_CHARGE, 20000);
|
||||
break;
|
||||
case EVENT_SPELL_KNOCKDOWN:
|
||||
me->CastSpell(me->GetVictim(), SPELL_KNOCKDOWN, false);
|
||||
_events.ScheduleEvent(EVENT_SPELL_KNOCKDOWN, 20000);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap _events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_attumen_midnightAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_midnight_fixate : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_midnight_fixate() : SpellScriptLoader("spell_midnight_fixate") { }
|
||||
|
||||
class spell_midnight_fixate_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_midnight_fixate_AuraScript);
|
||||
|
||||
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (Unit* caster = GetCaster())
|
||||
caster->TauntApply(target);
|
||||
}
|
||||
|
||||
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (Unit* caster = GetCaster())
|
||||
caster->TauntFadeOut(target);
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const
|
||||
{
|
||||
return new spell_midnight_fixate_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_attumen()
|
||||
{
|
||||
new boss_midnight();
|
||||
new boss_attumen();
|
||||
new boss_attumen_midnight();
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "karazhan.h"
|
||||
|
||||
enum Yells
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SPECIAL = 1,
|
||||
SAY_KILL = 2,
|
||||
SAY_DEATH = 3,
|
||||
SAY_OUT_OF_COMBAT = 4,
|
||||
|
||||
SAY_GUEST = 0
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_VANISH = 29448,
|
||||
SPELL_GARROTE_DUMMY = 29433,
|
||||
SPELL_GARROTE = 37066,
|
||||
SPELL_BLIND = 34694,
|
||||
SPELL_GOUGE = 29425,
|
||||
SPELL_FRENZY = 37023,
|
||||
SPELL_DUAL_WIELD = 29651,
|
||||
SPELL_BERSERK = 26662,
|
||||
SPELL_VANISH_TELEPORT = 29431,
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
EVENT_GUEST_TALK = 1,
|
||||
EVENT_GUEST_TALK2 = 2,
|
||||
EVENT_SPELL_VANISH = 3,
|
||||
EVENT_SPELL_GARROTE = 4,
|
||||
EVENT_SPELL_BLIND = 5,
|
||||
EVENT_SPELL_GOUGE = 6,
|
||||
EVENT_CHECK_HEALTH = 7,
|
||||
EVENT_SPELL_ENRAGE = 8,
|
||||
EVENT_KILL_TALK = 9,
|
||||
|
||||
ACTIVE_GUEST_COUNT = 4,
|
||||
MAX_GUEST_COUNT = 6
|
||||
};
|
||||
|
||||
const Position GuestsPosition[4] =
|
||||
{
|
||||
{-10987.38f, -1883.38f, 81.73f, 1.50f},
|
||||
{-10989.60f, -1881.27f, 81.73f, 0.73f},
|
||||
{-10978.81f, -1884.08f, 81.73f, 1.50f},
|
||||
{-10976.38f, -1882.59f, 81.73f, 2.31f},
|
||||
};
|
||||
|
||||
const uint32 GuestEntries[6]=
|
||||
{
|
||||
17007,
|
||||
19872,
|
||||
19873,
|
||||
19874,
|
||||
19875,
|
||||
19876,
|
||||
};
|
||||
|
||||
class boss_moroes : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_moroes() : CreatureScript("boss_moroes") { }
|
||||
|
||||
struct boss_moroesAI : public BossAI
|
||||
{
|
||||
boss_moroesAI(Creature* creature) : BossAI(creature, TYPE_MOROES)
|
||||
{
|
||||
_activeGuests = 0;
|
||||
}
|
||||
|
||||
void InitializeAI()
|
||||
{
|
||||
BossAI::InitializeAI();
|
||||
InitializeGuests();
|
||||
}
|
||||
|
||||
void JustReachedHome()
|
||||
{
|
||||
BossAI::JustReachedHome();
|
||||
InitializeGuests();
|
||||
}
|
||||
|
||||
void InitializeGuests()
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
return;
|
||||
|
||||
if (_activeGuests == 0)
|
||||
{
|
||||
_activeGuests |= 0x3F;
|
||||
uint8 rand1 = RAND(0x01, 0x02, 0x04);
|
||||
uint8 rand2 = RAND(0x08, 0x10, 0x20);
|
||||
_activeGuests &= ~(rand1|rand2);
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < MAX_GUEST_COUNT; ++i)
|
||||
if ((1 << i) & _activeGuests)
|
||||
me->SummonCreature(GuestEntries[i], GuestsPosition[summons.size()], TEMPSUMMON_MANUAL_DESPAWN);
|
||||
|
||||
_events2.Reset();
|
||||
_events2.ScheduleEvent(EVENT_GUEST_TALK, 10000);
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->CastSpell(me, SPELL_DUAL_WIELD, true);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who)
|
||||
{
|
||||
BossAI::EnterCombat(who);
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_VANISH, 30000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BLIND, 20000);
|
||||
events.ScheduleEvent(EVENT_SPELL_GOUGE, 13000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 5000);
|
||||
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 600000);
|
||||
|
||||
_events2.Reset();
|
||||
me->CallForHelp(20.0f);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer)
|
||||
{
|
||||
summons.clear();
|
||||
BossAI::JustDied(killer);
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GARROTE);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
Creature* GetRandomGuest()
|
||||
{
|
||||
std::list<Creature*> guestList;
|
||||
for (SummonList::const_iterator i = summons.begin(); i != summons.end(); ++i)
|
||||
if (Creature* summon = ObjectAccessor::GetCreature(*me, *i))
|
||||
guestList.push_back(summon);
|
||||
|
||||
return Trinity::Containers::SelectRandomContainerElement(guestList);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
_events2.Update(diff);
|
||||
switch (_events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_GUEST_TALK:
|
||||
if (Creature* guest = GetRandomGuest())
|
||||
guest->AI()->Talk(SAY_GUEST);
|
||||
_events2.ScheduleEvent(EVENT_GUEST_TALK2, 5000);
|
||||
break;
|
||||
case EVENT_GUEST_TALK2:
|
||||
Talk(SAY_OUT_OF_COMBAT);
|
||||
_events2.ScheduleEvent(EVENT_GUEST_TALK, urand(60000, 120000));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(31))
|
||||
{
|
||||
me->CastSpell(me, SPELL_FRENZY, true);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
break;
|
||||
case EVENT_SPELL_ENRAGE:
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
break;
|
||||
case EVENT_SPELL_BLIND:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 10.0f, true))
|
||||
me->CastSpell(target, SPELL_BLIND, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_BLIND, urand(25000, 40000));
|
||||
break;
|
||||
case EVENT_SPELL_GOUGE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_GOUGE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_GOUGE, urand(25000, 40000));
|
||||
return;
|
||||
case EVENT_SPELL_VANISH:
|
||||
events.DelayEvents(9000);
|
||||
events.SetPhase(1);
|
||||
me->CastSpell(me, SPELL_VANISH, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_VANISH, 30000);
|
||||
events.ScheduleEvent(EVENT_SPELL_GARROTE, urand(5000, 7000));
|
||||
return;
|
||||
case EVENT_SPELL_GARROTE:
|
||||
me->CastSpell(me, SPELL_VANISH_TELEPORT, false);
|
||||
break;
|
||||
}
|
||||
|
||||
// Xinef: not in vanish
|
||||
if (events.GetPhaseMask() == 0)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap _events2;
|
||||
uint8 _activeGuests;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_moroesAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_moroes_vanish : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_moroes_vanish() : SpellScriptLoader("spell_moroes_vanish") { }
|
||||
|
||||
class spell_moroes_vanish_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_moroes_vanish_SpellScript);
|
||||
|
||||
void HandleDummy(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
Position pos;
|
||||
target->GetFirstCollisionPosition(pos, 5.0f, M_PI);
|
||||
GetCaster()->CastSpell(target, SPELL_GARROTE_DUMMY, true);
|
||||
GetCaster()->RemoveAurasDueToSpell(SPELL_VANISH);
|
||||
GetCaster()->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), target->GetOrientation());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_moroes_vanish_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const
|
||||
{
|
||||
return new spell_moroes_vanish_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_moroes()
|
||||
{
|
||||
new boss_moroes();
|
||||
new spell_moroes_vanish();
|
||||
}
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Netherspite
|
||||
SD%Complete: 90
|
||||
SDComment: Not sure about timing and portals placing
|
||||
SDCategory: Karazhan
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "karazhan.h"
|
||||
#include "Player.h"
|
||||
|
||||
enum Netherspite
|
||||
{
|
||||
EMOTE_PHASE_PORTAL = 0,
|
||||
EMOTE_PHASE_BANISH = 1,
|
||||
|
||||
SPELL_NETHERBURN_AURA = 30522,
|
||||
SPELL_VOIDZONE = 37063,
|
||||
SPELL_NETHER_INFUSION = 38688,
|
||||
SPELL_NETHERBREATH = 38523,
|
||||
SPELL_BANISH_VISUAL = 39833,
|
||||
SPELL_BANISH_ROOT = 42716,
|
||||
SPELL_EMPOWERMENT = 38549,
|
||||
SPELL_NETHERSPITE_ROAR = 38684,
|
||||
};
|
||||
|
||||
|
||||
const float PortalCoord[3][3] =
|
||||
{
|
||||
{-11195.353516f, -1613.237183f, 278.237258f}, // Left side
|
||||
{-11137.846680f, -1685.607422f, 278.239258f}, // Right side
|
||||
{-11094.493164f, -1591.969238f, 279.949188f} // Back side
|
||||
};
|
||||
|
||||
enum Netherspite_Portal{
|
||||
RED_PORTAL = 0, // Perseverence
|
||||
GREEN_PORTAL = 1, // Serenity
|
||||
BLUE_PORTAL = 2 // Dominance
|
||||
};
|
||||
|
||||
const uint32 PortalID[3] = {17369, 17367, 17368};
|
||||
const uint32 PortalVisual[3] = {30487, 30490, 30491};
|
||||
const uint32 PortalBeam[3] = {30465, 30464, 30463};
|
||||
const uint32 PlayerBuff[3] = {30421, 30422, 30423};
|
||||
const uint32 NetherBuff[3] = {30466, 30467, 30468};
|
||||
const uint32 PlayerDebuff[3] = {38637, 38638, 38639};
|
||||
|
||||
class boss_netherspite : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_netherspite() : CreatureScript("boss_netherspite") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_netherspiteAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_netherspiteAI : public ScriptedAI
|
||||
{
|
||||
boss_netherspiteAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
PortalGUID[i] = 0;
|
||||
BeamTarget[i] = 0;
|
||||
BeamerGUID[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
bool PortalPhase;
|
||||
bool Berserk;
|
||||
uint32 PhaseTimer; // timer for phase switching
|
||||
uint32 VoidZoneTimer;
|
||||
uint32 NetherInfusionTimer; // berserking timer
|
||||
uint32 NetherbreathTimer;
|
||||
uint32 EmpowermentTimer;
|
||||
uint32 PortalTimer; // timer for beam checking
|
||||
uint64 PortalGUID[3]; // guid's of portals
|
||||
uint64 BeamerGUID[3]; // guid's of auxiliary beaming portals
|
||||
uint64 BeamTarget[3]; // guid's of portals' current targets
|
||||
|
||||
bool IsBetween(WorldObject* u1, WorldObject* target, WorldObject* u2) // the in-line checker
|
||||
{
|
||||
if (!u1 || !u2 || !target)
|
||||
return false;
|
||||
|
||||
float xn, yn, xp, yp, xh, yh;
|
||||
xn = u1->GetPositionX();
|
||||
yn = u1->GetPositionY();
|
||||
xp = u2->GetPositionX();
|
||||
yp = u2->GetPositionY();
|
||||
xh = target->GetPositionX();
|
||||
yh = target->GetPositionY();
|
||||
|
||||
// check if target is between (not checking distance from the beam yet)
|
||||
if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp))
|
||||
return false;
|
||||
// check distance from the beam
|
||||
return (abs((xn-xp)*yh+(yp-yn)*xh-xn*yp+xp*yn)/dist(xn, yn, xp, yp) < 1.5f);
|
||||
}
|
||||
|
||||
float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance
|
||||
{
|
||||
return sqrt((xa-xb)*(xa-xb) + (ya-yb)*(ya-yb));
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Berserk = false;
|
||||
NetherInfusionTimer = 540000;
|
||||
VoidZoneTimer = 15000;
|
||||
NetherbreathTimer = 3000;
|
||||
|
||||
HandleDoors(true);
|
||||
DestroyPortals();
|
||||
}
|
||||
|
||||
void SummonPortals()
|
||||
{
|
||||
uint8 r = rand()%4;
|
||||
uint8 pos[3];
|
||||
pos[RED_PORTAL] = ((r % 2) ? (r > 1 ? 2 : 1) : 0);
|
||||
pos[GREEN_PORTAL] = ((r % 2) ? 0 : (r > 1 ? 2 : 1));
|
||||
pos[BLUE_PORTAL] = (r > 1 ? 1 : 2); // Blue Portal not on the left side (0)
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
if (Creature* portal = me->SummonCreature(PortalID[i], PortalCoord[pos[i]][0], PortalCoord[pos[i]][1], PortalCoord[pos[i]][2], 0, TEMPSUMMON_TIMED_DESPAWN, 60000))
|
||||
{
|
||||
PortalGUID[i] = portal->GetGUID();
|
||||
portal->AddAura(PortalVisual[i], portal);
|
||||
}
|
||||
}
|
||||
|
||||
void DestroyPortals()
|
||||
{
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[i]))
|
||||
portal->DisappearAndDie();
|
||||
if (Creature* portal = ObjectAccessor::GetCreature(*me, BeamerGUID[i]))
|
||||
portal->DisappearAndDie();
|
||||
PortalGUID[i] = 0;
|
||||
BeamTarget[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePortals() // Here we handle the beams' behavior
|
||||
{
|
||||
for (int j=0; j<3; ++j) // j = color
|
||||
if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[j]))
|
||||
{
|
||||
// the one who's been cast upon before
|
||||
Unit* current = ObjectAccessor::GetUnit(*portal, BeamTarget[j]);
|
||||
// temporary store for the best suitable beam reciever
|
||||
Unit* target = me;
|
||||
|
||||
if (Map* map = me->GetMap())
|
||||
{
|
||||
Map::PlayerList const& players = map->GetPlayers();
|
||||
|
||||
// get the best suitable target
|
||||
for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
|
||||
{
|
||||
Player* p = i->GetSource();
|
||||
if (p && p->IsAlive() // alive
|
||||
&& (!target || target->GetDistance2d(portal)>p->GetDistance2d(portal)) // closer than current best
|
||||
&& !p->HasAura(PlayerDebuff[j], 0) // not exhausted
|
||||
&& !p->HasAura(PlayerBuff[(j+1)%3], 0) // not on another beam
|
||||
&& !p->HasAura(PlayerBuff[(j+2)%3], 0)
|
||||
&& IsBetween(me, p, portal)) // on the beam
|
||||
target = p;
|
||||
}
|
||||
}
|
||||
// buff the target
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
target->AddAura(PlayerBuff[j], target);
|
||||
else
|
||||
target->AddAura(NetherBuff[j], target);
|
||||
// cast visual beam on the chosen target if switched
|
||||
// simple target switching isn't working -> using BeamerGUID to cast (workaround)
|
||||
if (!current || target != current)
|
||||
{
|
||||
BeamTarget[j] = target->GetGUID();
|
||||
// remove currently beaming portal
|
||||
if (Creature* beamer = ObjectAccessor::GetCreature(*portal, BeamerGUID[j]))
|
||||
{
|
||||
beamer->CastSpell(target, PortalBeam[j], false);
|
||||
beamer->DisappearAndDie();
|
||||
BeamerGUID[j] = 0;
|
||||
}
|
||||
// create new one and start beaming on the target
|
||||
if (Creature* beamer = portal->SummonCreature(PortalID[j], portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), portal->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 60000))
|
||||
{
|
||||
beamer->CastSpell(target, PortalBeam[j], false);
|
||||
BeamerGUID[j] = beamer->GetGUID();
|
||||
}
|
||||
}
|
||||
// aggro target if Red Beam
|
||||
if (j == RED_PORTAL && me->GetVictim() != target && target->GetTypeId() == TYPEID_PLAYER)
|
||||
me->getThreatManager().addThreat(target, 100000.0f+DoGetThreat(me->GetVictim()));
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchToPortalPhase()
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_BANISH_ROOT);
|
||||
me->RemoveAurasDueToSpell(SPELL_BANISH_VISUAL);
|
||||
SummonPortals();
|
||||
PhaseTimer = 60000;
|
||||
PortalPhase = true;
|
||||
PortalTimer = 10000;
|
||||
EmpowermentTimer = 10000;
|
||||
Talk(EMOTE_PHASE_PORTAL);
|
||||
}
|
||||
|
||||
void SwitchToBanishPhase()
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_EMPOWERMENT);
|
||||
me->RemoveAurasDueToSpell(SPELL_NETHERBURN_AURA);
|
||||
DoCast(me, SPELL_BANISH_VISUAL, true);
|
||||
DoCast(me, SPELL_BANISH_ROOT, true);
|
||||
DestroyPortals();
|
||||
PhaseTimer = 30000;
|
||||
PortalPhase = false;
|
||||
Talk(EMOTE_PHASE_BANISH);
|
||||
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
me->RemoveAurasDueToSpell(NetherBuff[i]);
|
||||
}
|
||||
|
||||
void HandleDoors(bool open) // Massive Door switcher
|
||||
{
|
||||
if (GameObject* Door = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_GO_MASSIVE_DOOR) ))
|
||||
Door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
HandleDoors(false);
|
||||
SwitchToPortalPhase();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
HandleDoors(true);
|
||||
DestroyPortals();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
// Void Zone
|
||||
if (VoidZoneTimer <= diff)
|
||||
{
|
||||
DoCast(SelectTarget(SELECT_TARGET_RANDOM, 1, 45, true), SPELL_VOIDZONE, true);
|
||||
VoidZoneTimer = 15000;
|
||||
} else VoidZoneTimer -= diff;
|
||||
|
||||
// NetherInfusion Berserk
|
||||
if (!Berserk && NetherInfusionTimer <= diff)
|
||||
{
|
||||
me->AddAura(SPELL_NETHER_INFUSION, me);
|
||||
DoCast(me, SPELL_NETHERSPITE_ROAR);
|
||||
Berserk = true;
|
||||
} else NetherInfusionTimer -= diff;
|
||||
|
||||
if (PortalPhase) // PORTAL PHASE
|
||||
{
|
||||
// Distribute beams and buffs
|
||||
if (PortalTimer <= diff)
|
||||
{
|
||||
UpdatePortals();
|
||||
PortalTimer = 1000;
|
||||
} else PortalTimer -= diff;
|
||||
|
||||
// Empowerment & Nether Burn
|
||||
if (EmpowermentTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_EMPOWERMENT);
|
||||
me->AddAura(SPELL_NETHERBURN_AURA, me);
|
||||
EmpowermentTimer = 90000;
|
||||
} else EmpowermentTimer -= diff;
|
||||
|
||||
if (PhaseTimer <= diff)
|
||||
{
|
||||
if (!me->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
SwitchToBanishPhase();
|
||||
return;
|
||||
}
|
||||
} else PhaseTimer -= diff;
|
||||
}
|
||||
else // BANISH PHASE
|
||||
{
|
||||
// Netherbreath
|
||||
if (NetherbreathTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true))
|
||||
DoCast(target, SPELL_NETHERBREATH);
|
||||
NetherbreathTimer = urand(5000, 7000);
|
||||
} else NetherbreathTimer -= diff;
|
||||
|
||||
if (PhaseTimer <= diff)
|
||||
{
|
||||
if (!me->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
SwitchToPortalPhase();
|
||||
return;
|
||||
}
|
||||
} else PhaseTimer -= diff;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_netherspite()
|
||||
{
|
||||
new boss_netherspite();
|
||||
}
|
||||
@@ -1,434 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Nightbane
|
||||
SD%Complete: 80
|
||||
SDComment: SDComment: Timers may incorrect
|
||||
SDCategory: Karazhan
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "karazhan.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// phase 1
|
||||
SPELL_BELLOWING_ROAR = 39427,
|
||||
SPELL_CHARRED_EARTH = 30129,
|
||||
SPELL_DISTRACTING_ASH = 30130,
|
||||
SPELL_SMOLDERING_BREATH = 30210,
|
||||
SPELL_TAIL_SWEEP = 25653,
|
||||
// phase 2
|
||||
SPELL_RAIN_OF_BONES = 37098,
|
||||
SPELL_SMOKING_BLAST = 37057,
|
||||
SPELL_FIREBALL_BARRAGE = 30282,
|
||||
SPELL_SEARING_CINDERS = 30127,
|
||||
SPELL_SUMMON_SKELETON = 30170
|
||||
};
|
||||
|
||||
enum Says
|
||||
{
|
||||
EMOTE_SUMMON = 0, // Not used in script
|
||||
YELL_AGGRO = 1,
|
||||
YELL_FLY_PHASE = 2,
|
||||
YELL_LAND_PHASE = 3,
|
||||
EMOTE_BREATH = 4
|
||||
};
|
||||
|
||||
float IntroWay[8][3] =
|
||||
{
|
||||
{-11053.37f, -1794.48f, 149.00f},
|
||||
{-11141.07f, -1841.40f, 125.00f},
|
||||
{-11187.28f, -1890.23f, 125.00f},
|
||||
{-11189.20f, -1931.25f, 125.00f},
|
||||
{-11153.76f, -1948.93f, 125.00f},
|
||||
{-11128.73f, -1929.75f, 125.00f},
|
||||
{-11140.00f, -1915.00f, 122.00f},
|
||||
{-11163.00f, -1903.00f, 91.473f}
|
||||
};
|
||||
|
||||
class boss_nightbane : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_nightbane() : CreatureScript("boss_nightbane") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new boss_nightbaneAI (creature);
|
||||
}
|
||||
|
||||
struct boss_nightbaneAI : public ScriptedAI
|
||||
{
|
||||
boss_nightbaneAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
Intro = true;
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
uint32 Phase;
|
||||
|
||||
bool RainBones;
|
||||
bool Skeletons;
|
||||
|
||||
uint32 BellowingRoarTimer;
|
||||
uint32 CharredEarthTimer;
|
||||
uint32 DistractingAshTimer;
|
||||
uint32 SmolderingBreathTimer;
|
||||
uint32 TailSweepTimer;
|
||||
uint32 RainofBonesTimer;
|
||||
uint32 SmokingBlastTimer;
|
||||
uint32 FireballBarrageTimer;
|
||||
uint32 SearingCindersTimer;
|
||||
|
||||
uint32 FlyCount;
|
||||
uint32 FlyTimer;
|
||||
|
||||
bool Intro;
|
||||
bool Flying;
|
||||
bool Movement;
|
||||
|
||||
uint32 MovePhase;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
BellowingRoarTimer = 30000;
|
||||
CharredEarthTimer = 15000;
|
||||
DistractingAshTimer = 20000;
|
||||
SmolderingBreathTimer = 10000;
|
||||
TailSweepTimer = 12000;
|
||||
RainofBonesTimer = 10000;
|
||||
SmokingBlastTimer = 20000;
|
||||
FireballBarrageTimer = 13000;
|
||||
SearingCindersTimer = 14000;
|
||||
|
||||
Phase = 1;
|
||||
FlyCount = 0;
|
||||
MovePhase = 0;
|
||||
|
||||
me->SetSpeed(MOVE_RUN, 2.0f);
|
||||
me->SetDisableGravity(Intro);
|
||||
me->SetWalk(false);
|
||||
me->setActive(true);
|
||||
|
||||
if (instance)
|
||||
{
|
||||
if (instance->GetData(TYPE_NIGHTBANE) == DONE)
|
||||
me->DisappearAndDie();
|
||||
else
|
||||
instance->SetData(TYPE_NIGHTBANE, NOT_STARTED);
|
||||
}
|
||||
|
||||
HandleTerraceDoors(true);
|
||||
|
||||
Flying = false;
|
||||
Movement = false;
|
||||
|
||||
if (!Intro)
|
||||
{
|
||||
me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
}
|
||||
|
||||
void HandleTerraceDoors(bool open)
|
||||
{
|
||||
if (instance)
|
||||
{
|
||||
instance->HandleGameObject(instance->GetData64(DATA_MASTERS_TERRACE_DOOR_1), open);
|
||||
instance->HandleGameObject(instance->GetData64(DATA_MASTERS_TERRACE_DOOR_2), open);
|
||||
}
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
if (instance)
|
||||
instance->SetData(TYPE_NIGHTBANE, IN_PROGRESS);
|
||||
|
||||
HandleTerraceDoors(false);
|
||||
Talk(YELL_AGGRO);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who)
|
||||
{
|
||||
if (!Intro && !Flying)
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
if (instance)
|
||||
instance->SetData(TYPE_NIGHTBANE, DONE);
|
||||
|
||||
HandleTerraceDoors(true);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who)
|
||||
{
|
||||
if (!Intro && !Flying)
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id)
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (Intro)
|
||||
{
|
||||
if (id >= 8)
|
||||
{
|
||||
Intro = false;
|
||||
me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
|
||||
return;
|
||||
}
|
||||
|
||||
MovePhase = id+1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Flying)
|
||||
{
|
||||
if (id == 0)
|
||||
{
|
||||
Talk(EMOTE_BREATH);
|
||||
Flying = false;
|
||||
Phase = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (id < 8)
|
||||
MovePhase = id+1;
|
||||
else
|
||||
{
|
||||
Phase = 1;
|
||||
Flying = false;
|
||||
Movement = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summoned)
|
||||
{
|
||||
summoned->AI()->AttackStart(me->GetVictim());
|
||||
}
|
||||
|
||||
void TakeOff()
|
||||
{
|
||||
Talk(YELL_FLY_PHASE);
|
||||
|
||||
me->InterruptSpell(CURRENT_GENERIC_SPELL);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->SetDisableGravity(true);
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MovePoint(0, IntroWay[2][0], IntroWay[2][1], IntroWay[2][2]);
|
||||
|
||||
Flying = true;
|
||||
|
||||
FlyTimer = urand(45000, 60000); //timer wrong between 45 and 60 seconds
|
||||
++FlyCount;
|
||||
|
||||
RainofBonesTimer = 5000; //timer wrong (maybe)
|
||||
RainBones = false;
|
||||
Skeletons = false;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (Intro)
|
||||
{
|
||||
if (MovePhase)
|
||||
{
|
||||
if (MovePhase >= 7)
|
||||
{
|
||||
me->SetDisableGravity(false);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]);
|
||||
}
|
||||
MovePhase = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (Flying && MovePhase)
|
||||
{
|
||||
if (MovePhase >= 7)
|
||||
{
|
||||
me->SetDisableGravity(false);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]);
|
||||
}
|
||||
else
|
||||
me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]);
|
||||
|
||||
MovePhase = 0;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (Flying)
|
||||
return;
|
||||
|
||||
// Phase 1 "GROUND FIGHT"
|
||||
if (Phase == 1)
|
||||
{
|
||||
if (Movement)
|
||||
{
|
||||
DoStartMovement(me->GetVictim());
|
||||
Movement = false;
|
||||
}
|
||||
|
||||
if (BellowingRoarTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_BELLOWING_ROAR);
|
||||
BellowingRoarTimer = urand(30000, 40000);
|
||||
} else BellowingRoarTimer -= diff;
|
||||
|
||||
if (SmolderingBreathTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SMOLDERING_BREATH);
|
||||
SmolderingBreathTimer = 20000;
|
||||
} else SmolderingBreathTimer -= diff;
|
||||
|
||||
if (CharredEarthTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_CHARRED_EARTH);
|
||||
CharredEarthTimer = 20000;
|
||||
} else CharredEarthTimer -= diff;
|
||||
|
||||
if (TailSweepTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
if (!me->HasInArc(M_PI, target))
|
||||
DoCast(target, SPELL_TAIL_SWEEP);
|
||||
TailSweepTimer = 15000;
|
||||
} else TailSweepTimer -= diff;
|
||||
|
||||
if (SearingCindersTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_SEARING_CINDERS);
|
||||
SearingCindersTimer = 10000;
|
||||
} else SearingCindersTimer -= diff;
|
||||
|
||||
uint32 Prozent = uint32(me->GetHealthPct());
|
||||
|
||||
if (Prozent < 75 && FlyCount == 0) // first take off 75%
|
||||
TakeOff();
|
||||
|
||||
if (Prozent < 50 && FlyCount == 1) // secound take off 50%
|
||||
TakeOff();
|
||||
|
||||
if (Prozent < 25 && FlyCount == 2) // third take off 25%
|
||||
TakeOff();
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
//Phase 2 "FLYING FIGHT"
|
||||
if (Phase == 2)
|
||||
{
|
||||
if (!RainBones)
|
||||
{
|
||||
if (!Skeletons)
|
||||
{
|
||||
for (uint8 i = 0; i <= 3; ++i)
|
||||
{
|
||||
DoCastVictim(SPELL_SUMMON_SKELETON);
|
||||
Skeletons = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (RainofBonesTimer < diff && !RainBones) // only once at the beginning of phase 2
|
||||
{
|
||||
DoCastVictim(SPELL_RAIN_OF_BONES);
|
||||
RainBones = true;
|
||||
SmokingBlastTimer = 20000;
|
||||
} else RainofBonesTimer -= diff;
|
||||
|
||||
if (DistractingAshTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_DISTRACTING_ASH);
|
||||
DistractingAshTimer = 2000; //timer wrong
|
||||
} else DistractingAshTimer -= diff;
|
||||
}
|
||||
|
||||
if (RainBones)
|
||||
{
|
||||
if (SmokingBlastTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SMOKING_BLAST);
|
||||
SmokingBlastTimer = 1500; //timer wrong
|
||||
} else SmokingBlastTimer -= diff;
|
||||
}
|
||||
|
||||
if (FireballBarrageTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_FARTHEST, 0))
|
||||
DoCast(target, SPELL_FIREBALL_BARRAGE);
|
||||
FireballBarrageTimer = 20000;
|
||||
} else FireballBarrageTimer -= diff;
|
||||
|
||||
if (FlyTimer <= diff) //landing
|
||||
{
|
||||
Talk(YELL_LAND_PHASE);
|
||||
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MovePoint(3, IntroWay[3][0], IntroWay[3][1], IntroWay[3][2]);
|
||||
|
||||
Flying = true;
|
||||
} else FlyTimer -= diff;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class go_blackened_urn : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
go_blackened_urn() : GameObjectScript("go_blackened_urn") { }
|
||||
|
||||
bool OnGossipHello(Player* pPlayer, GameObject *pGo)
|
||||
{
|
||||
if (InstanceScript* pInstance = pGo->GetInstanceScript())
|
||||
{
|
||||
if (pInstance->GetData(TYPE_NIGHTBANE) != DONE && !pGo->FindNearestCreature(17225, 40.0f))
|
||||
if (Creature *cr = ObjectAccessor::GetCreature(*pPlayer, pInstance->GetData64(DATA_NIGHTBANE)))
|
||||
cr->GetMotionMaster()->MovePoint(0, IntroWay[0][0], IntroWay[0][1], IntroWay[0][2]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_nightbane()
|
||||
{
|
||||
new boss_nightbane();
|
||||
new go_blackened_urn();
|
||||
}
|
||||
@@ -1,596 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Prince_Malchezzar
|
||||
SD%Complete: 100
|
||||
SDComment:
|
||||
SDCategory: Karazhan
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "karazhan.h"
|
||||
#include "SpellInfo.h"
|
||||
|
||||
// 18 Coordinates for Infernal spawns
|
||||
struct InfernalPoint
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
#define INFERNAL_Z 275.5f
|
||||
|
||||
static InfernalPoint InfernalPoints[] =
|
||||
{
|
||||
{-10922.8f, -1985.2f},
|
||||
{-10916.2f, -1996.2f},
|
||||
{-10932.2f, -2008.1f},
|
||||
{-10948.8f, -2022.1f},
|
||||
{-10958.7f, -1997.7f},
|
||||
{-10971.5f, -1997.5f},
|
||||
{-10990.8f, -1995.1f},
|
||||
{-10989.8f, -1976.5f},
|
||||
{-10971.6f, -1973.0f},
|
||||
{-10955.5f, -1974.0f},
|
||||
{-10939.6f, -1969.8f},
|
||||
{-10958.0f, -1952.2f},
|
||||
{-10941.7f, -1954.8f},
|
||||
{-10943.1f, -1988.5f},
|
||||
{-10948.8f, -2005.1f},
|
||||
{-10984.0f, -2019.3f},
|
||||
{-10932.8f, -1979.6f},
|
||||
{-10935.7f, -1996.0f}
|
||||
};
|
||||
|
||||
//Enfeeble is supposed to reduce hp to 1 and then heal player back to full when it ends
|
||||
//Along with reducing healing and regen while enfeebled to 0%
|
||||
//This spell effect will only reduce healing
|
||||
enum PrinceMalchezaar
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_AXE_TOSS1 = 1,
|
||||
SAY_AXE_TOSS2 = 2,
|
||||
// SAY_SPECIAL1 = 3, Not used, needs to be implemented, but I don't know where it should be used.
|
||||
// SAY_SPECIAL2 = 4, Not used, needs to be implemented, but I don't know where it should be used.
|
||||
// SAY_SPECIAL3 = 5, Not used, needs to be implemented, but I don't know where it should be used.
|
||||
SAY_SLAY = 6,
|
||||
SAY_SUMMON = 7,
|
||||
SAY_DEATH = 8,
|
||||
|
||||
TOTAL_INFERNAL_POINTS = 18,
|
||||
|
||||
SPELL_ENFEEBLE = 30843, //Enfeeble during phase 1 and 2
|
||||
SPELL_ENFEEBLE_EFFECT = 41624,
|
||||
|
||||
SPELL_SHADOWNOVA = 30852, //Shadownova used during all phases
|
||||
SPELL_SW_PAIN = 30854, //Shadow word pain during phase 1 and 3 (different targeting rules though)
|
||||
SPELL_THRASH_PASSIVE = 12787, //Extra attack chance during phase 2
|
||||
SPELL_SUNDER_ARMOR = 30901, //Sunder armor during phase 2
|
||||
SPELL_THRASH_AURA = 12787, //Passive proc chance for thrash
|
||||
SPELL_EQUIP_AXES = 30857, //Visual for axe equiping
|
||||
SPELL_AMPLIFY_DAMAGE = 39095, //Amplifiy during phase 3
|
||||
SPELL_CLEAVE = 30131, //Same as Nightbane.
|
||||
SPELL_HELLFIRE = 30859, //Infenals' hellfire aura
|
||||
NETHERSPITE_INFERNAL = 17646, //The netherspite infernal creature
|
||||
MALCHEZARS_AXE = 17650, //Malchezar's axes (creatures), summoned during phase 3
|
||||
|
||||
INFERNAL_MODEL_INVISIBLE = 11686, //Infernal Effects
|
||||
SPELL_INFERNAL_RELAY = 30834,
|
||||
|
||||
EQUIP_ID_AXE = 33542 //Axes info
|
||||
};
|
||||
|
||||
//---------Infernal code first
|
||||
class netherspite_infernal : public CreatureScript
|
||||
{
|
||||
public:
|
||||
netherspite_infernal() : CreatureScript("netherspite_infernal") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new netherspite_infernalAI(creature);
|
||||
}
|
||||
|
||||
struct netherspite_infernalAI : public ScriptedAI
|
||||
{
|
||||
netherspite_infernalAI(Creature* creature) : ScriptedAI(creature),
|
||||
HellfireTimer(0), CleanupTimer(0), malchezaar(0), point(NULL) { }
|
||||
|
||||
uint32 HellfireTimer;
|
||||
uint32 CleanupTimer;
|
||||
uint64 malchezaar;
|
||||
InfernalPoint *point;
|
||||
|
||||
void Reset() { }
|
||||
void EnterCombat(Unit* /*who*/) { }
|
||||
void MoveInLineOfSight(Unit* /*who*/) { }
|
||||
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (HellfireTimer)
|
||||
{
|
||||
if (HellfireTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_HELLFIRE);
|
||||
HellfireTimer = 0;
|
||||
}
|
||||
else HellfireTimer -= diff;
|
||||
}
|
||||
|
||||
if (CleanupTimer)
|
||||
{
|
||||
if (CleanupTimer <= diff)
|
||||
{
|
||||
Cleanup();
|
||||
CleanupTimer = 0;
|
||||
} else CleanupTimer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who)
|
||||
{
|
||||
if (Unit* unit = ObjectAccessor::GetUnit(*me, malchezaar))
|
||||
if (Creature* creature = unit->ToCreature())
|
||||
creature->AI()->KilledUnit(who);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*who*/, const SpellInfo* spell)
|
||||
{
|
||||
if (spell->Id == SPELL_INFERNAL_RELAY)
|
||||
{
|
||||
me->SetDisplayId(me->GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID));
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
HellfireTimer = 4000;
|
||||
CleanupTimer = 170000;
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* done_by, uint32 &damage, DamageEffectType, SpellSchoolMask)
|
||||
{
|
||||
if (!done_by || done_by->GetGUID() != malchezaar)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
void Cleanup();
|
||||
};
|
||||
};
|
||||
|
||||
class boss_malchezaar : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_malchezaar() : CreatureScript("boss_malchezaar") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return GetInstanceAI<boss_malchezaarAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_malchezaarAI : public ScriptedAI
|
||||
{
|
||||
boss_malchezaarAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
memset(axes, 0, sizeof(axes));
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
uint32 EnfeebleTimer;
|
||||
uint32 EnfeebleResetTimer;
|
||||
uint32 ShadowNovaTimer;
|
||||
uint32 SWPainTimer;
|
||||
uint32 SunderArmorTimer;
|
||||
uint32 AmplifyDamageTimer;
|
||||
uint32 Cleave_Timer;
|
||||
uint32 InfernalTimer;
|
||||
uint32 AxesTargetSwitchTimer;
|
||||
uint32 InfernalCleanupTimer;
|
||||
|
||||
std::vector<uint64> infernals;
|
||||
std::vector<InfernalPoint*> positions;
|
||||
|
||||
uint64 axes[2];
|
||||
uint64 enfeeble_targets[5];
|
||||
uint32 enfeeble_health[5];
|
||||
|
||||
uint32 phase;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
AxesCleanup();
|
||||
ClearWeapons();
|
||||
InfernalCleanup();
|
||||
positions.clear();
|
||||
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
{
|
||||
enfeeble_targets[i] = 0;
|
||||
enfeeble_health[i] = 0;
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < TOTAL_INFERNAL_POINTS; ++i)
|
||||
positions.push_back(&InfernalPoints[i]);
|
||||
|
||||
EnfeebleTimer = 30000;
|
||||
EnfeebleResetTimer = 38000;
|
||||
ShadowNovaTimer = 35500;
|
||||
SWPainTimer = 20000;
|
||||
AmplifyDamageTimer = 5000;
|
||||
Cleave_Timer = 8000;
|
||||
InfernalTimer = 40000;
|
||||
InfernalCleanupTimer = 47000;
|
||||
AxesTargetSwitchTimer = urand(7500, 20000);
|
||||
SunderArmorTimer = urand(5000, 10000);
|
||||
phase = 1;
|
||||
|
||||
instance->HandleGameObject(instance->GetData64(DATA_GO_NETHER_DOOR), true);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/)
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
AxesCleanup();
|
||||
ClearWeapons();
|
||||
InfernalCleanup();
|
||||
positions.clear();
|
||||
|
||||
for (uint8 i = 0; i < TOTAL_INFERNAL_POINTS; ++i)
|
||||
positions.push_back(&InfernalPoints[i]);
|
||||
|
||||
instance->HandleGameObject(instance->GetData64(DATA_GO_NETHER_DOOR), true);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/)
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
instance->HandleGameObject(instance->GetData64(DATA_GO_NETHER_DOOR), false); // Open the door leading further in
|
||||
}
|
||||
|
||||
void InfernalCleanup()
|
||||
{
|
||||
//Infernal Cleanup
|
||||
for (std::vector<uint64>::const_iterator itr = infernals.begin(); itr != infernals.end(); ++itr)
|
||||
if (Unit* pInfernal = ObjectAccessor::GetUnit(*me, *itr))
|
||||
if (pInfernal->IsAlive())
|
||||
{
|
||||
pInfernal->SetVisible(false);
|
||||
pInfernal->setDeathState(JUST_DIED);
|
||||
}
|
||||
|
||||
infernals.clear();
|
||||
}
|
||||
|
||||
void AxesCleanup()
|
||||
{
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
{
|
||||
Unit* axe = ObjectAccessor::GetUnit(*me, axes[i]);
|
||||
if (axe && axe->IsAlive())
|
||||
Unit::Kill(axe, axe);
|
||||
axes[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ClearWeapons()
|
||||
{
|
||||
SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
|
||||
me->SetCanDualWield(false);
|
||||
}
|
||||
|
||||
void EnfeebleHealthEffect()
|
||||
{
|
||||
const SpellInfo* info = sSpellMgr->GetSpellInfo(SPELL_ENFEEBLE_EFFECT);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
ThreatContainer::StorageType const &t_list = me->getThreatManager().getThreatList();
|
||||
std::vector<Unit*> targets;
|
||||
|
||||
if (t_list.empty())
|
||||
return;
|
||||
|
||||
//begin + 1, so we don't target the one with the highest threat
|
||||
ThreatContainer::StorageType::const_iterator itr = t_list.begin();
|
||||
std::advance(itr, 1);
|
||||
for (; itr != t_list.end(); ++itr) //store the threat list in a different container
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
|
||||
if (target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
|
||||
targets.push_back(target);
|
||||
|
||||
//cut down to size if we have more than 5 targets
|
||||
while (targets.size() > 5)
|
||||
targets.erase(targets.begin()+rand()%targets.size());
|
||||
|
||||
uint32 i = 0;
|
||||
for (std::vector<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter, ++i)
|
||||
if (Unit* target = *iter)
|
||||
{
|
||||
enfeeble_targets[i] = target->GetGUID();
|
||||
enfeeble_health[i] = target->GetHealth();
|
||||
|
||||
target->CastSpell(target, SPELL_ENFEEBLE, true, 0, 0, me->GetGUID());
|
||||
target->SetHealth(1);
|
||||
}
|
||||
}
|
||||
|
||||
void EnfeebleResetHealth()
|
||||
{
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*me, enfeeble_targets[i]);
|
||||
if (target && target->IsAlive())
|
||||
target->SetHealth(enfeeble_health[i]);
|
||||
enfeeble_targets[i] = 0;
|
||||
enfeeble_health[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SummonInfernal(const uint32 /*diff*/)
|
||||
{
|
||||
InfernalPoint *point = NULL;
|
||||
Position pos;
|
||||
if ((me->GetMapId() != 532) || positions.empty())
|
||||
me->GetRandomNearPosition(pos, 60);
|
||||
else
|
||||
{
|
||||
point = Trinity::Containers::SelectRandomContainerElement(positions);
|
||||
pos.Relocate(point->x, point->y, INFERNAL_Z, frand(0.0f, float(M_PI * 2)));
|
||||
}
|
||||
|
||||
Creature* infernal = me->SummonCreature(NETHERSPITE_INFERNAL, pos, TEMPSUMMON_TIMED_DESPAWN, 180000);
|
||||
|
||||
if (infernal)
|
||||
{
|
||||
infernal->SetDisplayId(INFERNAL_MODEL_INVISIBLE);
|
||||
infernal->setFaction(me->getFaction());
|
||||
if (point)
|
||||
CAST_AI(netherspite_infernal::netherspite_infernalAI, infernal->AI())->point=point;
|
||||
CAST_AI(netherspite_infernal::netherspite_infernalAI, infernal->AI())->malchezaar=me->GetGUID();
|
||||
|
||||
infernals.push_back(infernal->GetGUID());
|
||||
DoCast(infernal, SPELL_INFERNAL_RELAY);
|
||||
}
|
||||
|
||||
Talk(SAY_SUMMON);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (EnfeebleResetTimer && EnfeebleResetTimer <= diff) // Let's not forget to reset that
|
||||
{
|
||||
EnfeebleResetHealth();
|
||||
EnfeebleResetTimer = 0;
|
||||
} else EnfeebleResetTimer -= diff;
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_STUNNED)) // While shifting to phase 2 malchezaar stuns himself
|
||||
return;
|
||||
|
||||
if (me->GetUInt64Value(UNIT_FIELD_TARGET) != me->GetVictim()->GetGUID())
|
||||
me->SetTarget(me->GetVictim()->GetGUID());
|
||||
|
||||
if (phase == 1)
|
||||
{
|
||||
if (HealthBelowPct(60))
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
|
||||
phase = 2;
|
||||
|
||||
//animation
|
||||
DoCast(me, SPELL_EQUIP_AXES);
|
||||
|
||||
//text
|
||||
Talk(SAY_AXE_TOSS1);
|
||||
|
||||
//passive thrash aura
|
||||
DoCast(me, SPELL_THRASH_AURA, true);
|
||||
|
||||
//models
|
||||
SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE);
|
||||
|
||||
me->SetAttackTime(OFF_ATTACK, (me->GetAttackTime(BASE_ATTACK)*150)/100);
|
||||
me->SetCanDualWield(true);
|
||||
}
|
||||
}
|
||||
else if (phase == 2)
|
||||
{
|
||||
if (HealthBelowPct(30))
|
||||
{
|
||||
InfernalTimer = 15000;
|
||||
|
||||
phase = 3;
|
||||
|
||||
ClearWeapons();
|
||||
|
||||
//remove thrash
|
||||
me->RemoveAurasDueToSpell(SPELL_THRASH_AURA);
|
||||
|
||||
Talk(SAY_AXE_TOSS2);
|
||||
|
||||
Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
{
|
||||
Creature* axe = me->SummonCreature(MALCHEZARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000);
|
||||
if (axe)
|
||||
{
|
||||
axe->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
axe->setFaction(me->getFaction());
|
||||
axes[i] = axe->GetGUID();
|
||||
if (target)
|
||||
{
|
||||
axe->AI()->AttackStart(target);
|
||||
//axe->getThreatManager().tauntApply(target); //Taunt Apply and fade out does not work properly
|
||||
// So we'll use a hack to add a lot of threat to our target
|
||||
axe->AddThreat(target, 10000000.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ShadowNovaTimer > 35000)
|
||||
ShadowNovaTimer = EnfeebleTimer + 5000;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SunderArmorTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SUNDER_ARMOR);
|
||||
SunderArmorTimer = urand(10000, 18000);
|
||||
} else SunderArmorTimer -= diff;
|
||||
|
||||
if (Cleave_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
Cleave_Timer = urand(6000, 12000);
|
||||
} else Cleave_Timer -= diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AxesTargetSwitchTimer <= diff)
|
||||
{
|
||||
AxesTargetSwitchTimer = urand(7500, 20000);
|
||||
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
{
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
{
|
||||
if (Unit* axe = ObjectAccessor::GetUnit(*me, axes[i]))
|
||||
{
|
||||
if (axe->GetVictim())
|
||||
DoModifyThreatPercent(axe->GetVictim(), -100);
|
||||
if (target)
|
||||
axe->AddThreat(target, 1000000.0f);
|
||||
//axe->getThreatManager().tauntFadeOut(axe->GetVictim());
|
||||
//axe->getThreatManager().tauntApply(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else AxesTargetSwitchTimer -= diff;
|
||||
|
||||
if (AmplifyDamageTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
||||
DoCast(target, SPELL_AMPLIFY_DAMAGE);
|
||||
AmplifyDamageTimer = urand(20000, 30000);
|
||||
} else AmplifyDamageTimer -= diff;
|
||||
}
|
||||
|
||||
//Time for global and double timers
|
||||
if (InfernalTimer <= diff)
|
||||
{
|
||||
SummonInfernal(diff);
|
||||
InfernalTimer = phase == 3 ? 14500 : 44500; // 15 secs in phase 3, 45 otherwise
|
||||
} else InfernalTimer -= diff;
|
||||
|
||||
if (ShadowNovaTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOWNOVA);
|
||||
ShadowNovaTimer = phase == 3 ? 31000 : uint32(-1);
|
||||
} else ShadowNovaTimer -= diff;
|
||||
|
||||
if (phase != 2)
|
||||
{
|
||||
if (SWPainTimer <= diff)
|
||||
{
|
||||
Unit* target = NULL;
|
||||
if (phase == 1)
|
||||
target = me->GetVictim(); // the tank
|
||||
else // anyone but the tank
|
||||
target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true);
|
||||
|
||||
if (target)
|
||||
DoCast(target, SPELL_SW_PAIN);
|
||||
|
||||
SWPainTimer = 20000;
|
||||
} else SWPainTimer -= diff;
|
||||
}
|
||||
|
||||
if (phase != 3)
|
||||
{
|
||||
if (EnfeebleTimer <= diff)
|
||||
{
|
||||
EnfeebleHealthEffect();
|
||||
EnfeebleTimer = 30000;
|
||||
ShadowNovaTimer = 5000;
|
||||
EnfeebleResetTimer = 9000;
|
||||
} else EnfeebleTimer -= diff;
|
||||
}
|
||||
|
||||
if (phase == 2)
|
||||
DoMeleeAttacksIfReady();
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void DoMeleeAttacksIfReady()
|
||||
{
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()) && !me->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
//Check for base attack
|
||||
if (me->isAttackReady() && me->GetVictim())
|
||||
{
|
||||
me->AttackerStateUpdate(me->GetVictim());
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
//Check for offhand attack
|
||||
if (me->isAttackReady(OFF_ATTACK) && me->GetVictim())
|
||||
{
|
||||
me->AttackerStateUpdate(me->GetVictim(), OFF_ATTACK);
|
||||
me->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cleanup(Creature* infernal, InfernalPoint *point)
|
||||
{
|
||||
for (std::vector<uint64>::iterator itr = infernals.begin(); itr!= infernals.end(); ++itr)
|
||||
if (*itr == infernal->GetGUID())
|
||||
{
|
||||
infernals.erase(itr);
|
||||
break;
|
||||
}
|
||||
|
||||
positions.push_back(point);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void netherspite_infernal::netherspite_infernalAI::Cleanup()
|
||||
{
|
||||
Creature* pMalchezaar = ObjectAccessor::GetCreature(*me, malchezaar);
|
||||
|
||||
if (pMalchezaar && pMalchezaar->IsAlive())
|
||||
CAST_AI(boss_malchezaar::boss_malchezaarAI, pMalchezaar->AI())->Cleanup(me, point);
|
||||
}
|
||||
|
||||
void AddSC_boss_malchezaar()
|
||||
{
|
||||
new boss_malchezaar();
|
||||
new netherspite_infernal();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user