mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-15 17:02:26 +00:00
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.
This commit is contained in:
parent
0c675c33e2
commit
63d678ce29
@ -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.
|
||||
|
||||
@ -16,8 +16,6 @@
|
||||
|
||||
#include "StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdarg>
|
||||
#include <cstring> // for strncpy
|
||||
#include <stdexcept>
|
||||
|
||||
@ -328,3 +326,15 @@ const char *ConvertArrayF(float input, char *returnchar)
|
||||
sprintf(returnchar, "%0.2f", input);
|
||||
return returnchar;
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitString(const std::string &str, char delim) {
|
||||
std::vector<std::string> ret;
|
||||
std::stringstream ss(str);
|
||||
std::string item;
|
||||
|
||||
while(std::getline(ss, item, delim)) {
|
||||
ret.push_back(item);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -16,7 +16,8 @@
|
||||
#ifndef _STRINGUTIL_H_
|
||||
#define _STRINGUTIL_H_
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstdarg>
|
||||
#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<std::string> SplitString(const std::string &s, char delim);
|
||||
|
||||
#endif
|
||||
|
||||
17
zone/AA.cpp
17
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;
|
||||
|
||||
@ -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++)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
10
zone/bot.cpp
10
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<NPC*> 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<NPC*> 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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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]);
|
||||
|
||||
@ -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);
|
||||
|
||||
137
zone/mob.cpp
137
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<SPECATK_MAXNUM ; i++) {
|
||||
SpecAttacks[i] = false;
|
||||
SpecAttackTimers[i] = 0;
|
||||
}
|
||||
|
||||
destructibleobject = false;
|
||||
wandertype=0;
|
||||
pausetype=0;
|
||||
@ -402,9 +399,9 @@ Mob::~Mob()
|
||||
else
|
||||
SetPet(0);
|
||||
}
|
||||
for (int i=0; i<SPECATK_MAXNUM ; i++) {
|
||||
safe_delete(SpecAttackTimers[i]);
|
||||
}
|
||||
|
||||
ClearSpecialAbilities();
|
||||
|
||||
EQApplicationPacket app;
|
||||
CreateDespawnPacket(&app, !IsCorpse());
|
||||
Corpse* corpse = entity_list.GetCorpseByID(GetID());
|
||||
@ -2339,19 +2336,19 @@ bool Mob::HateSummon() {
|
||||
if(GetOwnerID())
|
||||
mob_owner = entity_list.GetMob(GetOwnerID());
|
||||
|
||||
if (GetHPRatio() >= 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<std::string> sp = SplitString(str, '^');
|
||||
for(auto iter = sp.begin(); iter != sp.end(); ++iter) {
|
||||
std::vector<std::string> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
zone/mob.h
26
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<int, SpecialAbility> SpecialAbilities;
|
||||
bool bEnraged;
|
||||
bool destructibleobject;
|
||||
|
||||
private:
|
||||
void _StopSong(); //this is not what you think it is
|
||||
Mob* target;
|
||||
|
||||
175
zone/npc.cpp
175
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;
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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<Spawn2*> 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<Spawn2*> 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<Spawn2*> iterator(spawn2_list);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)))))
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
304
zone/zone.cpp
304
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<ZonePoint*>* 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*>& 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<Spawn2*> iterator(spawn2_list);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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++]);
|
||||
|
||||
@ -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*>& spawn2_list);
|
||||
bool LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list,const char* zonename, uint32 version);
|
||||
bool UpdateZoneSafeCoords(const char* zonename, float x, float y, float z);
|
||||
uint8 GetUseCFGSafeCoords();
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user