From 63d678ce29ab9efe5f75b7a50bd74bf52a7be294 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 6 Jul 2013 03:45:06 -0700 Subject: [PATCH] Replaced npcspecialatk with special_attacks, needs more testing also gotta export new api for it as I can't remove the legacy one. Too many quests rely on the legacy functionality. --- changelog.txt | 2 +- common/StringUtil.cpp | 14 +- common/StringUtil.h | 5 +- zone/AA.cpp | 17 +-- zone/MobAI.cpp | 76 +++++----- zone/aggro.cpp | 2 +- zone/attack.cpp | 40 +++--- zone/bot.cpp | 10 +- zone/botspellsai.cpp | 2 +- zone/client.cpp | 2 +- zone/client_process.cpp | 4 +- zone/command.cpp | 2 +- zone/common.h | 3 +- zone/entity.cpp | 53 +------ zone/entity.h | 1 - zone/fearpath.cpp | 4 +- zone/horse.cpp | 8 +- zone/merc.cpp | 8 +- zone/mob.cpp | 137 ++++++++++++++++-- zone/mob.h | 26 +++- zone/npc.cpp | 175 ++++++++++------------ zone/npc.h | 1 - zone/spawn2.cpp | 35 ----- zone/special_attacks.cpp | 6 +- zone/spell_effects.cpp | 10 +- zone/spells.cpp | 16 +-- zone/trap.cpp | 9 +- zone/zone.cpp | 304 +-------------------------------------- zone/zone.h | 2 - zone/zonedb.cpp | 8 +- zone/zonedb.h | 2 - zone/zonedump.h | 34 +---- 32 files changed, 355 insertions(+), 663 deletions(-) diff --git a/changelog.txt b/changelog.txt index 74f7b54de..2b1b681e8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,7 +3,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) == 07/05/2013 == KLS: Added some lua functions KLS: Fixed some lua functions -KLS: Perl now will (like lua) keep track of the values you return from EVENT_*. This allows perl to use the extra behavior in things like EVENT_DEATH. Now g,enerally the perl system is now considered deprecated (in favor of lua in the long term) I felt this was too big a change to pass up adding when I got it working. +KLS: Perl now will (like lua) keep track of the values you return from EVENT_*. This allows perl to use the extra behavior in things like EVENT_DEATH. Now generally the perl system is now considered deprecated (in favor of lua in the long term) I felt this was too big a change to pass up adding when I got it working. == 07/02/2013 == KLS: Exported eq.follow(entity_id, [distance]) and eq.stop_follow() to lua. diff --git a/common/StringUtil.cpp b/common/StringUtil.cpp index bba3433fb..08d602b9b 100644 --- a/common/StringUtil.cpp +++ b/common/StringUtil.cpp @@ -16,8 +16,6 @@ #include "StringUtil.h" -#include -#include #include // for strncpy #include @@ -328,3 +326,15 @@ const char *ConvertArrayF(float input, char *returnchar) sprintf(returnchar, "%0.2f", input); return returnchar; } + +std::vector SplitString(const std::string &str, char delim) { + std::vector ret; + std::stringstream ss(str); + std::string item; + + while(std::getline(ss, item, delim)) { + ret.push_back(item); + } + + return ret; +} \ No newline at end of file diff --git a/common/StringUtil.h b/common/StringUtil.h index ecfacc97d..496eabcc3 100644 --- a/common/StringUtil.h +++ b/common/StringUtil.h @@ -16,7 +16,8 @@ #ifndef _STRINGUTIL_H_ #define _STRINGUTIL_H_ -#include +#include +#include #include #include "types.h" @@ -48,4 +49,6 @@ const char *ConvertArrayF(float input, char *returnchar); void RemoveApostrophes(std::string &s); char *RemoveApostrophes(const char *s); +std::vector SplitString(const std::string &s, char delim); + #endif diff --git a/zone/AA.cpp b/zone/AA.cpp index 725219cd3..d8d54e6b2 100644 --- a/zone/AA.cpp +++ b/zone/AA.cpp @@ -837,50 +837,51 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) make_npc->npc_spells_id = 7; break; case PALADIN: - make_npc->npc_attacks[0] = 'T'; + //SPECATK_TRIPLE + make_npc->special_abilities = std::to_string((long)SPECATK_TRIPLE) + std::string(",1"); make_npc->cur_hp = make_npc->cur_hp * 150 / 100; make_npc->max_hp = make_npc->max_hp * 150 / 100; make_npc->npc_spells_id = 8; break; case SHADOWKNIGHT: - make_npc->npc_attacks[0] = 'T'; + make_npc->special_abilities = std::to_string((long)SPECATK_TRIPLE) + std::string(",1"); make_npc->cur_hp = make_npc->cur_hp * 150 / 100; make_npc->max_hp = make_npc->max_hp * 150 / 100; make_npc->npc_spells_id = 9; break; case RANGER: - make_npc->npc_attacks[0] = 'Q'; + make_npc->special_abilities = std::to_string((long)SPECATK_QUAD) + std::string(",1"); make_npc->cur_hp = make_npc->cur_hp * 135 / 100; make_npc->max_hp = make_npc->max_hp * 135 / 100; make_npc->npc_spells_id = 10; break; case BARD: - make_npc->npc_attacks[0] = 'T'; + make_npc->special_abilities = std::to_string((long)SPECATK_TRIPLE) + std::string(",1"); make_npc->cur_hp = make_npc->cur_hp * 110 / 100; make_npc->max_hp = make_npc->max_hp * 110 / 100; make_npc->npc_spells_id = 11; break; case BEASTLORD: - make_npc->npc_attacks[0] = 'Q'; + make_npc->special_abilities = std::to_string((long)SPECATK_QUAD) + std::string(",1"); make_npc->cur_hp = make_npc->cur_hp * 110 / 100; make_npc->max_hp = make_npc->max_hp * 110 / 100; make_npc->npc_spells_id = 12; break; case ROGUE: - make_npc->npc_attacks[0] = 'Q'; + make_npc->special_abilities = std::to_string((long)SPECATK_QUAD) + std::string(",1"); make_npc->max_dmg = make_npc->max_dmg * 150 /100; make_npc->cur_hp = make_npc->cur_hp * 110 / 100; make_npc->max_hp = make_npc->max_hp * 110 / 100; break; case MONK: - make_npc->npc_attacks[0] = 'Q'; + make_npc->special_abilities = std::to_string((long)SPECATK_QUAD) + std::string(",1"); make_npc->max_dmg = make_npc->max_dmg * 150 /100; make_npc->cur_hp = make_npc->cur_hp * 135 / 100; make_npc->max_hp = make_npc->max_hp * 135 / 100; break; case WARRIOR: case BERSERKER: - make_npc->npc_attacks[0] = 'Q'; + make_npc->special_abilities = std::to_string((long)SPECATK_QUAD) + std::string(",1"); make_npc->max_dmg = make_npc->max_dmg * 150 /100; make_npc->cur_hp = make_npc->cur_hp * 175 / 100; make_npc->max_hp = make_npc->max_hp * 175 / 100; diff --git a/zone/MobAI.cpp b/zone/MobAI.cpp index 3d4763133..c6d014c26 100644 --- a/zone/MobAI.cpp +++ b/zone/MobAI.cpp @@ -358,7 +358,7 @@ bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float if(caster->AI_HasSpells() == false) return false; - if(caster->SpecAttacks[NPC_NO_BUFFHEAL_FRIENDS]) + if(caster->GetSpecialAbility(NPC_NO_BUFFHEAL_FRIENDS)) return false; if (iChance < 100) { @@ -522,7 +522,7 @@ void NPC::AI_Start(uint32 iMoveDelay) { if (NPCTypedata) { AI_AddNPCSpells(NPCTypedata->npc_spells_id); - NPCSpecialAttacks(NPCTypedata->npc_attacks,0); + ProcessSpecialAbilities(NPCTypedata->special_abilities); } SendTo(GetX(), GetY(), GetZ()); @@ -823,7 +823,7 @@ void Client::AI_Process() if(GetTarget()) { bool triple_attack_success = false; if((((GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER) - && GetLevel() >= 60) || SpecAttacks[SPECATK_TRIPLE]) + && GetLevel() >= 60) || GetSpecialAbility(SPECATK_TRIPLE)) && CheckDoubleAttack(true)) { Attack(GetTarget(), 13, true); @@ -1095,10 +1095,10 @@ void Mob::AI_Process() { if(DivineAura()) return; - if(SpecAttacks[TETHER] || SpecAttacks[LEASH]) { + if(GetSpecialAbility(TETHER) || GetSpecialAbility(LEASH)) { if(DistNoRootNoZ(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY()) > pAggroRange*pAggroRange) { GMMove(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY(), CastToNPC()->GetSpawnPointZ(), CastToNPC()->GetSpawnPointH()); - if(SpecAttacks[LEASH]) { + if(GetSpecialAbility(LEASH)) { SetHP(GetMaxHP()); BuffFadeAll(); WipeHateList(); @@ -1164,27 +1164,25 @@ void Mob::AI_Process() { //check double attack, this is NOT the same rules that clients use... && RandRoll < (GetLevel() + NPCDualAttackModifier)) { - if (Attack(target, 13)) + Attack(target, 13); + // lets see if we can do a triple attack with the main hand + //pets are excluded from triple and quads... + if (GetSpecialAbility(SPECATK_TRIPLE) + && !IsPet() && RandRoll < (GetLevel()+NPCTripleAttackModifier)) { - // lets see if we can do a triple attack with the main hand - //pets are excluded from triple and quads... - if (SpecAttacks[SPECATK_TRIPLE] - && !IsPet() && RandRoll < (GetLevel()+NPCTripleAttackModifier)) + Attack(target, 13); + // now lets check the quad attack + if (GetSpecialAbility(SPECATK_QUAD) + && RandRoll < (GetLevel() + NPCQuadAttackModifier)) { - if (Attack(target, 13)) - { // now lets check the quad attack - if (SpecAttacks[SPECATK_QUAD] - && RandRoll < (GetLevel() + NPCQuadAttackModifier)) - { - Attack(target, 13); - } - } + Attack(target, 13); } + } } } - if (SpecAttacks[SPECATK_FLURRY]) { + if (GetSpecialAbility(SPECATK_FLURRY)) { uint8 npc_flurry = RuleI(Combat, NPCFlurryChance); if (GetFlurryChance()) @@ -1206,14 +1204,14 @@ void Mob::AI_Process() { } } - if (SpecAttacks[SPECATK_RAMPAGE]) + if (GetSpecialAbility(SPECATK_RAMPAGE)) { //simply based off dex for now, probably a better calc if(MakeRandomInt(0, 100) < ((int)(GetDEX() / ((GetLevel() * 0.760) + 10.0)) + 5)) Rampage(); } - if (SpecAttacks[SPECATK_AREA_RAMPAGE]) + if (GetSpecialAbility(SPECATK_AREA_RAMPAGE)) { //simply based off dex for now, probably a better calc @@ -1227,7 +1225,7 @@ void Mob::AI_Process() { { int myclass = GetClass(); //can only dual wield without a weapon if your a monk - if(SpecAttacks[SPECATK_INNATE_DW] || (GetEquipment(MATERIAL_SECONDARY) != 0 && GetLevel() > 29) || myclass == MONK || myclass == MONKGM) { + if(GetSpecialAbility(SPECATK_INNATE_DW) || (GetEquipment(MATERIAL_SECONDARY) != 0 && GetLevel() > 29) || myclass == MONK || myclass == MONKGM) { float DualWieldProbability = (GetSkill(DUAL_WIELD) + GetLevel()) / 400.0f; if(MakeRandomFloat(0.0, 1.0) < DualWieldProbability) { @@ -1274,7 +1272,7 @@ void Mob::AI_Process() { if (!HateSummon()) { //could not summon them, check ranged... - if(SpecAttacks[SPECATK_RANGED_ATK]) + if(GetSpecialAbility(SPECATK_RANGED_ATK)) doranged = true; // Now pursue @@ -1863,33 +1861,27 @@ void Mob::StartEnrage() // dont continue if already enraged if (bEnraged) return; - if (SpecAttackTimers[SPECATK_ENRAGE] && !SpecAttackTimers[SPECATK_ENRAGE]->Check()) - return; - // see if NPC has possibility to enrage - if (!SpecAttacks[SPECATK_ENRAGE]) - return; - // check if timer exists (should be true at all times) - if (SpecAttackTimers[SPECATK_ENRAGE]) - { - safe_delete(SpecAttackTimers[SPECATK_ENRAGE]); - SpecAttackTimers[SPECATK_ENRAGE] = nullptr; - } - if (!SpecAttackTimers[SPECATK_ENRAGE]) - { - SpecAttackTimers[SPECATK_ENRAGE] = new Timer(EnragedDurationTimer); - } + if(!GetSpecialAbility(SPECATK_ENRAGE)) + return; + + Timer *timer = GetSpecialAbilityTimer(SPECATK_ENRAGE); + if (timer && !timer->Check()) + return; + + StartSpecialAbilityTimer(SPECATK_ENRAGE, EnragedDurationTimer); + // start the timer. need to call IsEnraged frequently since we dont have callback timers :-/ - SpecAttackTimers[SPECATK_ENRAGE]->Start(); bEnraged = true; entity_list.MessageClose_StringID(this, true, 200, MT_NPCEnrage, NPC_ENRAGE_START, GetCleanName()); } void Mob::ProcessEnrage(){ if(IsEnraged()){ - if(SpecAttackTimers[SPECATK_ENRAGE] && SpecAttackTimers[SPECATK_ENRAGE]->Check()){ + Timer *timer = GetSpecialAbilityTimer(SPECATK_ENRAGE); + if(timer && timer->Check()){ entity_list.MessageClose_StringID(this, true, 200, MT_NPCEnrage, NPC_ENRAGE_END, GetCleanName()); - SpecAttackTimers[SPECATK_ENRAGE]->Start(EnragedTimer); + StartSpecialAbilityTimer(SPECATK_ENRAGE, EnragedTimer); bEnraged = false; } } @@ -1921,7 +1913,7 @@ bool Mob::AddRampage(Mob *mob) if(!mob) return false; - if (!SpecAttacks[SPECATK_RAMPAGE]) + if (!GetSpecialAbility(SPECATK_RAMPAGE)) return false; for (int i = 0; i < RampageArray.size(); i++) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 52899a856..3867a815d 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -517,7 +517,7 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack) if(this == target) // you can attack yourself return true; - if(target->SpecAttacks[NO_HARM_FROM_CLIENT]){ + if(target->GetSpecialAbility(NO_HARM_FROM_CLIENT)){ return false; } diff --git a/zone/attack.cpp b/zone/attack.cpp index 2ab8efdf6..cfd87d112 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -771,12 +771,12 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { int banedmg = 0; //can't hit invulnerable stuff with weapons. - if(against->GetInvul() || against->SpecAttacks[IMMUNE_MELEE]){ + if(against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE)){ return 0; } //check to see if our weapons or fists are magical. - if(against->SpecAttacks[IMMUNE_MELEE_NONMAGICAL]){ + if(against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)){ if(weapon_item){ if(weapon_item->Magic){ dmg = weapon_item->Damage; @@ -797,7 +797,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { //it gives us an idea if we can hit due to the dual nature of this function dmg = 1; } - else if(SpecAttacks[SPECATK_MAGICAL]) + else if(GetSpecialAbility(SPECATK_MAGICAL)) { dmg = 1; } @@ -822,7 +822,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { } int eledmg = 0; - if(!against->SpecAttacks[IMMUNE_MAGIC]){ + if(!against->GetSpecialAbility(IMMUNE_MAGIC)){ if(weapon_item && weapon_item->ElemDmgAmt){ //we don't check resist for npcs here eledmg = weapon_item->ElemDmgAmt; @@ -830,7 +830,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { } } - if(against->SpecAttacks[IMMUNE_MELEE_EXCEPT_BANE]){ + if(against->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)){ if(weapon_item){ if(weapon_item->BaneDmgBody == against->GetBodyType()){ banedmg += weapon_item->BaneDmgAmt; @@ -842,7 +842,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { } if(!eledmg && !banedmg){ - if(!SpecAttacks[SPECATK_BANE]) + if(!GetSpecialAbility(SPECATK_BANE)) return 0; else return 1; @@ -877,7 +877,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate int dmg = 0; int banedmg = 0; - if(!against || against->GetInvul() || against->SpecAttacks[IMMUNE_MELEE]){ + if(!against || against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE)){ return 0; } @@ -898,7 +898,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate } } - if(against->SpecAttacks[IMMUNE_MELEE_NONMAGICAL]){ + if(against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)){ if(weapon_item){ // check to see if the weapon is magic bool MagicWeapon = false; @@ -937,7 +937,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){ //pets wouldn't actually use this but... dmg = 1; //it gives us an idea if we can hit } - else if(SpecAttacks[SPECATK_MAGICAL]){ + else if(GetSpecialAbility(SPECATK_MAGICAL)){ dmg = 1; } else @@ -976,7 +976,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate } int eledmg = 0; - if(!against->SpecAttacks[IMMUNE_MAGIC]){ + if(!against->GetSpecialAbility(IMMUNE_MAGIC)){ if(weapon_item && weapon_item->GetItem() && weapon_item->GetItem()->ElemDmgAmt){ if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ eledmg = CastToClient()->CalcRecommendedLevelBonus(GetLevel(), weapon_item->GetItem()->RecLevel, weapon_item->GetItem()->ElemDmgAmt); @@ -1001,7 +1001,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate } } - if(against->SpecAttacks[IMMUNE_MELEE_EXCEPT_BANE]){ + if(against->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)){ if(weapon_item && weapon_item->GetItem()){ if(weapon_item->GetItem()->BaneDmgBody == against->GetBodyType()){ if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ @@ -1036,7 +1036,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate if(!eledmg && !banedmg) { - if(!SpecAttacks[SPECATK_BANE]) + if(!GetSpecialAbility(SPECATK_BANE)) return 0; else return 1; @@ -2423,16 +2423,16 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, if(IsClient() && !IsAIControlled()) return; - if(IsFamiliar() || SpecAttacks[IMMUNE_AGGRO]) + if(IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO)) return; if (other == myowner) return; - if(other->SpecAttacks[IMMUNE_AGGRO_ON]) + if(other->GetSpecialAbility(IMMUNE_AGGRO_ON)) return; - if(SpecAttacks[NPC_TUNNELVISION]) { + if(GetSpecialAbility(NPC_TUNNELVISION)) { Mob *top = GetTarget(); if(top && top != other) { hate *= RuleR(Aggro, TunnelVisionAggroMod); @@ -2493,7 +2493,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, } else { // cb:2007-08-17 // owner must get on list, but he's not actually gained any hate yet - if(!owner->SpecAttacks[IMMUNE_AGGRO]) + if(!owner->GetSpecialAbility(IMMUNE_AGGRO)) { hate_list.Add(owner, 0, 0, false, !iBuffTic); if(owner->IsClient()) @@ -2503,10 +2503,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, } if (mypet && (!(GetAA(aaPetDiscipline) && mypet->IsHeld()))) { // I have a pet, add other to it - if(!mypet->IsFamiliar() && !mypet->SpecAttacks[IMMUNE_AGGRO]) + if(!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO)) mypet->hate_list.Add(other, 0, 0, bFrenzy); } else if (myowner) { // I am a pet, add other to owner if it's NPC/LD - if (myowner->IsAIControlled() && !myowner->SpecAttacks[IMMUNE_AGGRO]) + if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO)) myowner->hate_list.Add(other, 0, 0, bFrenzy); } if (!wasengaged) { @@ -3366,7 +3366,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } //end `if there is some damage being done and theres anattacker person involved` Mob *pet = GetPet(); - if (pet && !pet->IsFamiliar() && !pet->SpecAttacks[IMMUNE_AGGRO] && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse()) + if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse()) { if (!pet->IsHeld()) { mlog(PETS__AGGRO, "Sending pet %s into battle due to attack.", pet->GetName()); @@ -4143,7 +4143,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage) entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, CRIPPLING_BLOW, GetCleanName(), itoa(damage)); // Crippling blows also have a chance to stun //Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a staggers message. - if (defender->GetLevel() <= 55 && !defender->SpecAttacks[IMMUNE_STUN]){ + if (defender->GetLevel() <= 55 && !defender->GetSpecialAbility(IMMUNE_STUN)){ defender->Emote("staggers."); defender->Stun(0); } diff --git a/zone/bot.cpp b/zone/bot.cpp index 39c48c09a..86d19af41 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3438,7 +3438,7 @@ bool Bot::CanDoSpecialAttack(Mob *other) return false; } - if(other->GetInvul() || other->SpecAttacks[IMMUNE_MELEE]) + if(other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)) return false; return true; @@ -3776,13 +3776,13 @@ void Bot::AI_Process() { Attack(GetTarget(), SLOT_PRIMARY, true); } - if(BotOwner && GetTarget() && SpecAttacks[SPECATK_TRIPLE] && CheckBotDoubleAttack(true)) { + if(BotOwner && GetTarget() && GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) { tripleSuccess = true; Attack(GetTarget(), SLOT_PRIMARY, true); } //quad attack, does this belong here?? - if(BotOwner && GetTarget() && SpecAttacks[SPECATK_QUAD] && CheckBotDoubleAttack(true)) { + if(BotOwner && GetTarget() && GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) { Attack(GetTarget(), SLOT_PRIMARY, true); } } @@ -8098,7 +8098,7 @@ void Bot::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage) entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, CRIPPLING_BLOW, GetCleanName(), itoa(damage)); // Crippling blows also have a chance to stun //Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a staggers message. - if (defender->GetLevel() <= 55 && !defender->SpecAttacks[IMMUNE_STUN]){ + if (defender->GetLevel() <= 55 && !defender->GetSpecialAbility(IMMUNE_STUN)){ defender->Emote("staggers."); defender->Stun(0); } @@ -10258,7 +10258,7 @@ void Bot::GenerateSpecialAttacks() { // Special Attacks if(((GetClass() == MONK) || (GetClass() == WARRIOR) || (GetClass() == RANGER) || (GetClass() == BERSERKER)) && (GetLevel() >= 60)) { - SpecAttacks[SPECATK_TRIPLE] = true; + SetSpecialAbility(SPECATK_TRIPLE, 1); } } diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index 10d3fa7af..191ed3a41 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -484,7 +484,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { if(botClass == PALADIN) stunChance = 50; - if(!tar->SpecAttacks[UNSTUNABLE] && !tar->IsStunned() && (MakeRandomInt(1, 100) <= stunChance)) { + if(!tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned() && (MakeRandomInt(1, 100) <= stunChance)) { botSpell = GetBestBotSpellForStunByTargetType(this, ST_Target); } } diff --git a/zone/client.cpp b/zone/client.cpp index a66ea3b70..5bd499c1d 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2316,7 +2316,7 @@ bool Client::CheckIncreaseSkill(SkillType skillid, Mob *against_who, int chancem if(against_who) { - if(against_who->SpecAttacks[IMMUNE_AGGRO] || against_who->IsClient() || + if(against_who->GetSpecialAbility(IMMUNE_AGGRO) || against_who->IsClient() || GetLevelCon(against_who->GetLevel()) == CON_GREEN) { //false by default diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 5899460de..0ace11d54 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -419,7 +419,7 @@ bool Client::Process() { //triple attack: rangers, monks, warriors, berserkers over level 60 if((((GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER) - && GetLevel() >= 60) || SpecAttacks[SPECATK_TRIPLE]) + && GetLevel() >= 60) || GetSpecialAbility(SPECATK_TRIPLE)) && CheckDoubleAttack(true)) { tripleAttackSuccess = true; @@ -427,7 +427,7 @@ bool Client::Process() { } //quad attack, does this belong here?? - if(SpecAttacks[SPECATK_QUAD] && CheckDoubleAttack(true)) + if(GetSpecialAbility(SPECATK_QUAD) && CheckDoubleAttack(true)) { Attack(auto_attack_target, 13, false); } diff --git a/zone/command.cpp b/zone/command.cpp index 18496b9d6..12966fbb2 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -3373,7 +3373,7 @@ void command_viewnpctype(Client *c, const Seperator *sep) c->Message(0, " Class: %i", npct->class_); c->Message(0, " MinDmg: %i", npct->min_dmg); c->Message(0, " MaxDmg: %i", npct->max_dmg); - c->Message(0, " Attacks: %s", npct->npc_attacks); + c->Message(0, " Special Abilities: %s", npct->special_abilities.c_str()); c->Message(0, " Spells: %i", npct->npc_spells_id); c->Message(0, " Loot Table: %i", npct->loottable_id); c->Message(0, " NPCFactionID: %i", npct->npc_faction_id); diff --git a/zone/common.h b/zone/common.h index f7716c927..a614a9d12 100644 --- a/zone/common.h +++ b/zone/common.h @@ -128,8 +128,7 @@ enum { LEASH, // J - Dispell, wipe agro && return to spawn TETHER, // j - Return to spawn DESTRUCTIBLE_OBJECT, // o - This is only for destructible objects - NO_HARM_FROM_CLIENT, // Z - This is to prevent attacking NPC's period for clients - SPECATK_MAXNUM + NO_HARM_FROM_CLIENT // Z - This is to prevent attacking NPC's period for clients }; typedef enum { //fear states diff --git a/zone/entity.cpp b/zone/entity.cpp index 0b40b1bee..370a153d9 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2646,57 +2646,6 @@ void EntityList::CountNPC(uint32* NPCCount, uint32* NPCLootCount, uint32* gmspaw } } -void EntityList::DoZoneDump(ZSDump_Spawn2* spawn2_dump, ZSDump_NPC* npc_dump, ZSDump_NPC_Loot* npcloot_dump, NPCType* gmspawntype_dump) { - uint32 spawn2index = 0; - uint32 NPCindex = 0; - uint32 NPCLootindex = 0; - uint32 gmspawntype_index = 0; - - if (npc_dump != 0) { - LinkedListIterator iterator(npc_list); - NPC* npc = 0; - iterator.Reset(); - while(iterator.MoreElements()) - { - npc = iterator.GetData()->CastToNPC(); - if (spawn2_dump != 0) - npc_dump[NPCindex].spawn2_dump_index = zone->DumpSpawn2(spawn2_dump, &spawn2index, npc->respawn2); - npc_dump[NPCindex].npctype_id = npc->GetNPCTypeID(); - npc_dump[NPCindex].cur_hp = npc->GetHP(); - if (npc->IsCorpse()) { - if (npc->CastToCorpse()->IsLocked()) - npc_dump[NPCindex].corpse = 2; - else - npc_dump[NPCindex].corpse = 1; - } - else - npc_dump[NPCindex].corpse = 0; - npc_dump[NPCindex].decay_time_left = 0xFFFFFFFF; - npc_dump[NPCindex].x = npc->GetX(); - npc_dump[NPCindex].y = npc->GetY(); - npc_dump[NPCindex].z = npc->GetZ(); - npc_dump[NPCindex].heading = npc->GetHeading(); - npc_dump[NPCindex].copper = npc->copper; - npc_dump[NPCindex].silver = npc->silver; - npc_dump[NPCindex].gold = npc->gold; - npc_dump[NPCindex].platinum = npc->platinum; - if (npcloot_dump != 0) - npc->DumpLoot(NPCindex, npcloot_dump, &NPCLootindex); - if (gmspawntype_dump != 0) { - if (npc->GetNPCTypeID() == 0) { - memcpy(&gmspawntype_dump[gmspawntype_index], npc->NPCTypedata, sizeof(NPCType)); - npc_dump[NPCindex].gmspawntype_index = gmspawntype_index; - gmspawntype_index++; - } - } - NPCindex++; - iterator.Advance(); - } - } - if (spawn2_dump != 0) - zone->DumpAllSpawn2(spawn2_dump, &spawn2index); -} - void EntityList::Depop(bool StartSpawnTimer) { LinkedListIterator iterator(npc_list); @@ -3212,7 +3161,7 @@ void EntityList::ClearFeignAggro(Mob* targ) { if (iterator.GetData()->CheckAggro(targ)) { - if(iterator.GetData()->SpecAttacks[IMMUNE_FEIGN_DEATH]) + if(iterator.GetData()->GetSpecialAbility(IMMUNE_FEIGN_DEATH)) { iterator.Advance(); continue; diff --git a/zone/entity.h b/zone/entity.h index c642e4ed5..0292543c7 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -316,7 +316,6 @@ public: static char* RemoveNumbers(char* name); void SignalMobsByNPCID(uint32 npc_type, int signal_id); void CountNPC(uint32* NPCCount, uint32* NPCLootCount, uint32* gmspawntype_count); - void DoZoneDump(ZSDump_Spawn2* spawn2dump, ZSDump_NPC* npcdump, ZSDump_NPC_Loot* npclootdump, NPCType* gmspawntype_dump); void RemoveEntity(uint16 id); void SendPetitionToAdmins(Petition* pet); void SendPetitionToAdmins(); diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index f74c1fe98..3c96c3310 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -45,7 +45,7 @@ void Mob::CheckFlee() { return; //dont bother if we are immune to fleeing - if(SpecAttacks[IMMUNE_FLEEING] || spellbonuses.ImmuneToFlee) + if(GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) return; if(!flee_timer.Check()) @@ -105,7 +105,7 @@ void Mob::ProcessFlee() { //Stop fleeing if effect is applied after they start to run. //When ImmuneToFlee effect fades it will turn fear back on and check if it can still flee. - if(flee_mode && (SpecAttacks[IMMUNE_FLEEING] || spellbonuses.ImmuneToFlee) && !spellbonuses.IsFeared){ + if(flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) && !spellbonuses.IsFeared){ curfp = false; return; } diff --git a/zone/horse.cpp b/zone/horse.cpp index e77dd9692..050cc49f7 100644 --- a/zone/horse.cpp +++ b/zone/horse.cpp @@ -86,7 +86,13 @@ const NPCType *Horse::BuildHorseType(uint16 spell_id) { NPCType* npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); strcpy(npc_type->name,"Unclaimed_Mount"); //this should never get used - strcpy(npc_type->npc_attacks,"ABH"); + + npc_type->special_abilities = itoa(IMMUNE_MELEE); + npc_type->special_abilities += std::string(",1^"); + npc_type->special_abilities += itoa(IMMUNE_MAGIC); + npc_type->special_abilities += std::string(",1^"); + npc_type->special_abilities += itoa(IMMUNE_AGGRO); + npc_type->special_abilities += std::string(",1"); npc_type->cur_hp = 1; npc_type->max_hp = 1; npc_type->race = atoi(row[0]); diff --git a/zone/merc.cpp b/zone/merc.cpp index e75efe8fe..aed882a51 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1671,13 +1671,13 @@ void Merc::AI_Process() { Attack(GetTarget(), SLOT_PRIMARY, true); } - if(GetOwner() && GetTarget() && SpecAttacks[SPECATK_TRIPLE]) { + if(GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_TRIPLE)) { tripleSuccess = true; Attack(GetTarget(), SLOT_PRIMARY, true); } //quad attack, does this belong here?? - if(GetOwner() && GetTarget() && SpecAttacks[SPECATK_QUAD]) { + if(GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_QUAD)) { Attack(GetTarget(), SLOT_PRIMARY, true); } } @@ -1851,7 +1851,7 @@ void Merc::AI_Start(int32 iMoveDelay) { if (NPCTypedata_ours) { //AI_AddNPCSpells(ourNPCData->npc_spells_id); - NPCSpecialAttacks(NPCTypedata_ours->npc_attacks,0); + ProcessSpecialAbilities(NPCTypedata_ours->special_abilities); } SendTo(GetX(), GetY(), GetZ()); @@ -2373,7 +2373,7 @@ bool Merc::AICastSpell(int8 iChance, int32 iSpellTypes) { selectedMercSpell = GetBestMercSpellForAENuke(this, tar); - if(selectedMercSpell.spellid == 0 && !tar->SpecAttacks[UNSTUNABLE] && !tar->IsStunned()) { + if(selectedMercSpell.spellid == 0 && !tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned()) { uint8 stunChance = 15; if(MakeRandomInt(1, 100) <= stunChance) { selectedMercSpell = GetBestMercSpellForStun(this); diff --git a/zone/mob.cpp b/zone/mob.cpp index 3acd05619..4892d8ce3 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -299,10 +299,7 @@ Mob::Mob(const char* in_name, shielder[m].shielder_id = 0; shielder[m].shielder_bonus = 0; } - for (i=0; i= 98 || SpecAttacks[SPECATK_SUMMON] == false || !GetTarget() || + if (GetHPRatio() >= 98 || GetSpecialAbility(SPECATK_SUMMON) == 0 || !GetTarget() || (mob_owner && mob_owner->IsClient() && !CheckLosFN(GetTarget()))) return false; // now validate the timer - if (!SpecAttackTimers[SPECATK_SUMMON]) + Timer *timer = GetSpecialAbilityTimer(SPECATK_SUMMON); + if (!timer) { - SpecAttackTimers[SPECATK_SUMMON] = new Timer(6000); - SpecAttackTimers[SPECATK_SUMMON]->Start(); + StartSpecialAbilityTimer(SPECATK_SUMMON, 6000); } // now check the timer - if (!SpecAttackTimers[SPECATK_SUMMON]->Check()) + if (!timer->Check()) return false; // get summon target @@ -2813,7 +2810,7 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime) { void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on) { // Changed proc targets to look up based on the spells goodEffect flag. // This should work for the majority of weapons. - if(spell_id == SPELL_UNKNOWN || on->SpecAttacks[NO_HARM_FROM_CLIENT]) { + if(spell_id == SPELL_UNKNOWN || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) { //This is so 65535 doesn't get passed to the client message and to logs because it is not relavant information for debugging. return; } @@ -4778,3 +4775,117 @@ bool Mob::HasSpellEffect(int effectid) return(0); } +int Mob::GetSpecialAbility(int ability) { + auto iter = SpecialAbilities.find(ability); + if(iter != SpecialAbilities.end()) { + return iter->second.level; + } + + return 0; +} + +void Mob::SetSpecialAbility(int ability, int level) { + auto iter = SpecialAbilities.find(ability); + if(iter != SpecialAbilities.end()) { + SpecialAbility spec = iter->second; + spec.level = level; + SpecialAbilities[ability] = spec; + } else { + SpecialAbility spec; + spec.level = level; + spec.timer = nullptr; + SpecialAbilities[ability] = spec; + } +} + +void Mob::StartSpecialAbilityTimer(int ability, uint32 time) { + auto iter = SpecialAbilities.find(ability); + if(iter != SpecialAbilities.end()) { + SpecialAbility spec = iter->second; + spec.level = level; + if(spec.timer) { + spec.timer->Start(time); + } else { + spec.timer = new Timer(time); + spec.timer->Start(); + } + + SpecialAbilities[ability] = spec; + } else { + SpecialAbility spec; + spec.level = level; + spec.timer = new Timer(time); + spec.timer->Start(); + SpecialAbilities[ability] = spec; + } +} + +void Mob::StopSpecialAbilityTimer(int ability) { + auto iter = SpecialAbilities.find(ability); + if(iter != SpecialAbilities.end()) { + SpecialAbility spec = iter->second; + if(spec.timer) { + delete spec.timer; + spec.timer = nullptr; + } + + SpecialAbilities[ability] = spec; + } +} + +Timer *Mob::GetSpecialAbilityTimer(int ability) { + auto iter = SpecialAbilities.find(ability); + if(iter != SpecialAbilities.end()) { + return iter->second.timer; + } + + return nullptr; +} + +void Mob::ClearSpecialAbilities() { + auto iter = SpecialAbilities.begin(); + while(iter != SpecialAbilities.end()) { + if(iter->second.timer) { + delete iter->second.timer; + } + ++iter; + } + + SpecialAbilities.clear(); +} + +void Mob::ProcessSpecialAbilities(const std::string str) { + ClearSpecialAbilities(); + + std::vector sp = SplitString(str, '^'); + for(auto iter = sp.begin(); iter != sp.end(); ++iter) { + std::vector sub_sp = SplitString((*iter), ','); + if(sub_sp.size() == 2) { + int ability = std::stoi(sub_sp[0]); + int value = std::stoi(sub_sp[1]); + + SetSpecialAbility(ability, value); + switch(ability) { + case SPECATK_SUMMON: + if(value > 0) { + StartSpecialAbilityTimer(SPECATK_SUMMON, 6000); + } + break; + case SPECATK_QUAD: + if(value > 0) { + SetSpecialAbility(SPECATK_TRIPLE, 1); + } + break; + case DESTRUCTIBLE_OBJECT: + if(value == 0) { + SetDestructibleObject(false); + } else { + SetDestructibleObject(true); + } + break; + default: + break; + } + } + } +} \ No newline at end of file diff --git a/zone/mob.h b/zone/mob.h index a69199aea..757e346e1 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -37,6 +37,11 @@ public: CLIENT_KICKED, DISCONNECTED, CLIENT_ERROR, CLIENT_CONNECTINGALL }; enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard }; + struct SpecialAbility { + int level; + Timer *timer; + }; + Mob(const char* in_name, const char* in_lastname, int32 in_cur_hp, @@ -758,12 +763,19 @@ public: void SetNextIncHPEvent( int inchpevent ); bool DivineAura() const; - bool SpecAttacks[SPECATK_MAXNUM]; + bool HasNPCSpecialAtk(const char* parse); + int GetSpecialAbility(int ability); + void SetSpecialAbility(int ability, int level); + void StartSpecialAbilityTimer(int ability, uint32 time); + void StopSpecialAbilityTimer(int ability); + Timer *GetSpecialAbilityTimer(int ability); + void ClearSpecialAbilities(); + void ProcessSpecialAbilities(const std::string str); + Shielders_Struct shielder[MAX_SHIELDERS]; Trade* trade; - - + inline float GetCWPX() const { return(cur_wp_x); } inline float GetCWPY() const { return(cur_wp_y); } inline float GetCWPZ() const { return(cur_wp_z); } @@ -947,10 +959,6 @@ protected: char clean_name[64]; char lastname[64]; - bool bEnraged; - Timer *SpecAttackTimers[SPECATK_MAXNUM]; - bool destructibleobject; - int32 delta_heading; float delta_x; float delta_y; @@ -1145,6 +1153,10 @@ protected: void InsertQuestGlobal(int charid, int npcid, int zoneid, const char *name, const char *value, int expdate); uint16 emoteid; + std::map SpecialAbilities; + bool bEnraged; + bool destructibleobject; + private: void _StopSong(); //this is not what you think it is Mob* target; diff --git a/zone/npc.cpp b/zone/npc.cpp index 6c5ebbd5b..00e5301c4 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -716,23 +716,6 @@ uint32 NPC::CountLoot() { return(itemlist.size()); } -void NPC::DumpLoot(uint32 npcdump_index, ZSDump_NPC_Loot* npclootdump, uint32* NPCLootindex) { - ItemList::iterator cur,end; - cur = itemlist.begin(); - end = itemlist.end(); - for(; cur != end; cur++) { - ServerLootItem_Struct* item = *cur; - npclootdump[*NPCLootindex].npc_dump_index = npcdump_index; - npclootdump[*NPCLootindex].itemid = item->item_id; - npclootdump[*NPCLootindex].charges = item->charges; - npclootdump[*NPCLootindex].equipSlot = item->equipSlot; - npclootdump[*NPCLootindex].minlevel = item->minlevel; - npclootdump[*NPCLootindex].maxlevel = item->maxlevel; - (*NPCLootindex)++; - } - ClearItemList(); -} - void NPC::Depop(bool StartSpawnTimer) { uint16 emoteid = this->GetEmoteID(); if(emoteid != 0) @@ -1431,11 +1414,7 @@ void NPC::PickPocket(Client* thief) { void Mob::NPCSpecialAttacks(const char* parse, int permtag, bool reset, bool remove) { if(reset) { - for(int i = 0; i < SPECATK_MAXNUM; i++) - { - SpecAttacks[i] = false; - safe_delete(SpecAttackTimers[i]); - } + ClearSpecialAbilities(); } const char* orig_parse = parse; @@ -1444,124 +1423,122 @@ void Mob::NPCSpecialAttacks(const char* parse, int permtag, bool reset, bool rem switch(*parse) { case 'E': - SpecAttacks[SPECATK_ENRAGE] = (remove ? false : true); + SetSpecialAbility(SPECATK_ENRAGE, remove ? 0 : 1); break; case 'F': - SpecAttacks[SPECATK_FLURRY] = (remove ? false : true); + SetSpecialAbility(SPECATK_FLURRY, remove ? 0 : 1); break; case 'R': - SpecAttacks[SPECATK_RAMPAGE] = (remove ? false : true); + SetSpecialAbility(SPECATK_RAMPAGE, remove ? 0 : 1); break; case 'r': - SpecAttacks[SPECATK_AREA_RAMPAGE] = (remove ? false : true); + SetSpecialAbility(SPECATK_AREA_RAMPAGE, remove ? 0 : 1); break; case 'S': if(remove) { - SpecAttacks[SPECATK_SUMMON] = false; - safe_delete(SpecAttackTimers[SPECATK_SUMMON]); + SetSpecialAbility(SPECATK_SUMMON, 0); + StopSpecialAbilityTimer(SPECATK_SUMMON); } else { - SpecAttacks[SPECATK_SUMMON] = true; - safe_delete(SpecAttackTimers[SPECATK_SUMMON]); - SpecAttackTimers[SPECATK_SUMMON] = new Timer(6000); - SpecAttackTimers[SPECATK_SUMMON]->Start(); + SetSpecialAbility(SPECATK_SUMMON, 1); + StartSpecialAbilityTimer(SPECATK_SUMMON, 6000); } break; case 'T': - SpecAttacks[SPECATK_TRIPLE] = (remove ? false : true); + SetSpecialAbility(SPECATK_TRIPLE, remove ? 0 : 1); break; case 'Q': //quad requires triple to work properly if(remove) { - SpecAttacks[SPECATK_QUAD] = false; + SetSpecialAbility(SPECATK_QUAD, 0); } else { - SpecAttacks[SPECATK_TRIPLE] = true; - SpecAttacks[SPECATK_QUAD] = true; - } + SetSpecialAbility(SPECATK_TRIPLE, 1); + SetSpecialAbility(SPECATK_QUAD, 1); + } break; case 'b': - SpecAttacks[SPECATK_BANE] = (remove ? false : true); + SetSpecialAbility(SPECATK_BANE, remove ? 0 : 1); break; case 'm': - SpecAttacks[SPECATK_MAGICAL] = (remove ? false : true); + SetSpecialAbility(SPECATK_MAGICAL, remove ? 0 : 1); break; case 'U': - SpecAttacks[UNSLOWABLE] = (remove ? false : true); + SetSpecialAbility(UNSLOWABLE, remove ? 0 : 1); break; case 'M': - SpecAttacks[UNMEZABLE] = (remove ? false : true); + SetSpecialAbility(UNMEZABLE, remove ? 0 : 1); break; case 'C': - SpecAttacks[UNCHARMABLE] = (remove ? false : true); + SetSpecialAbility(UNCHARMABLE, remove ? 0 : 1); break; case 'N': - SpecAttacks[UNSTUNABLE] = (remove ? false : true); + SetSpecialAbility(UNSTUNABLE, remove ? 0 : 1); break; case 'I': - SpecAttacks[UNSNAREABLE] = (remove ? false : true); + SetSpecialAbility(UNSNAREABLE, remove ? 0 : 1); break; case 'D': - SpecAttacks[UNFEARABLE] = (remove ? false : true); + SetSpecialAbility(UNFEARABLE, remove ? 0 : 1); break; case 'K': - SpecAttacks[UNDISPELLABLE] = (remove ? false : true); + SetSpecialAbility(UNDISPELLABLE, remove ? 0 : 1); break; case 'A': - SpecAttacks[IMMUNE_MELEE] = (remove ? false : true); + SetSpecialAbility(IMMUNE_MELEE, remove ? 0 : 1); break; case 'B': - SpecAttacks[IMMUNE_MAGIC] = (remove ? false : true); + SetSpecialAbility(IMMUNE_MAGIC, remove ? 0 : 1); break; case 'f': - SpecAttacks[IMMUNE_FLEEING] = (remove ? false : true); + SetSpecialAbility(IMMUNE_FLEEING, remove ? 0 : 1); break; case 'O': - SpecAttacks[IMMUNE_MELEE_EXCEPT_BANE] = (remove ? false : true); + SetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE, remove ? 0 : 1); break; case 'W': - SpecAttacks[IMMUNE_MELEE_NONMAGICAL] = (remove ? false : true); + SetSpecialAbility(IMMUNE_MELEE_NONMAGICAL, remove ? 0 : 1); break; case 'H': - SpecAttacks[IMMUNE_AGGRO] = (remove ? false : true); + SetSpecialAbility(IMMUNE_AGGRO, remove ? 0 : 1); break; case 'G': - SpecAttacks[IMMUNE_AGGRO_ON] = (remove ? false : true); + SetSpecialAbility(IMMUNE_AGGRO_ON, remove ? 0 : 1); break; case 'g': - SpecAttacks[IMMUNE_CASTING_FROM_RANGE] = (remove ? false : true); + SetSpecialAbility(IMMUNE_CASTING_FROM_RANGE, remove ? 0 : 1); break; case 'd': - SpecAttacks[IMMUNE_FEIGN_DEATH] = (remove ? false : true); + SetSpecialAbility(IMMUNE_FEIGN_DEATH, remove ? 0 : 1); break; case 'Y': - SpecAttacks[SPECATK_RANGED_ATK] = (remove ? false : true); + SetSpecialAbility(SPECATK_RANGED_ATK, remove ? 0 : 1); break; case 'L': - SpecAttacks[SPECATK_INNATE_DW] = (remove ? false : true); + SetSpecialAbility(SPECATK_INNATE_DW, remove ? 0 : 1); break; case 't': - SpecAttacks[NPC_TUNNELVISION] = (remove ? false : true); + SetSpecialAbility(NPC_TUNNELVISION, remove ? 0 : 1); break; case 'n': - SpecAttacks[NPC_NO_BUFFHEAL_FRIENDS] = (remove ? false : true); + SetSpecialAbility(NPC_NO_BUFFHEAL_FRIENDS, remove ? 0 : 1); break; case 'p': - SpecAttacks[IMMUNE_PACIFY] = (remove ? false : true); + SetSpecialAbility(IMMUNE_PACIFY, remove ? 0 : 1); break; case 'J': - SpecAttacks[LEASH] = (remove ? false : true); + SetSpecialAbility(LEASH, remove ? 0 : 1); break; case 'j': - SpecAttacks[TETHER] = (remove ? false : true); + SetSpecialAbility(TETHER, remove ? 0 : 1); break; case 'o': - SpecAttacks[DESTRUCTIBLE_OBJECT] = (remove ? false : true); - SetDestructibleObject(true); + SetSpecialAbility(DESTRUCTIBLE_OBJECT, remove ? 0 : 1); + SetDestructibleObject(remove ? true : false); break; case 'Z': - SpecAttacks[NO_HARM_FROM_CLIENT] = (remove ? false : true); + SetSpecialAbility(NO_HARM_FROM_CLIENT, remove ? 0 : 1); break; case 'i': - SpecAttacks[IMMUNE_TAUNT] = (remove ? false : true); + SetSpecialAbility(IMMUNE_TAUNT, remove ? 0 : 1); break; default: @@ -1588,138 +1565,138 @@ bool Mob::HasNPCSpecialAtk(const char* parse) { switch(*parse) { case 'E': - if (!SpecAttacks[SPECATK_ENRAGE]) + if (!GetSpecialAbility(SPECATK_ENRAGE)) HasAllAttacks = false; break; case 'F': - if (!SpecAttacks[SPECATK_FLURRY]) + if (!GetSpecialAbility(SPECATK_FLURRY)) HasAllAttacks = false; break; case 'R': - if (!SpecAttacks[SPECATK_RAMPAGE]) + if (!GetSpecialAbility(SPECATK_RAMPAGE)) HasAllAttacks = false; break; case 'r': - if (!SpecAttacks[SPECATK_AREA_RAMPAGE]) + if (!GetSpecialAbility(SPECATK_AREA_RAMPAGE)) HasAllAttacks = false; break; case 'S': - if (!SpecAttacks[SPECATK_SUMMON]) + if (!GetSpecialAbility(SPECATK_SUMMON)) HasAllAttacks = false; break; case 'T': - if (!SpecAttacks[SPECATK_TRIPLE]) + if (!GetSpecialAbility(SPECATK_TRIPLE)) HasAllAttacks = false; break; case 'Q': - if (!SpecAttacks[SPECATK_QUAD]) + if (!GetSpecialAbility(SPECATK_QUAD)) HasAllAttacks = false; break; case 'b': - if (!SpecAttacks[SPECATK_BANE]) + if (!GetSpecialAbility(SPECATK_BANE)) HasAllAttacks = false; break; case 'm': - if (!SpecAttacks[SPECATK_MAGICAL]) + if (!GetSpecialAbility(SPECATK_MAGICAL)) HasAllAttacks = false; break; case 'U': - if (!SpecAttacks[UNSLOWABLE]) + if (!GetSpecialAbility(UNSLOWABLE)) HasAllAttacks = false; break; case 'M': - if (!SpecAttacks[UNMEZABLE]) + if (!GetSpecialAbility(UNMEZABLE)) HasAllAttacks = false; break; case 'C': - if (!SpecAttacks[UNCHARMABLE]) + if (!GetSpecialAbility(UNCHARMABLE)) HasAllAttacks = false; break; case 'N': - if (!SpecAttacks[UNSTUNABLE]) + if (!GetSpecialAbility(UNSTUNABLE)) HasAllAttacks = false; break; case 'I': - if (!SpecAttacks[UNSNAREABLE]) + if (!GetSpecialAbility(UNSNAREABLE)) HasAllAttacks = false; break; case 'D': - if (!SpecAttacks[UNFEARABLE]) + if (!GetSpecialAbility(UNFEARABLE)) HasAllAttacks = false; break; case 'A': - if (!SpecAttacks[IMMUNE_MELEE]) + if (!GetSpecialAbility(IMMUNE_MELEE)) HasAllAttacks = false; break; case 'B': - if (!SpecAttacks[IMMUNE_MAGIC]) + if (!GetSpecialAbility(IMMUNE_MAGIC)) HasAllAttacks = false; break; case 'f': - if (!SpecAttacks[IMMUNE_FLEEING]) + if (!GetSpecialAbility(IMMUNE_FLEEING)) HasAllAttacks = false; break; case 'O': - if (!SpecAttacks[IMMUNE_MELEE_EXCEPT_BANE]) + if (!GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)) HasAllAttacks = false; break; case 'W': - if (!SpecAttacks[IMMUNE_MELEE_NONMAGICAL]) + if (!GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)) HasAllAttacks = false; break; case 'H': - if (!SpecAttacks[IMMUNE_AGGRO]) + if (!GetSpecialAbility(IMMUNE_AGGRO)) HasAllAttacks = false; break; case 'G': - if (!SpecAttacks[IMMUNE_AGGRO_ON]) + if (!GetSpecialAbility(IMMUNE_AGGRO_ON)) HasAllAttacks = false; break; case 'g': - if (!SpecAttacks[IMMUNE_CASTING_FROM_RANGE]) + if (!GetSpecialAbility(IMMUNE_CASTING_FROM_RANGE)) HasAllAttacks = false; break; case 'd': - if (!SpecAttacks[IMMUNE_FEIGN_DEATH]) + if (!GetSpecialAbility(IMMUNE_FEIGN_DEATH)) HasAllAttacks = false; break; case 'Y': - if (!SpecAttacks[SPECATK_RANGED_ATK]) + if (!GetSpecialAbility(SPECATK_RANGED_ATK)) HasAllAttacks = false; break; case 'L': - if (!SpecAttacks[SPECATK_INNATE_DW]) + if (!GetSpecialAbility(SPECATK_INNATE_DW)) HasAllAttacks = false; break; case 't': - if (!SpecAttacks[NPC_TUNNELVISION]) + if (!GetSpecialAbility(NPC_TUNNELVISION)) HasAllAttacks = false; break; case 'n': - if (!SpecAttacks[NPC_NO_BUFFHEAL_FRIENDS]) + if (!GetSpecialAbility(NPC_NO_BUFFHEAL_FRIENDS)) HasAllAttacks = false; break; case 'p': - if(!SpecAttacks[IMMUNE_PACIFY]) + if(!GetSpecialAbility(IMMUNE_PACIFY)) HasAllAttacks = false; break; case 'J': - if(!SpecAttacks[LEASH]) + if(!GetSpecialAbility(LEASH)) HasAllAttacks = false; break; case 'j': - if(!SpecAttacks[TETHER]) + if(!GetSpecialAbility(TETHER)) HasAllAttacks = false; break; case 'o': - if(!SpecAttacks[DESTRUCTIBLE_OBJECT]) + if(!GetSpecialAbility(DESTRUCTIBLE_OBJECT)) { HasAllAttacks = false; SetDestructibleObject(false); } break; case 'Z': - if(!SpecAttacks[NO_HARM_FROM_CLIENT]){ + if(!GetSpecialAbility(NO_HARM_FROM_CLIENT)){ HasAllAttacks = false; } break; diff --git a/zone/npc.h b/zone/npc.h index 1a8b871ce..8ccaec74b 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -164,7 +164,6 @@ public: void RemoveCash(); void QueryLoot(Client* to); uint32 CountLoot(); - void DumpLoot(uint32 npcdump_index, ZSDump_NPC_Loot* npclootdump, uint32* NPCLootindex); inline uint32 GetLoottableID() const { return loottable_id; } inline uint32 GetCopper() const { return copper; } diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index c6da2094f..30071ad33 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -459,41 +459,6 @@ uint32 Zone::CountSpawn2() { return count; } -uint32 Zone::DumpSpawn2(ZSDump_Spawn2* spawn2dump, uint32* spawn2index, Spawn2* spawn2) { - if (spawn2 == 0) - return 0; - LinkedListIterator iterator(spawn2_list); - // uint32 index = 0; - - iterator.Reset(); - while(iterator.MoreElements()) - { - if (iterator.GetData() == spawn2) { - spawn2dump[*spawn2index].spawn2_id = iterator.GetData()->spawn2_id; - spawn2dump[*spawn2index].time_left = iterator.GetData()->timer.GetRemainingTime(); - iterator.RemoveCurrent(); - return (*spawn2index)++; - } - iterator.Advance(); - } - return 0xFFFFFFFF; -} - -void Zone::DumpAllSpawn2(ZSDump_Spawn2* spawn2dump, uint32* spawn2index) { - LinkedListIterator iterator(spawn2_list); - // uint32 index = 0; - - iterator.Reset(); - while(iterator.MoreElements()) - { - spawn2dump[*spawn2index].spawn2_id = iterator.GetData()->spawn2_id; - spawn2dump[*spawn2index].time_left = iterator.GetData()->timer.GetRemainingTime(); - (*spawn2index)++; - iterator.RemoveCurrent(); - - } -} - void Zone::Despawn(uint32 spawn2ID) { LinkedListIterator iterator(spawn2_list); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index e2c2d5e7f..7653fcb5a 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -979,7 +979,7 @@ void NPC::RangedAttack(Mob* other) //if we have SPECATK_RANGED_ATK set then we range attack without weapon or ammo const Item_Struct* weapon = nullptr; const Item_Struct* ammo = nullptr; - if(!SpecAttacks[SPECATK_RANGED_ATK]) + if(!GetSpecialAbility(SPECATK_RANGED_ATK)) { //find our bow and ammo return if we can't find them... return; @@ -1940,7 +1940,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { float level_difference = GetLevel() - who->GetLevel(); //Support for how taunt worked pre 2000 on LIVE - Can not taunt NPC over your level. - if ((RuleB(Combat,TauntOverLevel) == false) && (level_difference < 0) || who->SpecAttacks[IMMUNE_TAUNT]){ + if ((RuleB(Combat,TauntOverLevel) == false) && (level_difference < 0) || who->GetSpecialAbility(IMMUNE_TAUNT)){ Message_StringID(MT_SpellFailure,FAILED_TAUNT); return; } @@ -2207,7 +2207,7 @@ bool Mob::CanDoSpecialAttack(Mob *other) return false; } - if(other->GetInvul() || other->SpecAttacks[IMMUNE_MELEE]) + if(other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)) return false; return true; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index fb1255cfe..0d43ee3c5 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -646,7 +646,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (max_level == 0) max_level = RuleI(Spells, BaseImmunityLevel); // NPCs get to ignore max_level for their spells. - if(SpecAttacks[UNSTUNABLE] || + if(GetSpecialAbility(UNSTUNABLE) || ((GetLevel() > max_level) && caster && (!caster->IsNPC() || (caster->IsNPC() && !RuleB(Spells, NPCIgnoreBaseImmunity))))) { @@ -989,7 +989,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Cancel Magic: %d", effect_value); #endif - if(SpecAttacks[UNDISPELLABLE]){ + if(GetSpecialAbility(UNDISPELLABLE)){ caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); break; } @@ -1013,7 +1013,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Dispel Detrimental: %d", effect_value); #endif - if(SpecAttacks[UNDISPELLABLE]){ + if(GetSpecialAbility(UNDISPELLABLE)){ caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); break; } @@ -1037,7 +1037,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Dispel Beneficial: %d", effect_value); #endif - if(SpecAttacks[UNDISPELLABLE]){ + if(GetSpecialAbility(UNDISPELLABLE)){ caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); break; } @@ -1377,7 +1377,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) max_level = RuleI(Spells, BaseImmunityLevel); // Default max is 55 level limit // NPCs ignore level limits in their spells - if(SpecAttacks[UNSTUNABLE] || + if(GetSpecialAbility(UNSTUNABLE) || ((GetLevel() > max_level) && caster && (!caster->IsNPC() || (caster->IsNPC() && !RuleB(Spells, NPCIgnoreBaseImmunity))))) { diff --git a/zone/spells.cpp b/zone/spells.cpp index 489131961..2aa1d1b0a 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -222,7 +222,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, for(int i = 0; i < EFFECT_COUNT; i++) { // not important to check limit on SE_Lull as it doesnt have one and if the other components won't land, then SE_Lull wont either if (spells[spell_id].effectid[i] == SE_ChangeFrenzyRad || spells[spell_id].effectid[i] == SE_Harmony) { - if((spells[spell_id].max[i] != 0 && GetTarget()->GetLevel() > spells[spell_id].max[i]) || GetTarget()->SpecAttacks[IMMUNE_PACIFY]) { + if((spells[spell_id].max[i] != 0 && GetTarget()->GetLevel() > spells[spell_id].max[i]) || GetTarget()->GetSpecialAbility(IMMUNE_PACIFY)) { InterruptSpell(CANNOT_AFFECT_NPC, 0x121, spell_id); return(false); } @@ -3761,7 +3761,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) if(IsMezSpell(spell_id)) { - if(SpecAttacks[UNMEZABLE]) { + if(GetSpecialAbility(UNMEZABLE)) { mlog(SPELLS__RESISTS, "We are immune to Mez spells."); caster->Message_StringID(MT_Shout, CANNOT_MEZ); int32 aggro = CheckAggroAmount(spell_id); @@ -3787,7 +3787,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) } // slow and haste spells - if(SpecAttacks[UNSLOWABLE] && IsEffectInSpell(spell_id, SE_AttackSpeed)) + if(GetSpecialAbility(UNSLOWABLE) && IsEffectInSpell(spell_id, SE_AttackSpeed)) { mlog(SPELLS__RESISTS, "We are immune to Slow spells."); caster->Message_StringID(MT_Shout, IMMUNE_ATKSPEED); @@ -3804,7 +3804,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) if(IsEffectInSpell(spell_id, SE_Fear)) { effect_index = GetSpellEffectIndex(spell_id, SE_Fear); - if(SpecAttacks[UNFEARABLE]) { + if(GetSpecialAbility(UNFEARABLE)) { mlog(SPELLS__RESISTS, "We are immune to Fear spells."); caster->Message_StringID(MT_Shout, IMMUNE_FEAR); int32 aggro = CheckAggroAmount(spell_id); @@ -3838,7 +3838,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) if(IsCharmSpell(spell_id)) { - if(SpecAttacks[UNCHARMABLE]) + if(GetSpecialAbility(UNCHARMABLE)) { mlog(SPELLS__RESISTS, "We are immune to Charm spells."); caster->Message_StringID(MT_Shout, CANNOT_CHARM); @@ -3879,7 +3879,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) IsEffectInSpell(spell_id, SE_MovementSpeed) ) { - if(SpecAttacks[UNSNAREABLE]) { + if(GetSpecialAbility(UNSNAREABLE)) { mlog(SPELLS__RESISTS, "We are immune to Snare spells."); caster->Message_StringID(MT_Shout, IMMUNE_MOVEMENT); int32 aggro = CheckAggroAmount(spell_id); @@ -3939,7 +3939,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use return 0; } - if(SpecAttacks[IMMUNE_CASTING_FROM_RANGE]) + if(GetSpecialAbility(IMMUNE_CASTING_FROM_RANGE)) { if(!caster->CombatRange(this)) { @@ -3947,7 +3947,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use } } - if(SpecAttacks[IMMUNE_MAGIC]) + if(GetSpecialAbility(IMMUNE_MAGIC)) { mlog(SPELLS__RESISTS, "We are immune to magic, so we fully resist the spell %d", spell_id); return(0); diff --git a/zone/trap.cpp b/zone/trap.cpp index f8818d9f9..f631680fb 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -330,7 +330,14 @@ void Trap::CreateHiddenTrigger() make_npc->d_meele_texture2 = 0; make_npc->trackable = 0; make_npc->level = level; - strcpy(make_npc->npc_attacks, "ABHG"); + make_npc->special_abilities = itoa(IMMUNE_MELEE); + make_npc->special_abilities += std::string(",1^"); + make_npc->special_abilities += itoa(IMMUNE_MAGIC); + make_npc->special_abilities += std::string(",1^"); + make_npc->special_abilities += itoa(IMMUNE_AGGRO); + make_npc->special_abilities += std::string(",1^"); + make_npc->special_abilities += itoa(IMMUNE_AGGRO_ON); + make_npc->special_abilities += std::string(",1"); NPC* npca = new NPC(make_npc, 0, x, y, z, 0, FlyMode3); npca->GiveNPCTypeData(make_npc); entity_list.AddNPC(npca); diff --git a/zone/zone.cpp b/zone/zone.cpp index a4d068146..1931bb9d2 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -79,9 +79,6 @@ volatile bool ZoneLoaded = false; extern QuestParserCollection* parse; extern DBAsyncFinishedQueue MTdbafq; extern DBAsync *dbasync; -void CleanupLoadZoneState(uint32 spawn2_count, ZSDump_Spawn2** spawn2_dump, ZSDump_NPC** npc_dump, ZSDump_NPC_Loot** npcloot_dump, NPCType** gmspawntype_dump, Spawn2*** spawn2_loaded, NPC*** npc_loaded, MYSQL_RES** result); - - bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { _ZP(Zone_Bootup); @@ -805,14 +802,7 @@ void Zone::Shutdown(bool quite) if (!quite) LogFile->write(EQEMuLog::Normal, "Zone shutdown: going to sleep"); ZoneLoaded = false; - char pzs[3] = ""; - if (database.GetVariable("PersistentZoneState", pzs, 2)) { - if (pzs[0] == '1') { - Sleep(100); - LogFile->write(EQEMuLog::Normal, "Saving zone state"); - database.DumpZoneState(); - } - } + zone->ResetAuth(); safe_delete(zone); dbasync->CommitWrites(); @@ -1662,301 +1652,9 @@ bool ZoneDatabase::LoadStaticZonePoints(LinkedList* zone_point_list, safe_delete_array(query); return false; } -return true; -} - -bool ZoneDatabase::DumpZoneState() { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - - if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM zone_state_dump WHERE zonename='%s'", zone->GetShortName()), errbuf)) { - std::cerr << "Error in DumpZoneState query '" << query << "' " << errbuf << std::endl; - safe_delete_array(query); - return false; - } - safe_delete_array(query); - - - - uint32 spawn2_count = zone->CountSpawn2(); - uint32 npc_count = 0; - uint32 npcloot_count = 0; - uint32 gmspawntype_count = 0; - entity_list.CountNPC(&npc_count, &npcloot_count, &gmspawntype_count); - - std::cout << "DEBUG: spawn2count=" << spawn2_count << ", npc_count=" << npc_count << ", npcloot_count=" << npcloot_count << ", gmspawntype_count=" << gmspawntype_count << std::endl; - - ZSDump_Spawn2* spawn2_dump = 0; - ZSDump_NPC* npc_dump = 0; - ZSDump_NPC_Loot* npcloot_dump = 0; - NPCType* gmspawntype_dump = 0; - if (spawn2_count > 0) { - spawn2_dump = (ZSDump_Spawn2*) new uchar[spawn2_count * sizeof(ZSDump_Spawn2)]; - memset(spawn2_dump, 0, sizeof(ZSDump_Spawn2) * spawn2_count); - } - if (npc_count > 0) { - npc_dump = (ZSDump_NPC*) new uchar[npc_count * sizeof(ZSDump_NPC)]; - memset(npc_dump, 0, sizeof(ZSDump_NPC) * npc_count); - for (unsigned int i=0; i < npc_count; i++) { - npc_dump[i].spawn2_dump_index = 0xFFFFFFFF; - npc_dump[i].gmspawntype_index = 0xFFFFFFFF; - } - } - if (npcloot_count > 0) { - npcloot_dump = (ZSDump_NPC_Loot*) new uchar[npcloot_count * sizeof(ZSDump_NPC_Loot)]; - memset(npcloot_dump, 0, sizeof(ZSDump_NPC_Loot) * npcloot_count); - for (unsigned int k=0; k < npcloot_count; k++) - npcloot_dump[k].npc_dump_index = 0xFFFFFFFF; - } - if (gmspawntype_count > 0) { - gmspawntype_dump = (NPCType*) new uchar[gmspawntype_count * sizeof(NPCType)]; - memset(gmspawntype_dump, 0, sizeof(NPCType) * gmspawntype_count); - } - - entity_list.DoZoneDump(spawn2_dump, npc_dump, npcloot_dump, gmspawntype_dump); - query = new char[512 + ((sizeof(ZSDump_Spawn2) * spawn2_count + sizeof(ZSDump_NPC) * npc_count + sizeof(ZSDump_NPC_Loot) * npcloot_count + sizeof(NPCType) * gmspawntype_count) * 2)]; - char* end = query; - - end += sprintf(end, "Insert Into zone_state_dump (zonename, spawn2_count, npc_count, npcloot_count, gmspawntype_count, spawn2, npcs, npc_loot, gmspawntype) values ('%s', %i, %i, %i, %i, ", zone->GetShortName(), spawn2_count, npc_count, npcloot_count, gmspawntype_count); - *end++ = '\''; - if (spawn2_dump != 0) { - end += DoEscapeString(end, (char*)spawn2_dump, sizeof(ZSDump_Spawn2) * spawn2_count); - safe_delete_array(spawn2_dump); - } - *end++ = '\''; - end += sprintf(end, ", "); - *end++ = '\''; - if (npc_dump != 0) { - end += DoEscapeString(end, (char*)npc_dump, sizeof(ZSDump_NPC) * npc_count); - safe_delete_array(npc_dump); - } - *end++ = '\''; - end += sprintf(end, ", "); - *end++ = '\''; - if (npcloot_dump != 0) { - end += DoEscapeString(end, (char*)npcloot_dump, sizeof(ZSDump_NPC_Loot) * npcloot_count); - safe_delete_array(npcloot_dump); - } - *end++ = '\''; - end += sprintf(end, ", "); - *end++ = '\''; - if (gmspawntype_dump != 0) { - end += DoEscapeString(end, (char*)gmspawntype_dump, sizeof(NPCType) * gmspawntype_count); - safe_delete_array(gmspawntype_dump); - } - *end++ = '\''; - end += sprintf(end, ")"); - - uint32 affected_rows = 0; - if (!RunQuery(query, (uint32) (end - query), errbuf, 0, &affected_rows)) { - // if (DoEscapeString(query, (unsigned int) (end - query))) { - safe_delete_array(query); - std::cerr << "Error in ZoneDump query " << errbuf << std::endl; - return false; - } - safe_delete_array(query); - - if (affected_rows == 0) { - std::cerr << "Zone dump failed. (affected rows = 0)" << std::endl; - return false; - } return true; } -int8 ZoneDatabase::LoadZoneState(const char* zonename, LinkedList& spawn2_list) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - uint32 i; - unsigned long* lengths; - uint32 elapsedtime = 0; - uint32 spawn2_count = 0; - uint32 npc_count = 0; - uint32 npcloot_count = 0; - uint32 gmspawntype_count = 0; - ZSDump_Spawn2* spawn2_dump = 0; - ZSDump_NPC* npc_dump = 0; - ZSDump_NPC_Loot* npcloot_dump = 0; - NPCType* gmspawntype_dump = 0; - Spawn2** spawn2_loaded = 0; - NPC** npc_loaded = 0; - - if (RunQuery(query, MakeAnyLenString(&query, "SELECT spawn2_count, npc_count, npcloot_count, gmspawntype_count, spawn2, npcs, npc_loot, gmspawntype, (UNIX_TIMESTAMP()-UNIX_TIMESTAMP(time)) as elapsedtime FROM zone_state_dump WHERE zonename='%s'", zonename), errbuf, &result)) { - safe_delete_array(query); - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - std::cout << "Elapsed time: " << row[8] << std::endl; - elapsedtime = atoi(row[8]) * 1000; - lengths = mysql_fetch_lengths(result); - spawn2_count = atoi(row[0]); - std::cout << "Spawn2count: " << spawn2_count << std::endl; - if (lengths[4] != (sizeof(ZSDump_Spawn2) * spawn2_count)) { - std::cerr << "Error in LoadZoneState: spawn2_dump length mismatch l=" << lengths[4] << ", e=" << (sizeof(ZSDump_Spawn2) * spawn2_count) << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - else if (spawn2_count > 0) { - spawn2_dump = new ZSDump_Spawn2[spawn2_count]; - spawn2_loaded = new Spawn2*[spawn2_count]; - memcpy(spawn2_dump, row[4], lengths[4]); - for (i=0; i < spawn2_count; i++) { - if (spawn2_dump[i].time_left == 0xFFFFFFFF) // npc spawned, timer should be disabled - spawn2_loaded[i] = LoadSpawn2(spawn2_list, spawn2_dump[i].spawn2_id, 0xFFFFFFFF); - else if (spawn2_dump[i].time_left <= elapsedtime) - spawn2_loaded[i] = LoadSpawn2(spawn2_list, spawn2_dump[i].spawn2_id, 0); - else - spawn2_loaded[i] = LoadSpawn2(spawn2_list, spawn2_dump[i].spawn2_id, spawn2_dump[i].time_left - elapsedtime); - if (spawn2_loaded[i] == 0) { - std::cerr << "Error in LoadZoneState: spawn2_loaded[" << i << "] == 0" << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - - } - } - } - - gmspawntype_count = atoi(row[3]); - std::cout << "gmspawntype_count: " << gmspawntype_count << std::endl; - if (lengths[7] != (sizeof(NPCType) * gmspawntype_count)) { - std::cerr << "Error in LoadZoneState: gmspawntype_dump length mismatch l=" << lengths[7] << ", e=" << (sizeof(NPCType) * gmspawntype_count) << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - else if (gmspawntype_count > 0) { - gmspawntype_dump = new NPCType[gmspawntype_count]; - memcpy(gmspawntype_dump, row[7], lengths[7]); - } - - npc_count = atoi(row[1]); - std::cout << "npc_count: " << npc_count << std::endl; - if (lengths[5] != (sizeof(ZSDump_NPC) * npc_count)) { - std::cerr << "Error in LoadZoneState: npc_dump length mismatch l=" << lengths[5] << ", e=" << (sizeof(ZSDump_NPC) * npc_count) << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - else if (npc_count > 0) { - npc_dump = new ZSDump_NPC[npc_count]; - npc_loaded = new NPC*[npc_count]; - for (i=0; i < npc_count; i++) { - npc_loaded[i] = 0; - } - memcpy(npc_dump, row[5], lengths[5]); - for (i=0; i < npc_count; i++) { - if (npc_loaded[i] != 0) { - std::cerr << "Error in LoadZoneState: npc_loaded[" << i << "] != 0" << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - Spawn2* tmp = 0; - if (!npc_dump[i].corpse && npc_dump[i].spawn2_dump_index != 0xFFFFFFFF) { - if (spawn2_loaded == 0 || npc_dump[i].spawn2_dump_index >= spawn2_count) { - std::cerr << "Error in LoadZoneState: (spawn2_loaded == 0 || index >= count) && npc_dump[" << i << "].spawn2_dump_index != 0xFFFFFFFF" << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - tmp = spawn2_loaded[npc_dump[i].spawn2_dump_index]; - spawn2_loaded[npc_dump[i].spawn2_dump_index] = 0; - } - if (npc_dump[i].npctype_id == 0) { - if (npc_dump[i].gmspawntype_index == 0xFFFFFFFF) { - std::cerr << "Error in LoadZoneState: gmspawntype index invalid" << std::endl; - safe_delete(tmp); - - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - else { - if (gmspawntype_dump == 0 || npc_dump[i].gmspawntype_index >= gmspawntype_count) { - std::cerr << "Error in LoadZoneState: (gmspawntype_dump == 0 || index >= count) && npc_dump[" << i << "].npctype_id == 0" << std::endl; - safe_delete(tmp); - - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - npc_loaded[i] = new NPC(&gmspawntype_dump[npc_dump[i].gmspawntype_index], tmp, npc_dump[i].x, npc_dump[i].y, npc_dump[i].z, npc_dump[i].heading, FlyMode3, npc_dump[i].corpse); - } - } - else { - const NPCType* crap = database.GetNPCType(npc_dump[i].npctype_id); - if (crap != 0) - npc_loaded[i] = new NPC(crap, tmp, npc_dump[i].x, npc_dump[i].y, npc_dump[i].z, npc_dump[i].heading, FlyMode3, npc_dump[i].corpse); - else { - std::cerr << "Error in LoadZoneState: Unknown npctype_id: " << npc_dump[i].npctype_id << std::endl; - safe_delete(tmp); - } - } - if (npc_loaded[i] != 0) { - npc_loaded[i]->AddCash(npc_dump[i].copper, npc_dump[i].silver, npc_dump[i].gold, npc_dump[i].platinum); - // if (npc_dump[i].corpse) { - // if (npc_dump[i].decay_time_left <= elapsedtime) - // npc_loaded[i]->SetDecayTimer(0); - // else - // npc_loaded[i]->SetDecayTimer(npc_dump[i].decay_time_left - elapsedtime); - // } - entity_list.AddNPC(npc_loaded[i]); - } - } - } - - npcloot_count = atoi(row[2]); - std::cout << "npcloot_count: " << npcloot_count << std::endl; - if (lengths[6] != (sizeof(ZSDump_NPC_Loot) * npcloot_count)) { - std::cerr << "Error in LoadZoneState: npcloot_dump length mismatch l=" << lengths[6] << ", e=" << (sizeof(ZSDump_NPC_Loot) * npcloot_count) << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - else if (npcloot_count > 0) { - if (npc_loaded == 0) { - std::cerr << "Error in LoadZoneState: npcloot_count > 0 && npc_loaded == 0" << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - npcloot_dump = new ZSDump_NPC_Loot[npcloot_count]; - memcpy(npcloot_dump, row[6], lengths[6]); - for (i=0; i < npcloot_count; i++) { - if (npcloot_dump[i].npc_dump_index >= npc_count) { - std::cerr << "Error in LoadZoneState: npcloot_dump[" << i << "].npc_dump_index >= npc_count" << std::endl; - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return -1; - } - if (npc_loaded[npcloot_dump[i].npc_dump_index] != 0) { - npc_loaded[npcloot_dump[i].npc_dump_index]->AddItem(npcloot_dump[i].itemid, npcloot_dump[i].charges, npcloot_dump[i].equipSlot); - } - } - } - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - } - else { - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - return 0; - } - CleanupLoadZoneState(spawn2_count, &spawn2_dump, &npc_dump, &npcloot_dump, &gmspawntype_dump, &spawn2_loaded, &npc_loaded, &result); - } - else { - std::cerr << "Error in LoadZoneState query '" << query << "' " << errbuf << std::endl; - - safe_delete_array(query); - return -1; - } - - return 1; -} - -void CleanupLoadZoneState(uint32 spawn2_count, ZSDump_Spawn2** spawn2_dump, ZSDump_NPC** npc_dump, ZSDump_NPC_Loot** npcloot_dump, NPCType** gmspawntype_dump, Spawn2*** spawn2_loaded, NPC*** npc_loaded, MYSQL_RES** result) { - safe_delete(*spawn2_dump); - safe_delete(*spawn2_loaded); - safe_delete(*gmspawntype_dump); - safe_delete(*npc_dump); - safe_delete(*npc_loaded); - safe_delete(*npcloot_dump); - if (*result) { - mysql_free_result(*result); - *result = 0; - } -} - void Zone::SpawnStatus(Mob* client) { LinkedListIterator iterator(spawn2_list); diff --git a/zone/zone.h b/zone/zone.h index 28c133fe0..f9012b314 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -139,8 +139,6 @@ public: bool RemoveSpawnGroup(uint32 in_id); bool Process(); - void DumpAllSpawn2(ZSDump_Spawn2* spawn2dump, uint32* spawn2index); - uint32 DumpSpawn2(ZSDump_Spawn2* spawn2dump, uint32* spawn2index, Spawn2* spawn2); void Despawn(uint32 spawngroupID); bool Depop(bool StartSpawnTimer = false); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 6b08d98c2..7014f0791 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1035,7 +1035,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { "npc_types.mindmg," "npc_types.maxdmg," "npc_types.attack_count," - "npc_types.npcspecialattks," + "npc_types.special_abilities," "npc_types.npc_spells_id," "npc_types.d_meele_texture1," "npc_types.d_meele_texture2," @@ -1130,7 +1130,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { tmpNPCType->min_dmg = atoi(row[r++]); tmpNPCType->max_dmg = atoi(row[r++]); tmpNPCType->attack_count = atoi(row[r++]); - strcpy(tmpNPCType->npc_attacks,row[r++]); + tmpNPCType->special_abilities = row[r++]; tmpNPCType->npc_spells_id = atoi(row[r++]); tmpNPCType->d_meele_texture1 = atoi(row[r++]); tmpNPCType->d_meele_texture2 = atoi(row[r++]); @@ -1345,7 +1345,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client "vwMercNpcTypes.mindmg," "vwMercNpcTypes.maxdmg," "vwMercNpcTypes.attack_count," - "vwMercNpcTypes.npcspecialattks," + "vwMercNpcTypes.special_abilities," // "vwMercNpcTypes.npc_spells_id," "vwMercNpcTypes.d_meele_texture1," "vwMercNpcTypes.d_meele_texture2," @@ -1440,7 +1440,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client tmpNPCType->min_dmg = atoi(row[r++]); tmpNPCType->max_dmg = atoi(row[r++]); tmpNPCType->attack_count = atoi(row[r++]); - strcpy(tmpNPCType->npc_attacks,row[r++]); + tmpNPCType->special_abilities = row[r++]; //tmpNPCType->npc_spells_id = atoi(row[r++]); tmpNPCType->d_meele_texture1 = atoi(row[r++]); tmpNPCType->d_meele_texture2 = atoi(row[r++]); diff --git a/zone/zonedb.h b/zone/zonedb.h index ab5814ee1..76f528e29 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -297,8 +297,6 @@ public: */ bool GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, int &ruleset, char **map_filename); bool SaveZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct* zd); - bool DumpZoneState(); - int8 LoadZoneState(const char* zonename, LinkedList& spawn2_list); bool LoadStaticZonePoints(LinkedList* zone_point_list,const char* zonename, uint32 version); bool UpdateZoneSafeCoords(const char* zonename, float x, float y, float z); uint8 GetUseCFGSafeCoords(); diff --git a/zone/zonedump.h b/zone/zonedump.h index 815730f88..99ca61d50 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -89,7 +89,7 @@ struct NPCType uint32 min_dmg; uint32 max_dmg; int16 attack_count; - char npc_attacks[30]; + std::string special_abilities; uint16 d_meele_texture1; uint16 d_meele_texture2; uint8 prim_melee_type; @@ -120,38 +120,6 @@ struct NPCType float healscale; }; -struct ZSDump_Spawn2 { - uint32 spawn2_id; - uint32 time_left; -}; - -struct ZSDump_NPC { - uint32 spawn2_dump_index; - uint32 gmspawntype_index; - uint32 npctype_id; - int32 cur_hp; - uint8 corpse; // 0=no, 1=yes, 2=yes and locked - uint32 decay_time_left; -// needatype buffs; // decided not to save these, would be hard because if expired them on bootup, wouldnt take into account the npcai refreshing them, etc - float x; - float y; - float z; - float heading; - uint32 copper; - uint32 silver; - uint32 gold; - uint32 platinum; -}; - -struct ZSDump_NPC_Loot { - uint32 npc_dump_index; - uint16 itemid; - int8 charges; - int16 equipSlot; - uint8 minlevel; - uint8 maxlevel; -}; - /* Below are the blob structures for saving player corpses to the database -Quagmire