/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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 3 of the License, or
(at your option) any later version.
EQ2Emulator 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 EQ2Emulator. If not, see .
*/
#include "HeroicOp.h"
#include "../../common/Log.h"
#include "../Rules/Rules.h"
extern MasterHeroicOPList master_ho_list;
extern RuleManager rule_manager;
HeroicOP::HeroicOP() {
m_complete = 0;
m_currentStage = 0;
m_wheel = 0;
m_target = 0;
m_startTime = 0;
m_totalTime = 0;
m_shifted = false;
for (int8 i = 0; i < 6; i++)
countered[i] = 0;
}
HeroicOP::~HeroicOP() {
starters.clear();
}
void HeroicOP::SetWheel(HeroicOPWheel* val) {
if (!m_wheel)
m_wheel = val;
else
LogWrite(SPELL__ERROR, 0, "HO", "Attempted to set the wheel on a heroic op with a wheel already set");
}
void HeroicOP::SetTarget(int32 val) {
m_target = val;
}
bool HeroicOP::UpdateHeroicOP(int16 icon) {
bool ret = false;
vector::iterator itr;
vector temp;
HeroicOPStarter* starter = 0;
LogWrite(SPELL__DEBUG, 0, "HO", "Current Stage %u, wheel exists: %u, looking for icon %u", m_currentStage, m_wheel ? 1 : 0, icon);
// If no wheel is set we are dealing with a starter chain still.
if (!m_wheel) {
// Loop through the starter chains
for (itr = starters.begin(); itr != starters.end(); itr++) {
starter = *itr;
// See if the icon matches the ability at our current stage, if not add it to a list to be removed
if (starter->abilities[m_currentStage] == icon)
ret = true;
else
temp.push_back(*itr);
}
if (ret) {
// ret = true so we had a match, first thing to do is remove those that didn't match
vector::iterator remove_itr;
for (remove_itr = temp.begin(); remove_itr != temp.end(); remove_itr++)
{
std::vector::iterator it = std::find(starters.begin(), starters.end(), *remove_itr);
starters.erase(it);
}
// now advance the current stage
m_currentStage++;
// Temp pointer to hold the completed chain, if any
HeroicOPStarter* complete_starter = 0;
// now loop through those that are left and check the next stage abilities for a 0xFFFF
for (itr = starters.begin(); itr != starters.end(); itr++) {
starter = *itr;
// Found one that is 0xFFFF, means the starter chain is done, get a wheel and reset the stage to 0
if ((starter->abilities[m_currentStage] == 0xFFFF)) {
LogWrite(SPELL__DEBUG, 0, "HO", "Current Stage %u, starter reset (new stage 0)", m_currentStage);
// reset the stage
ResetStage();
// geth the wheel
m_wheel = master_ho_list.GetWheel(starter);
// store the starter chain that is completed
complete_starter = starter;
// set the start time to now
SetStartTime(Timer::GetCurrentTime2());
// set the total time to complete the real to was the admin set in rules (default 10.0f)
SetTotalTime(rule_manager.GetGlobalRule(R_Zone, HOTime)->GetFloat());
// We set a wheel so we are done, kill the loop
break;
}
}
// Check to see if the completed start chain pointer was set
if (complete_starter) {
LogWrite(SPELL__DEBUG, 0, "HO", "Current Stage %u, complete_starter set", m_currentStage);
// clear the starter list
starters.clear();
// add the completed starter back in, we do this in case we need this starter again we can just do starters.at(0), for example shifting the wheel
starters.push_back(complete_starter);
}
}
}
else {
LogWrite(SPELL__DEBUG, 0, "HO", "Current Stage %u, wheel order: %u", m_currentStage, m_wheel->order);
// Wheel was set so we need to check the order it needs to be completed in.
if (m_wheel->order == 0) {
// No order
// Flag used to see if we can shift the wheel
bool can_shift = true;
// Check the icons and flag the ability as countered if there is a match
for (int8 i = 0; i < 6; i++) {
if (countered[i] == 1) {
// progress made on this wheel so we can't shift it
can_shift = false;
}
if (m_wheel->abilities[i] == icon) {
countered[i] = 1;
ret = true;
}
}
if (ret) {
// As we found a match lets loop through to see if we completed the ho
bool finished = true;
for (int8 i = 0; i < 6; i++) {
// if the ability is not 0xFFFF and countered is 0 then we still have more to go
if (m_wheel->abilities[i] != 0xFFFF && countered[i] == 0) {
finished = false;
break;
}
}
// is we finished the ho set the complete flag
if (finished)
SetComplete(2);
}
if (!ret && can_shift && m_wheel->shift_icon == icon) {
// can shift, icon matched shift icon, and no progress made
ret = ShiftWheel();
}
}
else {
// In order
// Check to see if we can shift the wheel
if (countered[0] == 0 && icon == m_wheel->shift_icon) {
// Can only shift the icon if nothing has completed yet (countered[0] = 0)
ret = ShiftWheel();
}
// Check the current stage and compare it to the icon
else if (m_wheel->abilities[m_currentStage] == icon) {
// Is a match so flag this stage as done
countered[m_currentStage] = 1;
// Advance the stage
m_currentStage++;
// Set the return value to true
ret = true;
// Check the next stage, if it is over 6 or equal to 0xFFFF flag the HO as complete
if (m_currentStage > 6 || m_wheel->abilities[m_currentStage] == 0xFFFF)
SetComplete(2);
}
}
}
return ret;
}
void HeroicOP::AddStarterChain(HeroicOPStarter* starter) {
starters.push_back(starter);
}
bool HeroicOP::ShiftWheel() {
// Can only shift once so if we already have return out
if (HasShifted())
return false;
// Clear the wheel
m_wheel = 0;
// Get a new Wheel
SetWheel(master_ho_list.GetWheel(starters.at(0)));
// Set the ho as shifted
m_shifted = true;
return true;
}
MasterHeroicOPList::MasterHeroicOPList() {
}
MasterHeroicOPList::~MasterHeroicOPList() {
map > >::iterator itr;
map >::iterator itr2;
vector::iterator itr3;
vector temp;
vector::iterator itr4;
// loop through the m_hoList to delete the pointers
for (itr = m_hoList.begin(); itr != m_hoList.end(); itr++) {
// loop through the second map of the m_hoList
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) {
// loop through the vector of the second map and delete the pointers
for (itr3 = itr2->second.begin(); itr3 != itr2->second.end(); itr3++)
safe_delete(*itr3);
// clear the vector
itr2->second.clear();
// put the starter in a temp list to delete later
temp.push_back(itr2->first);
}
// clear the seond map
itr->second.clear();
}
// clear the m_hoList
m_hoList.clear();
// Delete the starters
for (itr4 = temp.begin(); itr4 != temp.end(); itr4++)
safe_delete(*itr4);
// clear the temp vector
temp.clear();
}
void MasterHeroicOPList::AddStarter(int8 start_class, HeroicOPStarter* starter) {
if (m_hoList.count(start_class) == 0 || m_hoList[start_class].count(starter) == 0) {
m_hoList[start_class][starter]; // This adds the starter with out giving it a vector of wheels yet.
}
}
void MasterHeroicOPList::AddWheel(int32 starter_id, HeroicOPWheel* wheel) {
map > >::iterator itr;
map >::iterator itr2;
bool found = false;
// Loop through the list and add the wheel to the correct starter
for (itr = m_hoList.begin(); itr != m_hoList.end(); itr++) {
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) {
if (itr2->first->id == starter_id) {
// Found a match, add the wheel, set the flag to break the first loop, and break this loop
itr2->second.push_back(wheel);
found = true;
break;
}
}
// If we found a match break the first loop
if (found)
break;
}
// No match found give an error.
if (!found)
LogWrite(SPELL__DEBUG, 0, "HO", "Attempted to add a wheel to a starter (%u) that doesn't exsist", starter_id);
}
HeroicOP* MasterHeroicOPList::GetHeroicOP(int8 class_id) {
if (m_hoList.count(class_id) == 0) {
LogWrite(SPELL__ERROR, 0, "HO", "No HO's found for the given class (%i)", class_id);
return 0;
}
map >::iterator itr;
HeroicOP* ret = new HeroicOP();
// Loop through the starters for this class and add them to the HO
for (itr = m_hoList[class_id].begin(); itr != m_hoList[class_id].end(); itr++)
ret->AddStarterChain(itr->first);
return ret;
}
HeroicOPWheel* MasterHeroicOPList::GetWheel(HeroicOPStarter* starter) {
if (!starter)
return 0;
if (m_hoList.count(starter->start_class) == 0) {
LogWrite(SPELL__ERROR, 0, "HO", "Start class (%u) not found", starter->start_class);
return 0;
}
if (m_hoList[starter->start_class].count(starter) == 0) {
LogWrite(SPELL__ERROR, 0, "HO", "Wheel not found for the provided starter (%u)", starter->id);
return 0;
}
int index = MakeRandomInt(0, m_hoList[starter->start_class][starter].size() - 1);
if(index < m_hoList[starter->start_class][starter].size())
return m_hoList[starter->start_class][starter].at(index);
else
LogWrite(SPELL__ERROR, 0, "HO", "Wheel index %u for heroic_ops starter ID %u NOT Found!! Wheel starter_class %u, wheel size: %u. Wheels that match starter_link_id -> Starter 'id' missing.", index, starter->id, starter->start_class, m_hoList[starter->start_class][starter].size());
return nullptr;
}