Albireo Update #2 (persisting spells cross zone between group members, self pet, and more)
- /spawn details now includes the stat / base stats (STR/AGI/STA/INT/WIS) of an entity (NPC/PET/Player) - SetInfoStructUInt and GetInfoStructUInt now support interaction_flag, when not set we will default to 12 which is looking at other players nearby. - Fixed NPCs / Pets having spell bonuses, base stats updated (sta/str/agi/wis/int) - Deprecated GiveImmediateQuestReward - With spell persistence (groups, direct target and self pet) added new rule options for cross zone buffs: RULE_INIT(R_Spells, EnableCrossZoneGroupBuffs, "0"); // enables/disables allowing cross zone group buffs RULE_INIT(R_Spells, EnableCrossZoneTargetBuffs, "0"); // enables/disables allowing cross zone target buffs
This commit is contained in:
parent
92bd67d314
commit
3d3ea08dde
18 changed files with 516 additions and 203 deletions
|
@ -4098,6 +4098,16 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
details3 += "Speed: " + to_string(spawn->GetSpeed()) + "\n";
|
||||
details3 += "BaseSpeed: " + to_string(spawn->GetBaseSpeed()) + "\n";
|
||||
|
||||
if(spawn->IsEntity())
|
||||
{
|
||||
Entity* ent = (Entity*)spawn;
|
||||
details3 += "STR / STRBase: " + to_string(ent->GetInfoStruct()->get_str()) + " / " + to_string(ent->GetInfoStruct()->get_str_base()) + "\n";
|
||||
details3 += "AGI / AGIBase: " + to_string(ent->GetInfoStruct()->get_agi()) + " / " + to_string(ent->GetInfoStruct()->get_agi_base()) + "\n";
|
||||
details3 += "STA / STABase: " + to_string(ent->GetInfoStruct()->get_sta()) + " / " + to_string(ent->GetInfoStruct()->get_sta_base()) + "\n";
|
||||
details3 += "INT / INTBase: " + to_string(ent->GetInfoStruct()->get_intel()) + " / " + to_string(ent->GetInfoStruct()->get_intel_base()) + "\n";
|
||||
details3 += "WIS / WISBase: " + to_string(ent->GetInfoStruct()->get_wis()) + " / " + to_string(ent->GetInfoStruct()->get_wis_base()) + "\n";
|
||||
}
|
||||
|
||||
string details4;
|
||||
if (spawn->IsEntity()) {
|
||||
details4 += "Facial Hair Type: " + to_string(((Entity*)spawn)->GetFacialHairType()) + "\n";
|
||||
|
|
|
@ -109,7 +109,7 @@ Entity::~Entity(){
|
|||
DeleteSpellEffects();
|
||||
}
|
||||
|
||||
void Entity::DeleteSpellEffects()
|
||||
void Entity::DeleteSpellEffects(bool removeClient)
|
||||
{
|
||||
map<LuaSpell*,bool> deletedPtrs;
|
||||
|
||||
|
@ -119,7 +119,7 @@ void Entity::DeleteSpellEffects()
|
|||
{
|
||||
if(deletedPtrs.find(GetInfoStruct()->spell_effects[i].spell) == deletedPtrs.end())
|
||||
{
|
||||
lua_interface->RemoveSpell(GetInfoStruct()->maintained_effects[i].spell, IsPlayer() ? false: true);
|
||||
lua_interface->RemoveSpell(GetInfoStruct()->maintained_effects[i].spell, false, removeClient, "", removeClient);
|
||||
if (IsPlayer())
|
||||
GetInfoStruct()->maintained_effects[i].icon = 0xFFFF;
|
||||
|
||||
|
@ -132,11 +132,6 @@ void Entity::DeleteSpellEffects()
|
|||
}
|
||||
if(GetInfoStruct()->spell_effects[i].spell_id != 0xFFFFFFFF)
|
||||
{
|
||||
if(deletedPtrs.find(GetInfoStruct()->spell_effects[i].spell) == deletedPtrs.end())
|
||||
{
|
||||
lua_interface->RemoveSpell(GetInfoStruct()->spell_effects[i].spell, IsPlayer() ? false: true);
|
||||
deletedPtrs[GetInfoStruct()->spell_effects[i].spell] = true;
|
||||
}
|
||||
GetInfoStruct()->spell_effects[i].spell_id = 0xFFFFFFFF;
|
||||
GetInfoStruct()->spell_effects[i].spell = nullptr;
|
||||
}
|
||||
|
@ -289,6 +284,8 @@ void Entity::MapInfoStruct()
|
|||
|
||||
get_int8_funcs["no_interrupt"] = l::bind(&InfoStruct::get_no_interrupt, &info_struct);
|
||||
|
||||
get_int8_funcs["interaction_flag"] = l::bind(&InfoStruct::get_interaction_flag, &info_struct);
|
||||
|
||||
|
||||
/** SETS **/
|
||||
set_string_funcs["name"] = l::bind(&InfoStruct::set_name, &info_struct, l::_1);
|
||||
|
@ -434,6 +431,8 @@ void Entity::MapInfoStruct()
|
|||
|
||||
set_int8_funcs["no_interrupt"] = l::bind(&InfoStruct::set_no_interrupt, &info_struct, l::_1);
|
||||
|
||||
set_int8_funcs["interaction_flag"] = l::bind(&InfoStruct::set_interaction_flag, &info_struct, l::_1);
|
||||
|
||||
}
|
||||
|
||||
bool Entity::HasMoved(bool include_heading){
|
||||
|
@ -816,7 +815,7 @@ void Entity::AddMaintainedSpell(LuaSpell* luaspell){
|
|||
}
|
||||
}
|
||||
|
||||
void Entity::AddSpellEffect(LuaSpell* luaspell){
|
||||
void Entity::AddSpellEffect(LuaSpell* luaspell, int32 override_expire_time){
|
||||
if (!luaspell || !luaspell->caster)
|
||||
return;
|
||||
|
||||
|
@ -827,7 +826,11 @@ void Entity::AddSpellEffect(LuaSpell* luaspell){
|
|||
GetZone()->RemoveTargetFromSpell(old_effect->spell, this);
|
||||
RemoveSpellEffect(old_effect->spell);
|
||||
}
|
||||
effect = GetFreeSpellEffectSlot();
|
||||
|
||||
LogWrite(SPELL__DEBUG, 0, "Spell", "%s AddSpellEffect %s (%u).", spell->GetName(), GetName(), GetID());
|
||||
|
||||
if(!effect)
|
||||
effect = GetFreeSpellEffectSlot();
|
||||
|
||||
if(effect){
|
||||
MSpellEffects.writelock(__FUNCTION__, __LINE__);
|
||||
|
@ -837,6 +840,8 @@ void Entity::AddSpellEffect(LuaSpell* luaspell){
|
|||
effect->total_time = spell->GetSpellDuration()/10;
|
||||
if (spell->GetSpellData()->duration_until_cancel)
|
||||
effect->expire_timestamp = 0xFFFFFFFF;
|
||||
else if(override_expire_time)
|
||||
effect->expire_timestamp = Timer::GetCurrentTime2() + override_expire_time;
|
||||
else
|
||||
effect->expire_timestamp = Timer::GetCurrentTime2() + (spell->GetSpellDuration()*100);
|
||||
effect->icon = spell->GetSpellData()->icon;
|
||||
|
@ -889,6 +894,8 @@ void Entity::RemoveSpellEffect(LuaSpell* spell) {
|
|||
found = true;
|
||||
}
|
||||
if (found) {
|
||||
LogWrite(SPELL__DEBUG, 0, "Spell", "%s RemoveSpellEffect %s (%u).", spell->spell->GetName(), GetName(), GetID());
|
||||
GetZone()->GetSpellProcess()->RemoveTargetFromSpell(spell, this);
|
||||
memset(&GetInfoStruct()->spell_effects[44], 0, sizeof(SpellEffects));
|
||||
GetInfoStruct()->spell_effects[44].spell_id = 0xFFFFFFFF;
|
||||
changed = true;
|
||||
|
@ -1147,11 +1154,11 @@ void Entity::CalculateBonuses(){
|
|||
stats.clear();
|
||||
ItemStatsValues* values = equipment_list.CalculateEquipmentBonuses(this);
|
||||
CalculateSpellBonuses(values);
|
||||
info->add_sta(values->sta);
|
||||
info->add_str(values->str);
|
||||
info->add_agi(values->agi);
|
||||
info->add_wis(values->wis);
|
||||
info->add_intel(values->int_);
|
||||
info->add_sta((float)values->sta);
|
||||
info->add_str((float)values->str);
|
||||
info->add_agi((float)values->agi);
|
||||
info->add_wis((float)values->wis);
|
||||
info->add_intel((float)values->int_);
|
||||
|
||||
info->add_disease(values->vs_disease);
|
||||
info->add_divine(values->vs_divine);
|
||||
|
@ -1433,6 +1440,8 @@ void Entity::AddSpellBonus(LuaSpell* spell, int16 type, float value, int64 class
|
|||
bonus->tier = spell ? spell->spell->GetSpellTier() : 0;
|
||||
bonus_list.Add(bonus);
|
||||
|
||||
if(IsNPC())
|
||||
CalculateBonuses();
|
||||
}
|
||||
|
||||
BonusValues* Entity::GetSpellBonus(int32 spell_id) {
|
||||
|
@ -1464,6 +1473,9 @@ void Entity::RemoveSpellBonus(const LuaSpell* spell){
|
|||
if(itr.value->luaspell == spell)
|
||||
bonus_list.Remove(itr.value, true);
|
||||
}
|
||||
|
||||
if(IsNPC())
|
||||
CalculateBonuses();
|
||||
}
|
||||
|
||||
void Entity::CalculateSpellBonuses(ItemStatsValues* stats){
|
||||
|
@ -1715,7 +1727,8 @@ void Entity::DismissPet(Entity* pet, bool from_death, bool spawnListLocked) {
|
|||
}
|
||||
|
||||
if (pet->GetPetType() == PET_TYPE_CHARMED) {
|
||||
PetOwner->SetCharmedPet(0);
|
||||
if(PetOwner)
|
||||
PetOwner->SetCharmedPet(0);
|
||||
|
||||
if (!from_death) {
|
||||
// set the pet flag to false, owner to 0, and give the mob its old brain back
|
||||
|
@ -1727,15 +1740,15 @@ void Entity::DismissPet(Entity* pet, bool from_death, bool spawnListLocked) {
|
|||
pet->SetDismissing(false);
|
||||
}
|
||||
}
|
||||
else if (pet->GetPetType() == PET_TYPE_COMBAT)
|
||||
else if (PetOwner && pet->GetPetType() == PET_TYPE_COMBAT)
|
||||
PetOwner->SetCombatPet(0);
|
||||
else if (pet->GetPetType() == PET_TYPE_DEITY)
|
||||
else if (PetOwner && pet->GetPetType() == PET_TYPE_DEITY)
|
||||
PetOwner->SetDeityPet(0);
|
||||
else if (pet->GetPetType() == PET_TYPE_COSMETIC)
|
||||
else if (PetOwner && pet->GetPetType() == PET_TYPE_COSMETIC)
|
||||
PetOwner->SetCosmeticPet(0);
|
||||
|
||||
// if owner is player and no combat pets left reset the pet info
|
||||
if (PetOwner->IsPlayer()) {
|
||||
if (PetOwner && PetOwner->IsPlayer()) {
|
||||
if (!PetOwner->GetPet() && !PetOwner->GetCharmedPet())
|
||||
((Player*)PetOwner)->ResetPetInfo();
|
||||
}
|
||||
|
|
|
@ -256,6 +256,8 @@ struct InfoStruct{
|
|||
flying_type_ = 0;
|
||||
|
||||
no_interrupt_ = 0;
|
||||
|
||||
interaction_flag_ = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -407,6 +409,8 @@ struct InfoStruct{
|
|||
flying_type_ = oldStruct->get_flying_type();
|
||||
|
||||
no_interrupt_ = oldStruct->get_no_interrupt();
|
||||
|
||||
interaction_flag_ = oldStruct->get_interaction_flag();
|
||||
}
|
||||
|
||||
//mutable std::shared_mutex mutex_;
|
||||
|
@ -569,6 +573,8 @@ struct InfoStruct{
|
|||
|
||||
int8 get_no_interrupt() { std::lock_guard<std::mutex> lk(classMutex); return no_interrupt_; }
|
||||
|
||||
int8 get_interaction_flag() { std::lock_guard<std::mutex> lk(classMutex); return interaction_flag_; }
|
||||
|
||||
void set_name(std::string value) { std::lock_guard<std::mutex> lk(classMutex); name_ = value; }
|
||||
|
||||
void set_deity(std::string value) { std::lock_guard<std::mutex> lk(classMutex); deity_ = value; }
|
||||
|
@ -814,6 +820,8 @@ struct InfoStruct{
|
|||
|
||||
void set_no_interrupt(int8 value) { std::lock_guard<std::mutex> lk(classMutex); no_interrupt_ = value; }
|
||||
|
||||
void set_interaction_flag(int8 value) { std::lock_guard<std::mutex> lk(classMutex); interaction_flag_ = value; }
|
||||
|
||||
void ResetEffects(Spawn* spawn)
|
||||
{
|
||||
for(int i=0;i<45;i++){
|
||||
|
@ -981,6 +989,8 @@ private:
|
|||
int8 flying_type_;
|
||||
|
||||
int8 no_interrupt_;
|
||||
|
||||
int8 interaction_flag_;
|
||||
// when PacketStruct is fixed for C++17 this should become a shared_mutex and handle read/write lock
|
||||
std::mutex classMutex;
|
||||
};
|
||||
|
@ -1086,11 +1096,11 @@ public:
|
|||
Entity();
|
||||
virtual ~Entity();
|
||||
|
||||
void DeleteSpellEffects();
|
||||
void DeleteSpellEffects(bool removeClient = false);
|
||||
void MapInfoStruct();
|
||||
virtual float GetDodgeChance();
|
||||
virtual void AddMaintainedSpell(LuaSpell* spell);
|
||||
virtual void AddSpellEffect(LuaSpell* spell);
|
||||
virtual void AddSpellEffect(LuaSpell* spell, int32 override_expire_time = 0);
|
||||
virtual void RemoveMaintainedSpell(LuaSpell* spell);
|
||||
virtual void RemoveSpellEffect(LuaSpell* spell);
|
||||
virtual bool HasActiveMaintainedSpell(Spell* spell, Spawn* target);
|
||||
|
|
|
@ -349,6 +349,7 @@ int EQ2Emu_lua_SetVisualFlag(lua_State* state) {
|
|||
Spawn* spawn = lua_interface->GetSpawn(state);
|
||||
if (spawn) {
|
||||
spawn->vis_changed = true;
|
||||
spawn->GetZone()->AddChangedSpawn(spawn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -361,6 +362,7 @@ int EQ2Emu_lua_SetInfoFlag(lua_State* state) {
|
|||
Spawn* spawn = lua_interface->GetSpawn(state);
|
||||
if (spawn) {
|
||||
spawn->info_changed = true;
|
||||
spawn->GetZone()->AddChangedSpawn(spawn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3719,6 +3721,7 @@ int EQ2Emu_lua_AddQuestStepKill(lua_State* state) {
|
|||
Client* client = quest->GetPlayer()->GetZone()->GetClientBySpawn(quest->GetPlayer());
|
||||
quest->GetPlayer()->GetZone()->SendQuestUpdates(client);
|
||||
}
|
||||
safe_delete(ids);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3753,6 +3756,7 @@ int EQ2Emu_lua_AddQuestStepChat(lua_State* state) {
|
|||
if(client)
|
||||
quest->GetPlayer()->GetZone()->SendQuestUpdates(client);
|
||||
}
|
||||
safe_delete(ids);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3787,6 +3791,7 @@ int EQ2Emu_lua_AddQuestStepObtainItem(lua_State* state) {
|
|||
Client* client = quest->GetPlayer()->GetZone()->GetClientBySpawn(quest->GetPlayer());
|
||||
quest->GetPlayer()->GetZone()->SendQuestUpdates(client);
|
||||
}
|
||||
safe_delete(ids);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3893,6 +3898,7 @@ int EQ2Emu_lua_AddQuestStepSpell(lua_State* state) {
|
|||
Client* client = quest->GetPlayer()->GetZone()->GetClientBySpawn(quest->GetPlayer());
|
||||
quest->GetPlayer()->GetZone()->SendQuestUpdates(client);
|
||||
}
|
||||
safe_delete(ids);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3927,6 +3933,7 @@ int EQ2Emu_lua_AddQuestStepCraft(lua_State* state) {
|
|||
Client* client = quest->GetPlayer()->GetZone()->GetClientBySpawn(quest->GetPlayer());
|
||||
quest->GetPlayer()->GetZone()->SendQuestUpdates(client);
|
||||
}
|
||||
safe_delete(ids);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3961,6 +3968,7 @@ int EQ2Emu_lua_AddQuestStepHarvest(lua_State* state) {
|
|||
Client* client = quest->GetPlayer()->GetZone()->GetClientBySpawn(quest->GetPlayer());
|
||||
quest->GetPlayer()->GetZone()->SendQuestUpdates(client);
|
||||
}
|
||||
safe_delete(ids);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -4066,61 +4074,6 @@ int EQ2Emu_lua_UpdateQuestZone(lua_State* state) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GiveImmediateQuestReward(lua_State* state) {
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
Quest* quest = lua_interface->GetQuest(state);
|
||||
Spawn* playerSpawn = lua_interface->GetSpawn(state, 2);
|
||||
int32 coin = lua_interface->GetInt32Value(state, 3);
|
||||
int32 status_points = lua_interface->GetInt32Value(state, 4);
|
||||
string rewards_str = lua_interface->GetStringValue(state, 5);
|
||||
string select_rewards_str = lua_interface->GetStringValue(state, 6);
|
||||
string factions_map_str = lua_interface->GetStringValue(state, 7);
|
||||
string text = lua_interface->GetStringValue(state, 8);
|
||||
if (playerSpawn && playerSpawn->IsPlayer()) {
|
||||
Player* player = (Player*)playerSpawn;
|
||||
Client* client = player->GetZone()->GetClientBySpawn(player);
|
||||
if (client) {
|
||||
vector<Item*> reward_items;
|
||||
vector<Item*> selectable_reward_items;
|
||||
if (rewards_str.length() > 0) {
|
||||
map<unsigned int, unsigned short> rewards = ParseIntMap(rewards_str);
|
||||
map<unsigned int, unsigned short>::iterator itr;
|
||||
for (itr = rewards.begin(); itr != rewards.end(); itr++) {
|
||||
if (itr->first > 0) {
|
||||
Item* item = new Item(master_item_list.GetItem(itr->first));
|
||||
if (item) {
|
||||
if (itr->second > 0)
|
||||
item->details.count = itr->second;
|
||||
reward_items.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (select_rewards_str.length() > 0) {
|
||||
map<unsigned int, unsigned short> rewards = ParseIntMap(select_rewards_str);
|
||||
map<unsigned int, unsigned short>::iterator itr;
|
||||
for (itr = rewards.begin(); itr != rewards.end(); itr++) {
|
||||
if (itr->first > 0) {
|
||||
Item* item = new Item(master_item_list.GetItem(itr->first));
|
||||
if (item) {
|
||||
if (itr->second > 0)
|
||||
item->stack_count = itr->second;
|
||||
selectable_reward_items.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
map<unsigned int, signed int> faction_rewards = ParseSInt32Map(factions_map_str);
|
||||
const char* reward_type = "Quest Reward!";
|
||||
if (!quest)
|
||||
reward_type = "Reward!";
|
||||
client->DisplayQuestRewards(quest, coin, &reward_items, &selectable_reward_items, &faction_rewards, reward_type, status_points, text.c_str());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EQ2Emu_lua_GiveQuestReward(lua_State* state) {
|
||||
if (!lua_interface)
|
||||
return 0;
|
||||
|
@ -5878,7 +5831,7 @@ int EQ2Emu_lua_AddToWard(lua_State* state) {
|
|||
if (zone->GetSpawnByID(spell->targets.at(0))->IsEntity()) {
|
||||
Entity* target = (Entity*)zone->GetSpawnByID(spell->targets.at(0));
|
||||
ward = target->GetWard(spell->spell->GetSpellID());
|
||||
if (ward) {
|
||||
if (target && ward) {
|
||||
ward->DamageLeft += amount;
|
||||
if (ward->DamageLeft > ward->BaseDamage)
|
||||
ward->DamageLeft = ward->BaseDamage;
|
||||
|
@ -8264,7 +8217,7 @@ int EQ2Emu_lua_SetVision(lua_State* state) {
|
|||
ZoneServer* zone = spell->caster->GetZone();
|
||||
for (int8 i = 0; i < spell->targets.size(); i++) {
|
||||
Spawn* target = zone->GetSpawnByID(spell->targets.at(i));
|
||||
if (target->IsEntity()) {
|
||||
if (target && target->IsEntity()) {
|
||||
((Entity*)target)->GetInfoStruct()->set_vision(vision);
|
||||
if (target->IsPlayer())
|
||||
((Player*)target)->SetCharSheetChanged(true);
|
||||
|
@ -8338,7 +8291,7 @@ int EQ2Emu_lua_BreatheUnderwater(lua_State* state) {
|
|||
ZoneServer* zone = spell->caster->GetZone();
|
||||
for (int8 i = 0; i < spell->targets.size(); i++) {
|
||||
Spawn* target = zone->GetSpawnByID(spell->targets.at(i));
|
||||
if (target->IsEntity()) {
|
||||
if (target && target->IsEntity()) {
|
||||
((Entity*)target)->GetInfoStruct()->set_breathe_underwater(breatheUnderwater);
|
||||
if (target->IsPlayer())
|
||||
((Player*)target)->SetCharSheetChanged(true);
|
||||
|
@ -10959,7 +10912,7 @@ int EQ2Emu_lua_SetAlignment(lua_State* state) {
|
|||
ZoneServer* zone = spell->caster->GetZone();
|
||||
for (int8 i = 0; i < spell->targets.size(); i++) {
|
||||
Spawn* target = zone->GetSpawnByID(spell->targets.at(i));
|
||||
if (target->IsEntity()) {
|
||||
if (target && target->IsEntity()) {
|
||||
((Entity*)target)->GetInfoStruct()->set_alignment((sint8)alignment);
|
||||
if (target->IsPlayer())
|
||||
((Player*)target)->SetCharSheetChanged(true);
|
||||
|
|
|
@ -273,7 +273,6 @@ int EQ2Emu_lua_AddQuestStepCompleteAction(lua_State* state);
|
|||
int EQ2Emu_lua_AddQuestStepProgressAction(lua_State* state);
|
||||
int EQ2Emu_lua_SetQuestCompleteAction(lua_State* state);
|
||||
int EQ2Emu_lua_GiveQuestReward(lua_State* state);
|
||||
int EQ2Emu_lua_GiveImmediateQuestReward(lua_State* state);
|
||||
int EQ2Emu_lua_UpdateQuestTaskGroupDescription(lua_State* state);
|
||||
int EQ2Emu_lua_UpdateQuestStepDescription(lua_State* state);
|
||||
int EQ2Emu_lua_UpdateQuestDescription(lua_State* state);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "WorldDatabase.h"
|
||||
#include "SpellProcess.h"
|
||||
#include "../common/Log.h"
|
||||
#include "World.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <stdio.h>
|
||||
|
@ -34,6 +35,7 @@
|
|||
#endif
|
||||
|
||||
extern WorldDatabase database;
|
||||
extern ZoneList zone_list;
|
||||
|
||||
|
||||
LuaInterface::LuaInterface() {
|
||||
|
@ -277,6 +279,8 @@ bool LuaInterface::LoadLuaSpell(const char* name) {
|
|||
spell->damage_remaining = 0;
|
||||
spell->effect_bitmask = 0;
|
||||
spell->restored = false;
|
||||
spell->initial_caster_char_id = 0;
|
||||
spell->initial_target_char_id = 0;
|
||||
|
||||
MSpells.lock();
|
||||
if (spells.count(lua_script) > 0) {
|
||||
|
@ -751,7 +755,22 @@ void LuaInterface::RemoveSpell(LuaSpell* spell, bool call_remove_function, bool
|
|||
continue;
|
||||
|
||||
((Entity*)target)->RemoveProc(0, spell);
|
||||
((Entity*)target)->RemoveSpellEffect(spell);
|
||||
((Entity*)target)->RemoveSpellBonus(spell);
|
||||
}
|
||||
|
||||
multimap<int32,int8>::iterator entries;
|
||||
for(entries = spell->char_id_targets.begin(); entries != spell->char_id_targets.end(); entries++)
|
||||
{
|
||||
Client* tmpClient = zone_list.GetClientByCharID(entries->first);
|
||||
if(tmpClient && tmpClient->GetPlayer())
|
||||
{
|
||||
tmpClient->GetPlayer()->RemoveProc(0, spell);
|
||||
tmpClient->GetPlayer()->RemoveSpellEffect(spell);
|
||||
tmpClient->GetPlayer()->RemoveSpellBonus(spell);
|
||||
}
|
||||
}
|
||||
spell->char_id_targets.clear(); // TODO: reach out to those clients in different
|
||||
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
// we need to make sure all memory is purged for a copied spell, its only used once
|
||||
|
@ -1037,7 +1056,6 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
|
|||
lua_register(state, "AddQuestStepProgressAction", EQ2Emu_lua_AddQuestStepProgressAction);
|
||||
lua_register(state, "SetQuestCompleteAction", EQ2Emu_lua_SetQuestCompleteAction);
|
||||
lua_register(state, "GiveQuestReward", EQ2Emu_lua_GiveQuestReward);
|
||||
lua_register(state, "GiveImmediateQuestReward", EQ2Emu_lua_GiveImmediateQuestReward);
|
||||
lua_register(state, "UpdateQuestStepDescription", EQ2Emu_lua_UpdateQuestStepDescription);
|
||||
lua_register(state, "UpdateQuestDescription", EQ2Emu_lua_UpdateQuestDescription);
|
||||
lua_register(state, "UpdateQuestZone", EQ2Emu_lua_UpdateQuestZone);
|
||||
|
@ -1783,6 +1801,8 @@ LuaSpell* LuaInterface::GetSpell(const char* name) {
|
|||
new_spell->initial_target = 0;
|
||||
new_spell->spell = 0;
|
||||
new_spell->restored = false;
|
||||
new_spell->initial_caster_char_id = 0;
|
||||
new_spell->initial_target_char_id = 0;
|
||||
return new_spell;
|
||||
}
|
||||
else{
|
||||
|
|
|
@ -72,8 +72,11 @@ struct OptionWindowOption {
|
|||
|
||||
struct LuaSpell{
|
||||
Entity* caster;
|
||||
int32 initial_caster_char_id;
|
||||
int32 initial_target;
|
||||
int32 initial_target_char_id;
|
||||
vector<int32> targets;
|
||||
multimap<int32, int8> char_id_targets;
|
||||
Spell* spell;
|
||||
lua_State* state;
|
||||
string file_name;
|
||||
|
|
|
@ -1065,8 +1065,7 @@ EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyVal
|
|||
packet->setDataByName("mitigation_max2", info_struct->get_max_mitigation());
|
||||
packet->setDataByName("mitigation_base2", info_struct->get_mitigation_base());
|
||||
|
||||
if (version < 1096)
|
||||
packet->setDataByName("weight", info_struct->get_weight());
|
||||
packet->setDataByName("weight", info_struct->get_weight());
|
||||
packet->setDataByName("max_weight", info_struct->get_max_weight());
|
||||
packet->setDataByName("unknownint32a", 777777);
|
||||
packet->setDataByName("unknownint32b", 666666);
|
||||
|
@ -3126,7 +3125,8 @@ void Player::AddMaintainedSpell(LuaSpell* luaspell){
|
|||
effect->target_type = target_type;
|
||||
|
||||
effect->spell = luaspell;
|
||||
luaspell->slot_pos = effect->slot_pos;
|
||||
if(!luaspell->slot_pos)
|
||||
luaspell->slot_pos = effect->slot_pos;
|
||||
effect->spell_id = spell->GetSpellData()->id;
|
||||
LogWrite(PLAYER__DEBUG, 5, "Player", "AddMaintainedSpell Spell ID: %u, req concentration: %u", spell->GetSpellData()->id, spell->GetSpellData()->req_concentration);
|
||||
effect->icon = spell->GetSpellData()->icon;
|
||||
|
@ -3142,7 +3142,7 @@ void Player::AddMaintainedSpell(LuaSpell* luaspell){
|
|||
charsheet_changed = true;
|
||||
}
|
||||
}
|
||||
void Player::AddSpellEffect(LuaSpell* luaspell){
|
||||
void Player::AddSpellEffect(LuaSpell* luaspell, int32 override_expire_time){
|
||||
if(!luaspell || !luaspell->caster)
|
||||
return;
|
||||
|
||||
|
@ -3163,6 +3163,8 @@ void Player::AddSpellEffect(LuaSpell* luaspell){
|
|||
effect->total_time = spell->GetSpellDuration()/10;
|
||||
if (spell->GetSpellData()->duration_until_cancel)
|
||||
effect->expire_timestamp = 0xFFFFFFFF;
|
||||
else if(override_expire_time)
|
||||
effect->expire_timestamp = Timer::GetCurrentTime2() + override_expire_time;
|
||||
else
|
||||
effect->expire_timestamp = Timer::GetCurrentTime2() + (spell->GetSpellDuration()*100);
|
||||
effect->icon = spell->GetSpellData()->icon;
|
||||
|
@ -6374,17 +6376,18 @@ void Player::SaveSpellEffects()
|
|||
for(int i = 0; i < 45; i++) {
|
||||
if(info->spell_effects[i].spell_id != 0xFFFFFFFF)
|
||||
{
|
||||
Spawn* spawn = GetZone()->GetSpawnByID(info->spell_effects[i].spell->initial_target);
|
||||
|
||||
Spawn* spawn = nullptr;
|
||||
int32 target_char_id = 0;
|
||||
if(spawn && spawn->IsPlayer())
|
||||
if(info->spell_effects[i].spell->initial_target_char_id != 0)
|
||||
target_char_id = info->spell_effects[i].spell->initial_target_char_id;
|
||||
else if((spawn = GetZone()->GetSpawnByID(info->spell_effects[i].spell->initial_target)) != nullptr && spawn->IsPlayer())
|
||||
target_char_id = ((Player*)spawn)->GetCharacterID();
|
||||
|
||||
int32 timestamp = 0xFFFFFFFF;
|
||||
if(!info->spell_effects[i].spell->spell->GetSpellData()->duration_until_cancel)
|
||||
timestamp = info->spell_effects[i].expire_timestamp - Timer::GetCurrentTime2();
|
||||
|
||||
int32 caster_char_id = (info->spell_effects[i].caster && info->spell_effects[i].caster->IsPlayer()) ? ((Player*)info->spell_effects[i].caster)->GetCharacterID() : 0;
|
||||
int32 caster_char_id = info->spell_effects[i].spell->initial_caster_char_id;
|
||||
|
||||
if(caster_char_id == 0)
|
||||
continue;
|
||||
|
@ -6398,34 +6401,20 @@ void Player::SaveSpellEffects()
|
|||
info->spell_effects[i].total_time, timestamp, database.getSafeEscapeString(info->spell_effects[i].spell->file_name.c_str()).c_str(), info->spell_effects[i].spell->spell->IsCopiedSpell(), GetCharacterID(),
|
||||
info->spell_effects[i].spell->damage_remaining, info->spell_effects[i].spell->effect_bitmask, info->spell_effects[i].spell->num_triggers, info->spell_effects[i].spell->had_triggers, info->spell_effects[i].spell->cancel_after_all_triggers,
|
||||
info->spell_effects[i].spell->crit, info->spell_effects[i].spell->last_spellattack_hit, info->spell_effects[i].spell->interrupted, info->spell_effects[i].spell->resisted, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->spell_effects[i].spell).c_str()).c_str());
|
||||
|
||||
/* info->spell_effects[i].spell->MSpellTargets.readlock(__FUNCTION__, __LINE__);
|
||||
std::string insertTargets = string("insert into character_spell_effect_targets (caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos) values ");
|
||||
bool firstTarget = true;
|
||||
for (int8 t = 0; t < info->spell_effects[i].spell->targets.size(); t++) {
|
||||
Spawn* spawn = GetZone()->GetSpawnByID(info->spell_effects[i].spell->targets.at(t));
|
||||
if(spawn && spawn->IsPlayer())
|
||||
{
|
||||
if(!firstTarget)
|
||||
insertTargets.append(", ");
|
||||
|
||||
insertTargets.append("(" + caster_char_id + ", " + target_char_id + ", " + "0" + ", " std::to_string(DB_TYPE_SPELLEFFECTS) + ", " + info->spell_effects[i].spell_id + ", " + i + ", " + info->spell_effects[i].spell->slot_pos + ")");
|
||||
firstTarget = false;
|
||||
}
|
||||
}
|
||||
info->spell_effects[i].spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
|
||||
if(!firstTarget)
|
||||
{
|
||||
Query targetSave;
|
||||
targetSave.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, insertTarget.c_str());
|
||||
}*/
|
||||
}
|
||||
if (i < NUM_MAINTAINED_EFFECTS && info->maintained_effects[i].spell_id != 0xFFFFFFFF){
|
||||
Spawn* spawn = GetZone()->GetSpawnByID(info->maintained_effects[i].spell->initial_target);
|
||||
|
||||
int32 target_char_id = 0;
|
||||
if(spawn && spawn->IsPlayer())
|
||||
|
||||
if(info->maintained_effects[i].spell->initial_target_char_id != 0)
|
||||
target_char_id = info->maintained_effects[i].spell->initial_target_char_id;
|
||||
else if(!info->maintained_effects[i].spell->initial_target)
|
||||
target_char_id = GetCharacterID();
|
||||
else if(spawn && spawn->IsPlayer())
|
||||
target_char_id = ((Player*)spawn)->GetCharacterID();
|
||||
else if (spawn && spawn->IsPet() && ((Entity*)spawn)->GetOwner() == (Entity*)this)
|
||||
target_char_id = 0xFFFFFFFF;
|
||||
|
||||
int32 caster_char_id = (info->maintained_effects[i].spell->caster && info->maintained_effects[i].spell->caster->IsPlayer()) ? ((Player*)info->maintained_effects[i].spell->caster)->GetCharacterID() : 0;
|
||||
|
||||
|
@ -6446,11 +6435,19 @@ void Player::SaveSpellEffects()
|
|||
bool firstTarget = true;
|
||||
map<int32, bool> targetsInserted;
|
||||
for (int8 t = 0; t < info->maintained_effects[i].spell->targets.size(); t++) {
|
||||
Spawn* spawn = GetZone()->GetSpawnByID(info->maintained_effects[i].spell->targets.at(t));
|
||||
if(spawn && spawn->IsPlayer())
|
||||
int32 spawn_id = info->maintained_effects[i].spell->targets.at(t);
|
||||
Spawn* spawn = GetZone()->GetSpawnByID(spawn_id);
|
||||
LogWrite(SPELL__DEBUG, 0, "Spell", "%s has target %u to identify for spell %s", GetName(), spawn_id, info->maintained_effects[i].spell->spell->GetName());
|
||||
if(spawn && (spawn->IsPlayer() || spawn->IsPet()))
|
||||
{
|
||||
int32 tmpCharID = ((Player*)spawn)->GetCharacterID();
|
||||
|
||||
int32 tmpCharID = 0;
|
||||
|
||||
if(spawn->IsPlayer())
|
||||
tmpCharID = ((Player*)spawn)->GetCharacterID();
|
||||
else if (spawn->IsPet() && ((Entity*)spawn)->GetOwner() == (Entity*)this)
|
||||
{
|
||||
tmpCharID = 0xFFFFFFFF;
|
||||
}
|
||||
if(targetsInserted.find(tmpCharID) != targetsInserted.end())
|
||||
continue;
|
||||
|
||||
|
@ -6459,12 +6456,27 @@ void Player::SaveSpellEffects()
|
|||
|
||||
targetsInserted.insert(make_pair(tmpCharID, true));
|
||||
|
||||
|
||||
LogWrite(SPELL__DEBUG, 0, "Spell", "%s has target %s (%u) added to spell %s", GetName(), spawn ? spawn->GetName() : "NA", tmpCharID, info->maintained_effects[i].spell->spell->GetName());
|
||||
insertTargets.append("(" + std::to_string(caster_char_id) + ", " + std::to_string(tmpCharID) + ", " + "0" + ", " +
|
||||
std::to_string(DB_TYPE_MAINTAINEDEFFECTS) + ", " + std::to_string(info->maintained_effects[i].spell_id) + ", " + std::to_string(i) +
|
||||
", " + std::to_string(info->maintained_effects[i].spell->slot_pos) + ")");
|
||||
", " + std::to_string(info->maintained_effects[i].slot_pos) + ")");
|
||||
firstTarget = false;
|
||||
}
|
||||
}
|
||||
multimap<int32,int8>::iterator entries;
|
||||
for(entries = info->maintained_effects[i].spell->char_id_targets.begin(); entries != info->maintained_effects[i].spell->char_id_targets.end(); entries++)
|
||||
{
|
||||
if(!firstTarget)
|
||||
insertTargets.append(", ");
|
||||
|
||||
LogWrite(SPELL__DEBUG, 0, "Spell", "%s has target %s (%u) added to spell %s", GetName(), spawn ? spawn->GetName() : "NA", entries->first, info->maintained_effects[i].spell->spell->GetName());
|
||||
insertTargets.append("(" + std::to_string(caster_char_id) + ", " + std::to_string(entries->first) + ", " + "0" + ", " +
|
||||
std::to_string(DB_TYPE_MAINTAINEDEFFECTS) + ", " + std::to_string(info->maintained_effects[i].spell_id) + ", " + std::to_string(i) +
|
||||
", " + std::to_string(info->maintained_effects[i].slot_pos) + ")");
|
||||
|
||||
firstTarget = false;
|
||||
}
|
||||
info->maintained_effects[i].spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
|
||||
if(!firstTarget)
|
||||
{
|
||||
|
|
|
@ -431,7 +431,7 @@ public:
|
|||
tutorial_step = val;
|
||||
}
|
||||
void AddMaintainedSpell(LuaSpell* spell);
|
||||
void AddSpellEffect(LuaSpell* spell);
|
||||
void AddSpellEffect(LuaSpell* spell, int32 override_expire_time = 0);
|
||||
void RemoveMaintainedSpell(LuaSpell* spell);
|
||||
void RemoveSpellEffect(LuaSpell* spell);
|
||||
bool HasActiveMaintainedSpell(Spell* spell, Spawn* target);
|
||||
|
|
|
@ -24,8 +24,11 @@ along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "Spells.h"
|
||||
#include "LuaInterface.h"
|
||||
#include "Bots/Bot.h"
|
||||
#include "SpellProcess.h"
|
||||
#include "Rules/Rules.h"
|
||||
|
||||
extern ZoneList zone_list;
|
||||
extern RuleManager rule_manager;
|
||||
|
||||
/******************************************************** PlayerGroup ********************************************************/
|
||||
|
||||
|
@ -564,6 +567,7 @@ void PlayerGroupManager::UpdateGroupBuffs() {
|
|||
PlayerGroup* group = nullptr;
|
||||
Player* caster = nullptr;
|
||||
vector<int32> new_target_list;
|
||||
vector<int32> char_list;
|
||||
Client* client = nullptr;
|
||||
bool has_effect = false;
|
||||
vector<BonusValues*>* sb_list = nullptr;
|
||||
|
@ -614,6 +618,7 @@ void PlayerGroupManager::UpdateGroupBuffs() {
|
|||
(spell->GetSpellData()->target_type == SPELL_TARGET_GROUP_AE || spell->GetSpellData()->target_type == SPELL_TARGET_RAID_AE)) {
|
||||
|
||||
luaspell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
|
||||
luaspell->char_id_targets.clear();
|
||||
|
||||
for (target_itr = group->GetMembers()->begin(); target_itr != group->GetMembers()->end(); target_itr++) {
|
||||
group_member = (*target_itr)->member;
|
||||
|
@ -632,7 +637,8 @@ void PlayerGroupManager::UpdateGroupBuffs() {
|
|||
has_effect = true;
|
||||
|
||||
// Check if player is within range of the caster
|
||||
if (group_member->GetZone() != caster->GetZone() || caster->GetDistance(group_member) > spell->GetSpellData()->radius) {
|
||||
if (!rule_manager.GetGlobalRule(R_Spells, EnableCrossZoneGroupBuffs)->GetInt8() &&
|
||||
(group_member->GetZone() != caster->GetZone() || caster->GetDistance(group_member) > spell->GetSpellData()->radius)) {
|
||||
if (has_effect) {
|
||||
group_member->RemoveSpellEffect(luaspell);
|
||||
group_member->RemoveSpellBonus(luaspell);
|
||||
|
@ -659,13 +665,20 @@ void PlayerGroupManager::UpdateGroupBuffs() {
|
|||
continue;
|
||||
}
|
||||
|
||||
//this group member is a target of the spell
|
||||
new_target_list.push_back(group_member->GetID());
|
||||
if(group_member->GetZone() != caster->GetZone())
|
||||
{
|
||||
if(group_member->IsPlayer())
|
||||
luaspell->char_id_targets.insert(make_pair(((Player*)group_member)->GetCharacterID(), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
//this group member is a target of the spell
|
||||
new_target_list.push_back(group_member->GetID());
|
||||
}
|
||||
|
||||
if (has_effect)
|
||||
continue;
|
||||
|
||||
|
||||
pet = 0;
|
||||
charmed_pet = 0;
|
||||
|
||||
|
@ -674,11 +687,11 @@ void PlayerGroupManager::UpdateGroupBuffs() {
|
|||
charmed_pet = group_member->GetCharmedPet();
|
||||
}
|
||||
|
||||
group_member->AddSpellEffect(luaspell);
|
||||
group_member->AddSpellEffect(luaspell, luaspell->timer.GetRemainingTime() != 0 ? luaspell->timer.GetRemainingTime() : 0);
|
||||
if (pet)
|
||||
pet->AddSpellEffect(luaspell);
|
||||
pet->AddSpellEffect(luaspell, luaspell->timer.GetRemainingTime() != 0 ? luaspell->timer.GetRemainingTime() : 0);
|
||||
if (charmed_pet)
|
||||
charmed_pet->AddSpellEffect(luaspell);
|
||||
charmed_pet->AddSpellEffect(luaspell, luaspell->timer.GetRemainingTime() != 0 ? luaspell->timer.GetRemainingTime() : 0);
|
||||
|
||||
if (pet)
|
||||
new_target_list.push_back(pet->GetID());
|
||||
|
@ -714,8 +727,8 @@ void PlayerGroupManager::UpdateGroupBuffs() {
|
|||
}
|
||||
}
|
||||
|
||||
new_target_list.push_back(caster->GetID());
|
||||
luaspell->targets.swap(new_target_list);
|
||||
SpellProcess::AddSelfAndPet(luaspell, caster);
|
||||
luaspell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
|
||||
new_target_list.clear();
|
||||
}
|
||||
|
|
|
@ -328,6 +328,8 @@ void RuleManager::Init()
|
|||
RULE_INIT(R_Spells, DefaultFizzleChance, "10.0"); // default percentage x / 100, eg 10% is 10.0
|
||||
RULE_INIT(R_Spells, FizzleMaxSkill, "1.2"); // 1.0 is 100%, 1.2 is 120%, so you get 120% your max skill against a spell, no fizzle
|
||||
RULE_INIT(R_Spells, FizzleDefaultSkill, ".2"); // offset against MaxSkill to average out to 100%, default of .2f so we don't go over the threshold if no skill
|
||||
RULE_INIT(R_Spells, EnableCrossZoneGroupBuffs, "0"); // enables/disables allowing cross zone group buffs
|
||||
RULE_INIT(R_Spells, EnableCrossZoneTargetBuffs, "0"); // enables/disables allowing cross zone target buffs
|
||||
|
||||
RULE_INIT(R_Expansion, GlobalExpansionFlag, "0");
|
||||
RULE_INIT(R_Expansion, GlobalHolidayFlag, "0");
|
||||
|
|
|
@ -177,6 +177,8 @@ enum RuleType {
|
|||
DefaultFizzleChance,
|
||||
FizzleMaxSkill,
|
||||
FizzleDefaultSkill,
|
||||
EnableCrossZoneGroupBuffs,
|
||||
EnableCrossZoneTargetBuffs,
|
||||
|
||||
/* ZONE TIMERS */
|
||||
RegenTimer,
|
||||
|
|
|
@ -2291,8 +2291,13 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
|
|||
packet->setDataByName("difficulty", appearance.encounter_level); //6);
|
||||
packet->setDataByName("unknown6", 1);
|
||||
packet->setDataByName("heroic_flag", appearance.heroic_flag);
|
||||
if (!IsObject() && !IsGroundSpawn() && !IsWidget() && !IsSign())
|
||||
packet->setDataByName("interaction_flag", 12); //this makes NPCs head turn to look at you
|
||||
if (IsNPC() && !IsPet())
|
||||
{
|
||||
if(((Entity*)this)->GetInfoStruct()->get_interaction_flag())
|
||||
packet->setDataByName("interaction_flag", ((Entity*)this)->GetInfoStruct()->get_interaction_flag()); //this makes NPCs head turn to look at you (12)
|
||||
else
|
||||
packet->setDataByName("interaction_flag", 12); //turn head since no other value is set
|
||||
}
|
||||
|
||||
packet->setDataByName("class", appearance.adventure_class);
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ bool SpellProcess::DeleteCasterSpell(LuaSpell* spell, string reason, bool removi
|
|||
|
||||
spell->caster->RemoveProc(0, spell);
|
||||
spell->caster->RemoveMaintainedSpell(spell);
|
||||
CheckRemoveTargetFromSpell(spell, false);
|
||||
CheckRemoveTargetFromSpell(spell, removing_all_spells, removing_all_spells);
|
||||
ZoneServer* zone = spell->caster->GetZone();
|
||||
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__);
|
||||
for (int32 i = 0; i < spell->targets.size(); i++) {
|
||||
|
@ -514,8 +514,10 @@ bool SpellProcess::CastInstant(Spell* spell, Entity* caster, Entity* target, boo
|
|||
}
|
||||
|
||||
lua_spell->caster = caster;
|
||||
lua_spell->initial_caster_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0;
|
||||
lua_spell->spell = spell;
|
||||
lua_spell->initial_target = target->GetID();
|
||||
lua_spell->initial_target_char_id = (target && target->IsPlayer()) ? ((Player*)target)->GetCharacterID() : 0;
|
||||
GetSpellTargets(lua_spell);
|
||||
|
||||
if (!lua_spell->spell->IsCopiedSpell())
|
||||
|
@ -903,10 +905,12 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster,
|
|||
int8 target_type = spell->GetSpellData()->target_type;
|
||||
|
||||
lua_spell->caster = caster;
|
||||
lua_spell->initial_caster_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0;
|
||||
lua_spell->spell = spell;
|
||||
|
||||
int32 target_id = target->GetID();
|
||||
lua_spell->initial_target = target_id;
|
||||
lua_spell->initial_target_char_id = (target && target->IsPlayer()) ? ((Player*)target)->GetCharacterID() : 0;
|
||||
|
||||
if (!harvest_spell)
|
||||
GetSpellTargets(lua_spell);
|
||||
|
@ -1036,17 +1040,20 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster,
|
|||
if(client)
|
||||
UnlockSpell(client, conflictSpell->spell);
|
||||
}
|
||||
DeleteSpell(lua_spell);
|
||||
return;
|
||||
}
|
||||
else if(lua_spell->spell->GetSpellData()->spell_type == SPELL_TYPE_DEBUFF)
|
||||
{
|
||||
SpellCannotStack(zone, client, lua_spell->caster, lua_spell, conflictSpell);
|
||||
DeleteSpell(lua_spell);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellCannotStack(zone, client, lua_spell->caster, lua_spell, conflictSpell);
|
||||
DeleteSpell(lua_spell);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1943,6 +1950,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
secondary_target = target;
|
||||
implied = true;
|
||||
luaspell->initial_target = target->GetID();
|
||||
luaspell->initial_target_char_id = (target && target->IsPlayer()) ? ((Player*)target)->GetCharacterID() : 0;
|
||||
luaspell->targets.push_back(target->GetID());
|
||||
GetPlayerGroupTargets((Player*)target, caster, luaspell);
|
||||
|
||||
|
@ -1951,6 +1959,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
{
|
||||
implied = true;
|
||||
luaspell->initial_target = secondary_target->GetID();
|
||||
luaspell->initial_target_char_id = (secondary_target && secondary_target->IsPlayer()) ? ((Player*)secondary_target)->GetCharacterID() : 0;
|
||||
luaspell->targets.push_back(secondary_target->GetID());
|
||||
GetPlayerGroupTargets((Player*)secondary_target, caster, luaspell);
|
||||
}
|
||||
|
@ -1964,6 +1973,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
if (!target->IsPet() || (target->IsPet() && ((NPC*)target)->GetOwner()->IsNPC())) {
|
||||
target = caster;
|
||||
luaspell->initial_target = caster->GetID();
|
||||
luaspell->initial_target_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1971,6 +1981,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
{
|
||||
if (target->IsPlayer() && ((Entity*)caster)->AttackAllowed((Entity*)target)) {
|
||||
luaspell->initial_target = target->GetID();
|
||||
luaspell->initial_target_char_id = (target && target->IsPlayer()) ? ((Player*)target)->GetCharacterID() : 0;
|
||||
luaspell->targets.push_back(target->GetID());
|
||||
}
|
||||
}
|
||||
|
@ -1999,14 +2010,17 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
{
|
||||
// add self
|
||||
target = NULL;
|
||||
luaspell->targets.push_back(caster->GetID());
|
||||
luaspell->initial_target = 0;
|
||||
AddSelfAndPet(luaspell, caster);
|
||||
|
||||
luaspell->initial_target = caster->GetID();
|
||||
luaspell->initial_target_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0;
|
||||
}
|
||||
}
|
||||
else // default self cast for group/raid AE
|
||||
{
|
||||
target = caster;
|
||||
luaspell->initial_target = caster->GetID();
|
||||
luaspell->initial_target_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0;
|
||||
}
|
||||
// spell target versus self cast
|
||||
}
|
||||
|
@ -2014,11 +2028,13 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
{
|
||||
target = caster;
|
||||
luaspell->initial_target = caster->GetID();
|
||||
luaspell->initial_target_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0;
|
||||
}
|
||||
}
|
||||
else if (target_type == SPELL_TARGET_SELF){
|
||||
target = caster;
|
||||
luaspell->initial_target = caster->GetID();
|
||||
luaspell->initial_target_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0;
|
||||
}
|
||||
|
||||
//if using implied target, target = the implied target
|
||||
|
@ -2026,6 +2042,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
{
|
||||
target = secondary_target;
|
||||
luaspell->initial_target = secondary_target->GetID();
|
||||
luaspell->initial_target_char_id = (secondary_target && secondary_target->IsPlayer()) ? ((Player*)secondary_target)->GetCharacterID() : 0;
|
||||
}
|
||||
|
||||
luaspell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
|
||||
|
@ -2062,15 +2079,27 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
// get group member player info
|
||||
Entity* group_member = (*itr)->member;
|
||||
|
||||
LogWrite(SPELL__DEBUG, 0, "Player", "%s is group member for spell %s", group_member->GetName(), luaspell->spell->GetName());
|
||||
// if the group member is in the casters zone, and is alive
|
||||
if (group_member->GetZone() == luaspell->caster->GetZone() && group_member->Alive()) {
|
||||
luaspell->targets.push_back(group_member->GetID());
|
||||
if (group_member->HasPet()) {
|
||||
Entity* pet = group_member->GetPet();
|
||||
if (!pet)
|
||||
pet = group_member->GetCharmedPet();
|
||||
if (pet)
|
||||
luaspell->targets.push_back(pet->GetID());
|
||||
|
||||
if( group_member->Alive())
|
||||
{
|
||||
if(group_member->GetZone() != caster->GetZone())
|
||||
{
|
||||
if(group_member->IsPlayer())
|
||||
luaspell->char_id_targets.insert(make_pair(((Player*)group_member)->GetCharacterID(), 0));
|
||||
}
|
||||
else if (group_member->GetZone() == luaspell->caster->GetZone()) {
|
||||
luaspell->targets.push_back(group_member->GetID());
|
||||
if (group_member->HasPet()) {
|
||||
Entity* pet = group_member->GetPet();
|
||||
if (!pet)
|
||||
pet = group_member->GetCharmedPet();
|
||||
if (pet)
|
||||
luaspell->targets.push_back(pet->GetID());
|
||||
|
||||
LogWrite(SPELL__DEBUG, 0, "Player", "%s added a pet %s (%u) for spell %s", group_member->GetName(), pet ? pet->GetName() : "", pet ? pet->GetID() : 0, luaspell->spell->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2080,7 +2109,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
else
|
||||
luaspell->targets.push_back(caster->GetID()); // else caster is not in a group, thus alone
|
||||
AddSelfAndPet(luaspell, caster); // else caster is not in a group, thus alone
|
||||
}
|
||||
else if (caster->IsNPC()) // caster is NOT a player
|
||||
{
|
||||
|
@ -2108,7 +2137,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
}
|
||||
}
|
||||
else
|
||||
luaspell->targets.push_back(caster->GetID());
|
||||
AddSelfAndPet(luaspell, caster);
|
||||
|
||||
safe_delete(group);
|
||||
} // end is player
|
||||
|
@ -2119,10 +2148,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
luaspell->targets.push_back(caster->GetID()); // if spell is SELF, return caster
|
||||
|
||||
else if (target_type == SPELL_TARGET_CASTER_PET && caster && caster->IsEntity() && ((Entity*)caster)->HasPet()) {
|
||||
if (((Entity*)caster)->GetPet())
|
||||
luaspell->targets.push_back(((Entity*)caster)->GetPet()->GetID());
|
||||
if (((Entity*)caster)->GetCharmedPet())
|
||||
luaspell->targets.push_back(((Entity*)caster)->GetCharmedPet()->GetID());
|
||||
AddSelfAndPet(luaspell, caster, true);
|
||||
}
|
||||
|
||||
else if (target_type == SPELL_TARGET_ENEMY && target && target->Alive()) // if target is enemy, and is alive
|
||||
|
@ -2158,13 +2184,13 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
luaspell->targets.push_back(target->GetID()); // return the target
|
||||
}
|
||||
else
|
||||
luaspell->targets.push_back(caster->GetID()); // else return the caster
|
||||
AddSelfAndPet(luaspell, caster);
|
||||
}
|
||||
// if NPC caster is in a group, and target is a player and targeted player is a group member
|
||||
else if (((NPC*)caster)->HasSpawnGroup() && target->IsNPC() && ((NPC*)caster)->IsInSpawnGroup((NPC*)target))
|
||||
luaspell->targets.push_back(target->GetID()); // return the target
|
||||
else
|
||||
luaspell->targets.push_back(caster->GetID()); // else return the caster
|
||||
AddSelfAndPet(luaspell, caster);
|
||||
}
|
||||
else if (target->IsNPC())
|
||||
luaspell->targets.push_back(target->GetID()); // return target for single spell
|
||||
|
@ -2193,8 +2219,9 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
|
|||
{
|
||||
Spawn* group_member = *itr;
|
||||
|
||||
// if NPC group member is (still) an NPC (wtf?) and is alive, send the NPC group member back as a successful target of non-friendly spell
|
||||
if (group_member->IsNPC() && group_member->Alive() && !((Entity*)group_member)->IsAOEImmune() && (!((Entity*)group_member)->IsMezzed() || group_member == target))
|
||||
// if NPC group member is (still) an NPC (wtf?) and is alive, send the NPC group member back as a successful target of non-friendly spell group_member->Alive()
|
||||
if (group_member->GetZone() == caster->GetZone() &&
|
||||
group_member->IsNPC() && group_member->Alive() && !((Entity*)group_member)->IsAOEImmune() && (!((Entity*)group_member)->IsMezzed() || group_member == target))
|
||||
luaspell->targets.push_back(group_member->GetID());
|
||||
|
||||
// note: this should generate some hate towards the caster
|
||||
|
@ -2314,7 +2341,7 @@ void SpellProcess::GetPlayerGroupTargets(Player* target, Spawn* caster, LuaSpell
|
|||
info->client->GetPlayer()->GetZone() == ((Player*)target)->GetZone() && info->client->GetPlayer()->Alive()
|
||||
&& (bypassRangeChecks || caster->GetDistance((Entity*)info->client->GetPlayer()) <= luaspell->spell->GetSpellData()->range))
|
||||
{
|
||||
luaspell->targets.push_back(info->client->GetPlayer()->GetID());
|
||||
AddSelfAndPet(luaspell, info->client->GetPlayer());
|
||||
}
|
||||
}
|
||||
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
@ -2328,7 +2355,10 @@ void SpellProcess::GetSpellTargetsTrueAOE(LuaSpell* luaspell) {
|
|||
if (luaspell->caster->HasTarget() && luaspell->caster->GetTarget() != luaspell->caster){
|
||||
//Check if the caster has an implied target
|
||||
if (luaspell->caster->GetDistance(luaspell->caster->GetTarget()) <= luaspell->spell->GetSpellData()->radius)
|
||||
{
|
||||
luaspell->initial_target = luaspell->caster->GetTarget()->GetID();
|
||||
luaspell->initial_target_char_id = (luaspell->caster->GetTarget() && luaspell->caster->GetTarget()->IsPlayer()) ? ((Player*)luaspell->caster->GetTarget())->GetCharacterID() : 0;
|
||||
}
|
||||
}
|
||||
int32 ignore_target = 0;
|
||||
vector<Spawn*> spawns = luaspell->caster->GetZone()->GetAttackableSpawnsByDistance(luaspell->caster, luaspell->spell->GetSpellData()->radius);
|
||||
|
@ -2497,6 +2527,7 @@ void SpellProcess::RemoveTargetFromSpell(LuaSpell* spell, Spawn* target){
|
|||
if (!spell || !target)
|
||||
return;
|
||||
|
||||
LogWrite(SPELL__DEBUG, 0, "Spell", "%s RemoveTargetFromSpell %s (%u).", spell->spell->GetName(), target->GetName(), target->GetID());
|
||||
MRemoveTargetList.writelock(__FUNCTION__, __LINE__);
|
||||
|
||||
if (!remove_target_list[spell])
|
||||
|
@ -2506,7 +2537,7 @@ void SpellProcess::RemoveTargetFromSpell(LuaSpell* spell, Spawn* target){
|
|||
MRemoveTargetList.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete){
|
||||
void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete, bool removing_all_spells){
|
||||
if (!spell)
|
||||
return;
|
||||
|
||||
|
@ -2529,19 +2560,34 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete
|
|||
remove_spawn = spell->caster->GetZone()->GetSpawnByID((*remove_target_itr));
|
||||
if (remove_spawn) {
|
||||
spell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
|
||||
for (target_itr = targets->begin(); target_itr != targets->end(); target_itr++) {
|
||||
((Entity*)remove_spawn)->RemoveProc(0, spell);
|
||||
((Entity*)remove_spawn)->RemoveMaintainedSpell(spell);
|
||||
|
||||
if(remove_spawn && remove_spawn->IsPlayer())
|
||||
{
|
||||
multimap<int32,int8>::iterator entries;
|
||||
while((entries = spell->char_id_targets.find(((Player*)remove_spawn)->GetCharacterID())) != spell->char_id_targets.end())
|
||||
{
|
||||
spell->char_id_targets.erase(entries);
|
||||
}
|
||||
}
|
||||
for (target_itr = targets->begin(); target_itr != targets->end(); target_itr++) {
|
||||
if (remove_spawn->GetID() == (*target_itr)) {
|
||||
((Entity*)remove_spawn)->RemoveProc(0, spell);
|
||||
((Entity*)remove_spawn)->RemoveMaintainedSpell(spell);
|
||||
LogWrite(SPELL__DEBUG, 0, "Spell", "%s CheckRemoveTargetFromSpell %s (%u).", spell->spell->GetName(), remove_spawn->GetName(), remove_spawn->GetID());
|
||||
targets->erase(target_itr);
|
||||
if (remove_spawn->IsEntity())
|
||||
{
|
||||
if(!removing_all_spells && remove_spawn->IsPlayer())
|
||||
{
|
||||
spell->char_id_targets.insert(make_pair(((Player*)remove_spawn)->GetCharacterID(),0));
|
||||
}
|
||||
((Entity*)remove_spawn)->RemoveEffectsFromLuaSpell(spell);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
|
||||
if (targets->size() == 0 && allow_delete) {
|
||||
if (targets->size() == 0 && spell->char_id_targets.size() == 0 && allow_delete) {
|
||||
should_delete = true;
|
||||
break;
|
||||
}
|
||||
|
@ -2688,4 +2734,17 @@ void SpellProcess::AddActiveSpell(LuaSpell* spell)
|
|||
{
|
||||
if(!active_spells.count(spell))
|
||||
active_spells.Add(spell);
|
||||
}
|
||||
|
||||
void SpellProcess::AddSelfAndPet(LuaSpell* spell, Spawn* caster, bool onlyPet)
|
||||
{
|
||||
if(!onlyPet)
|
||||
spell->targets.push_back(caster->GetID());
|
||||
|
||||
if(caster->IsEntity() && ((Entity*)caster)->HasPet() && ((Entity*)caster)->GetPet())
|
||||
spell->targets.push_back(((Entity*)caster)->GetPet()->GetID());
|
||||
if(caster->IsEntity() && ((Entity*)caster)->HasPet() && ((Entity*)caster)->GetCharmedPet())
|
||||
spell->targets.push_back(((Entity*)caster)->GetCharmedPet()->GetID());
|
||||
if(!onlyPet && caster->IsEntity() && ((Entity*)caster)->IsPet() && ((Entity*)caster)->GetOwner())
|
||||
spell->targets.push_back(((Entity*)caster)->GetOwner()->GetID());
|
||||
}
|
|
@ -363,7 +363,7 @@ public:
|
|||
MutexList<LuaSpell*>* GetActiveSpells() { return &active_spells; }
|
||||
|
||||
void RemoveTargetFromSpell(LuaSpell* spell, Spawn* target);
|
||||
void CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete = true);
|
||||
void CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete = true, bool removing_all_spells = false);
|
||||
|
||||
/// <summary>Adds a solo HO to the SpellProcess</summary>
|
||||
/// <param name='client'>The client who is starting the HO</param>
|
||||
|
@ -388,6 +388,7 @@ public:
|
|||
bool ProcessSpell(LuaSpell* spell, bool first_cast = true, const char* function = 0, SpellScriptTimer* timer = 0);
|
||||
|
||||
void AddActiveSpell(LuaSpell* spell);
|
||||
static void AddSelfAndPet(LuaSpell* spell, Spawn* caster, bool onlyPet=false);
|
||||
private:
|
||||
Mutex MSpellProcess;
|
||||
MutexMap<Entity*,Spell*> spell_que;
|
||||
|
|
|
@ -2478,4 +2478,4 @@ Map* World::GetMap(std::string zoneFile, int32 client_version)
|
|||
|
||||
MWorldMaps.releasereadlock();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
|
@ -3598,10 +3598,10 @@ void WorldDatabase::UpdateStartingZone(int32 char_id, int8 class_id, int8 race_i
|
|||
int8 deity = create->getType_int8_ByName("deity"); // aka 'alignment' for early DOF, 0 = evil, 1 = good
|
||||
int32 startingZoneRuleFlag = rule_manager.GetGlobalRule(R_World, StartingZoneRuleFlag)->GetInt32();
|
||||
|
||||
if((startingZoneRuleFlag == 1 || startingZoneRuleFlag == 2) && choice > 1)
|
||||
if((startingZoneRuleFlag == 1 || startingZoneRuleFlag == 2) && packetVersion > 546)
|
||||
{
|
||||
LogWrite(PLAYER__INFO, 0, "Player", "Starting zone rule flag %u override choice %u to deity value of %u", startingZoneRuleFlag, choice, deity);
|
||||
choice = deity; // inherit deity to know starting choice is 'good' or evil
|
||||
LogWrite(PLAYER__INFO, 0, "Player", "Starting zone rule flag %u override choice %u to deity value of 0", startingZoneRuleFlag, choice);
|
||||
choice = 0;
|
||||
}
|
||||
|
||||
LogWrite(PLAYER__INFO, 0, "Player", "Adding default zone for race: %i, class: %i for char_id: %u (choice: %i), deity(alignment): %u, version: %u.", race_id, class_id, char_id, choice, deity, packetVersion);
|
||||
|
@ -7354,13 +7354,14 @@ int32 WorldDatabase::CreateSpiritShard(const char* name, int32 level, int8 race,
|
|||
|
||||
void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int8 db_spell_type)
|
||||
{
|
||||
SpellProcess* spellProcess = client->GetCurrentZone()->GetSpellProcess();
|
||||
SpellProcess* spellProcess = client->GetCurrentZone()->GetSpellProcess();
|
||||
Player* player = client->GetPlayer();
|
||||
|
||||
if(!spellProcess)
|
||||
return;
|
||||
DatabaseResult result;
|
||||
|
||||
Player* player = client->GetPlayer();
|
||||
multimap<LuaSpell*, Entity*> restoreSpells;
|
||||
// Use -1 on type and subtype to turn the enum into an int and make it a 0 index
|
||||
if (!database_new.Select(&result, "SELECT name, caster_char_id, target_char_id, target_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, custom_function FROM character_spell_effects WHERE charid = %u and db_effect_type = %u", char_id, db_spell_type)) {
|
||||
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
|
||||
|
@ -7413,9 +7414,9 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||
|
||||
bool isMaintained = false;
|
||||
bool isExistingLuaSpell = false;
|
||||
MaintainedEffects* effect;
|
||||
MaintainedEffects* effect = nullptr;
|
||||
Client* tmpCaster = nullptr;
|
||||
if(caster_char_id == player->GetCharacterID() && target_char_id == player->GetCharacterID() && (effect = player->GetMaintainedSpell(spell_id)) != nullptr)
|
||||
if(caster_char_id == player->GetCharacterID() && (target_char_id == 0xFFFFFFFF || target_char_id == player->GetCharacterID()) && (effect = player->GetMaintainedSpell(spell_id)) != nullptr)
|
||||
{
|
||||
safe_delete(lua_spell);
|
||||
lua_spell = effect->spell;
|
||||
|
@ -7427,25 +7428,22 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||
else if ( caster_char_id != player->GetCharacterID() && (tmpCaster = zone_list.GetClientByCharID(caster_char_id)) != nullptr
|
||||
&& tmpCaster->GetPlayer() && (effect = tmpCaster->GetPlayer()->GetMaintainedSpell(spell_id)) != nullptr)
|
||||
{
|
||||
if(tmpCaster->GetCurrentZone() != client->GetCurrentZone())
|
||||
{
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: GetSpell(%u, %u, '%s'), characters in different zones, cannot assign maintained spell.", spell_id, tier, lua_file.c_str());
|
||||
safe_delete(lua_spell);
|
||||
continue;
|
||||
}
|
||||
else if(effect->spell)
|
||||
if(effect->spell && effect->spell_id == spell_id)
|
||||
{
|
||||
safe_delete(lua_spell);
|
||||
effect->spell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
|
||||
effect->spell->targets.push_back(client->GetPlayer()->GetID());
|
||||
if(tmpCaster->GetCurrentZone() == player->GetZone())
|
||||
effect->spell->targets.push_back(client->GetPlayer()->GetID());
|
||||
effect->spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
|
||||
lua_spell = effect->spell;
|
||||
spell = effect->spell->spell;
|
||||
isExistingLuaSpell = true;
|
||||
isMaintained = true;
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: GetSpell(%u, %u, '%s'), effect spell id %u maintained spell recovered from %s", spell_id, tier, spell_name, effect ? effect->spell_id : 0, (tmpCaster && tmpCaster->GetPlayer()) ? tmpCaster->GetPlayer()->GetName() : "?");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: GetSpell(%u, %u, '%s'), something went wrong loading another characters maintained spell.", spell_id, tier, lua_file.c_str());
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: GetSpell(%u, %u, '%s'), something went wrong loading another characters maintained spell. Effect has spell id %u", spell_id, tier, lua_file.c_str(), effect ? effect->spell_id : 0);
|
||||
safe_delete(lua_spell);
|
||||
continue;
|
||||
}
|
||||
|
@ -7456,7 +7454,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||
|
||||
lua_interface->AddCustomSpell(lua_spell);
|
||||
}
|
||||
else
|
||||
else if(db_spell_type == DB_TYPE_MAINTAINEDEFFECTS)
|
||||
{
|
||||
safe_delete(lua_spell);
|
||||
lua_spell = lua_interface->GetSpell(spell->GetSpellData()->lua_script.c_str());
|
||||
|
@ -7483,26 +7481,95 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||
timer->customFunction = string(custom_function); // TODO
|
||||
timer->spell = lua_spell;
|
||||
timer->caster = (caster_char_id == player->GetCharacterID()) ? player->GetID() : 0;
|
||||
timer->target = (target_char_id == player->GetCharacterID()) ? player->GetID() : 0;
|
||||
|
||||
if(target_char_id == 0xFFFFFFFF && player->HasPet())
|
||||
timer->target = player->GetPet()->GetID();
|
||||
else
|
||||
timer->target = (target_char_id == player->GetCharacterID()) ? player->GetID() : 0;
|
||||
|
||||
if(!timer->target && target_char_id)
|
||||
{
|
||||
Client* tmpClient = zone_list.GetClientByCharID(target_char_id);
|
||||
if(tmpClient && tmpClient->GetPlayer() && tmpClient->GetPlayer()->GetZone() == player->GetZone())
|
||||
timer->target = tmpClient->GetPlayer()->GetID();
|
||||
}
|
||||
}
|
||||
|
||||
lua_spell->crit = crit;
|
||||
lua_spell->damage_remaining = damage_remaining;
|
||||
lua_spell->effect_bitmask = effect_bitmask;
|
||||
lua_spell->had_dmg_remaining = (damage_remaining>0) ? true : false;
|
||||
lua_spell->had_triggers = had_triggers;
|
||||
lua_spell->initial_target = (target_char_id == player->GetCharacterID()) ? player->GetID() : 0;
|
||||
lua_spell->interrupted = interrupted;
|
||||
lua_spell->last_spellattack_hit = last_spellattack_hit;
|
||||
lua_spell->num_triggers = num_triggers;
|
||||
if(!isExistingLuaSpell)
|
||||
{
|
||||
lua_spell->crit = crit;
|
||||
lua_spell->damage_remaining = damage_remaining;
|
||||
lua_spell->effect_bitmask = effect_bitmask;
|
||||
lua_spell->had_dmg_remaining = (damage_remaining>0) ? true : false;
|
||||
lua_spell->had_triggers = had_triggers;
|
||||
lua_spell->initial_caster_char_id = caster_char_id;
|
||||
lua_spell->initial_target = (target_char_id == player->GetCharacterID()) ? player->GetID() : 0;
|
||||
lua_spell->initial_target_char_id = target_char_id;
|
||||
lua_spell->interrupted = interrupted;
|
||||
lua_spell->last_spellattack_hit = last_spellattack_hit;
|
||||
lua_spell->num_triggers = num_triggers;
|
||||
}
|
||||
|
||||
if(lua_spell->initial_target == 0 && target_char_id == 0xFFFFFFFF && player->HasPet())
|
||||
{
|
||||
lua_spell->initial_target = player->GetPet()->GetID();
|
||||
lua_spell->initial_target_char_id = target_char_id;
|
||||
}
|
||||
//lua_spell->num_calls ??
|
||||
//if(target_char_id == player->GetCharacterID())
|
||||
// lua_spell->targets.push_back(player->GetID());
|
||||
|
||||
if(db_spell_type == DB_TYPE_SPELLEFFECTS)
|
||||
{
|
||||
if (caster_char_id != player->GetCharacterID() && lua_spell->spell->GetSpellData()->group_spell && lua_spell->spell->GetSpellData()->friendly_spell)
|
||||
{
|
||||
if(!isExistingLuaSpell)
|
||||
safe_delete(lua_spell);
|
||||
continue;
|
||||
}
|
||||
|
||||
player->MSpellEffects.writelock();
|
||||
info->spell_effects[effect_slot].caster = (caster_char_id == player->GetCharacterID()) ? player : 0;
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: %s lua_spell caster %s (%u), caster char id: %u.", lua_spell->spell->GetName(), lua_spell->caster ? lua_spell->caster->GetName() : "", lua_spell->caster ? lua_spell->caster->GetID() : 0, caster_char_id);
|
||||
|
||||
if(lua_spell->caster && (rule_manager.GetGlobalRule(R_Spells,EnableCrossZoneTargetBuffs)->GetInt8() || (!rule_manager.GetGlobalRule(R_Spells,EnableCrossZoneTargetBuffs)->GetInt8() && lua_spell->caster->GetZone() == player->GetZone())))
|
||||
info->spell_effects[effect_slot].caster = lua_spell->caster;
|
||||
else if(caster_char_id != player->GetCharacterID())
|
||||
{
|
||||
Client* tmpCaster = zone_list.GetClientByCharID(caster_char_id);
|
||||
if(tmpCaster)
|
||||
{
|
||||
if((rule_manager.GetGlobalRule(R_Spells,EnableCrossZoneTargetBuffs)->GetInt8() || (!rule_manager.GetGlobalRule(R_Spells,EnableCrossZoneTargetBuffs)->GetInt8() && lua_spell->caster->GetZone() == player->GetZone())))
|
||||
{
|
||||
info->spell_effects[effect_slot].caster = tmpCaster->GetPlayer();
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: %s lua_spell caster %s (%u), caster char id: %u, found player %s.", lua_spell->spell->GetName(), lua_spell->caster ? lua_spell->caster->GetName() : "", lua_spell->caster ? lua_spell->caster->GetID() : 0, caster_char_id, tmpCaster->GetPlayer()->GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: %s lua_spell caster %s (%u), caster char id: %u, found player %s, SKIPPED due to R_Spells, EnableCrossZoneTargetBuffs.", lua_spell->spell->GetName(), lua_spell->caster ? lua_spell->caster->GetName() : "", lua_spell->caster ? lua_spell->caster->GetID() : 0, caster_char_id, tmpCaster->GetPlayer()->GetName());
|
||||
if(!isExistingLuaSpell)
|
||||
{
|
||||
safe_delete(lua_spell);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_spell->char_id_targets.insert(make_pair(player->GetCharacterID(),0));
|
||||
}
|
||||
player->MSpellEffects.releasewritelock();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if(caster_char_id == player->GetCharacterID())
|
||||
info->spell_effects[effect_slot].caster = player;
|
||||
else
|
||||
{
|
||||
LogWrite(LUA__ERROR, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: %s lua_spell caster %s (%u), caster char id: %u, failed to find caster will delete: %u", lua_spell->spell->GetName(), lua_spell->caster ? lua_spell->caster->GetName() : "", lua_spell->caster ? lua_spell->caster->GetID() : 0, caster_char_id, isExistingLuaSpell);
|
||||
if(!isExistingLuaSpell)
|
||||
safe_delete(lua_spell);
|
||||
continue;
|
||||
}
|
||||
|
||||
info->spell_effects[effect_slot].expire_timestamp = Timer::GetCurrentTime2() + expire_timestamp;
|
||||
info->spell_effects[effect_slot].icon = icon;
|
||||
info->spell_effects[effect_slot].icon_backdrop = icon_backdrop;
|
||||
|
@ -7510,11 +7577,24 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||
info->spell_effects[effect_slot].tier = tier;
|
||||
info->spell_effects[effect_slot].total_time = total_time;
|
||||
info->spell_effects[effect_slot].spell = lua_spell;
|
||||
lua_spell->caster = player; // TODO: get actual player
|
||||
printf("SlotPos: %u %s\n",slot_pos,spell->GetName());
|
||||
multimap<int32,int8>::iterator entries;
|
||||
while((entries = lua_spell->char_id_targets.find(player->GetCharacterID())) != lua_spell->char_id_targets.end())
|
||||
{
|
||||
lua_spell->char_id_targets.erase(entries);
|
||||
}
|
||||
lua_spell->slot_pos = slot_pos;
|
||||
if(!isExistingLuaSpell)
|
||||
lua_spell->caster = player; // TODO: get actual player
|
||||
|
||||
player->MSpellEffects.releasewritelock();
|
||||
|
||||
if(!isMaintained)
|
||||
spellProcess->ProcessSpell(lua_spell, true, "cast", timer);
|
||||
else
|
||||
{
|
||||
// track target id when caster isnt in zone somehow
|
||||
}
|
||||
}
|
||||
else if ( db_spell_type == DB_TYPE_MAINTAINEDEFFECTS )
|
||||
{
|
||||
|
@ -7530,18 +7610,59 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||
if(spell_id != in_spell_id)
|
||||
continue;
|
||||
|
||||
Client* client2 = zone_list.GetClientByCharID(target_char);
|
||||
int32 idToAdd = 0;
|
||||
|
||||
if(target_char == 0xFFFFFFFF)
|
||||
{
|
||||
if( player->HasPet() )
|
||||
{
|
||||
idToAdd = player->GetPet()->GetID();
|
||||
restoreSpells.insert(make_pair(lua_spell, player->GetPet()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Client* client2 = zone_list.GetClientByCharID(target_char);
|
||||
if(client2 && client2->GetPlayer() && client2->GetCurrentZone() == client->GetCurrentZone())
|
||||
{
|
||||
idToAdd = client2->GetPlayer()->GetID();
|
||||
if(client != client2)
|
||||
restoreSpells.insert(make_pair(lua_spell, client2->GetPlayer()));
|
||||
|
||||
multimap<int32,int8>::iterator entries;
|
||||
while((entries = lua_spell->char_id_targets.find(target_char)) != lua_spell->char_id_targets.end())
|
||||
{
|
||||
lua_spell->char_id_targets.erase(entries);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_spell->char_id_targets.insert(make_pair(target_char,0));
|
||||
}
|
||||
}
|
||||
|
||||
if(!idToAdd)
|
||||
continue;
|
||||
|
||||
lua_spell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
|
||||
if(client2 && client2->GetPlayer() && client2->GetCurrentZone() == client->GetCurrentZone())
|
||||
lua_spell->targets.push_back(client2->GetPlayer()->GetID());
|
||||
lua_spell->targets.push_back(idToAdd);
|
||||
lua_spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Client* tmpClient = 0;
|
||||
int32 targetID = 0;
|
||||
if(target_char_id == 0xFFFFFFFF && player->HasPet())
|
||||
targetID = player->GetPet()->GetID();
|
||||
else if(target_char_id == player->GetCharacterID())
|
||||
targetID = player->GetID();
|
||||
else if((tmpClient = zone_list.GetClientByCharID(target_char_id)) != nullptr && tmpClient->GetPlayer())
|
||||
targetID = tmpClient->GetPlayer()->GetID();
|
||||
|
||||
info->maintained_effects[effect_slot].conc_used = conc_used;
|
||||
strncpy(info->maintained_effects[effect_slot].name, spell_name, 60);
|
||||
info->maintained_effects[effect_slot].slot_pos = slot_pos;
|
||||
info->maintained_effects[effect_slot].target = (target_char_id == player->GetCharacterID()) ? player->GetID() : 0;
|
||||
info->maintained_effects[effect_slot].target = targetID;
|
||||
info->maintained_effects[effect_slot].target_type = target_type;
|
||||
info->maintained_effects[effect_slot].expire_timestamp = Timer::GetCurrentTime2() + expire_timestamp;
|
||||
info->maintained_effects[effect_slot].icon = icon;
|
||||
|
@ -7550,9 +7671,18 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||
info->maintained_effects[effect_slot].tier = tier;
|
||||
info->maintained_effects[effect_slot].total_time = total_time;
|
||||
info->maintained_effects[effect_slot].spell = lua_spell;
|
||||
lua_spell->caster = player;
|
||||
if(!isExistingLuaSpell)
|
||||
lua_spell->caster = player;
|
||||
player->MMaintainedSpells.releasewritelock();
|
||||
|
||||
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: %s process spell caster %s (%u), caster char id: %u, target id %u (%s).", lua_spell->spell->GetName(), lua_spell->caster ? lua_spell->caster->GetName() : "",
|
||||
lua_spell->caster ? lua_spell->caster->GetID() : 0, caster_char_id, targetID, tmpClient ? tmpClient->GetPlayer()->GetName() : "");
|
||||
if(tmpClient && lua_spell->initial_target_char_id == tmpClient->GetCharacterID())
|
||||
{
|
||||
lua_spell->initial_target = tmpClient->GetPlayer()->GetID();
|
||||
lua_spell->targets.push_back(lua_spell->initial_target);
|
||||
}
|
||||
|
||||
spellProcess->ProcessSpell(lua_spell, true, "cast", timer);
|
||||
}
|
||||
if(!isExistingLuaSpell && expire_timestamp != 0xFFFFFFFF && !isMaintained)
|
||||
|
@ -7562,20 +7692,99 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||
lua_spell->timer.Start();
|
||||
}
|
||||
|
||||
if(lua_spell->spell->GetSpellData()->det_type)
|
||||
if(target_char_id == player->GetCharacterID() && lua_spell->spell->GetSpellData()->det_type)
|
||||
player->AddDetrimentalSpell(lua_spell, expire_timestamp);
|
||||
|
||||
if(timer)
|
||||
spellProcess->AddSpellScriptTimer(timer);
|
||||
|
||||
lua_spell->num_calls = 1;
|
||||
lua_spell->restored = true;
|
||||
if(!isExistingLuaSpell)
|
||||
{
|
||||
if(timer)
|
||||
spellProcess->AddSpellScriptTimer(timer);
|
||||
|
||||
lua_spell->num_calls = 1;
|
||||
lua_spell->restored = true;
|
||||
}
|
||||
|
||||
if(!lua_spell->resisted && (lua_spell->spell->GetSpellDuration() > 0 || lua_spell->spell->GetSpellData()->duration_until_cancel))
|
||||
spellProcess->AddActiveSpell(lua_spell);
|
||||
|
||||
if (num_triggers > 0)
|
||||
ClientPacketFunctions::SendMaintainedExamineUpdate(client, slot_pos, num_triggers, 0);
|
||||
if (damage_remaining > 0)
|
||||
ClientPacketFunctions::SendMaintainedExamineUpdate(client, slot_pos, damage_remaining, 1);
|
||||
if ( db_spell_type == DB_TYPE_MAINTAINEDEFFECTS )
|
||||
{
|
||||
if (num_triggers > 0)
|
||||
ClientPacketFunctions::SendMaintainedExamineUpdate(client, slot_pos, num_triggers, 0);
|
||||
if (damage_remaining > 0)
|
||||
ClientPacketFunctions::SendMaintainedExamineUpdate(client, slot_pos, damage_remaining, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(!rule_manager.GetGlobalRule(R_Spells,EnableCrossZoneTargetBuffs)->GetInt8() && db_spell_type == DB_TYPE_SPELLEFFECTS)
|
||||
{
|
||||
DatabaseResult targets;
|
||||
if (database_new.Select(&targets, "SELECT caster_char_id, target_type, spell_id from character_spell_effect_targets where target_char_id = %u", player->GetCharacterID())) {
|
||||
while (targets.Next()) {
|
||||
int32 caster_char_id = targets.GetInt32Str("caster_char_id");
|
||||
int16 target_type = targets.GetInt32Str("target_type");
|
||||
int32 in_spell_id = targets.GetInt32Str("spell_id");
|
||||
Client* tmpCaster = nullptr;
|
||||
MaintainedEffects* effect = nullptr;
|
||||
if ( caster_char_id != player->GetCharacterID() && (tmpCaster = zone_list.GetClientByCharID(caster_char_id)) != nullptr
|
||||
&& tmpCaster->GetCurrentZone() == player->GetZone() && tmpCaster->GetPlayer() && (effect = tmpCaster->GetPlayer()->GetMaintainedSpell(in_spell_id)) != nullptr)
|
||||
{
|
||||
if(!player->GetSpellEffect(effect->spell_id, tmpCaster->GetPlayer()))
|
||||
{
|
||||
if(effect->spell->initial_target_char_id == player->GetCharacterID())
|
||||
effect->spell->initial_target = player->GetID();
|
||||
restoreSpells.insert(make_pair(effect->spell, player));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multimap<LuaSpell*, Entity*>::const_iterator itr;
|
||||
|
||||
for (itr = restoreSpells.begin(); itr != restoreSpells.end(); itr++)
|
||||
{
|
||||
LuaSpell* tmpSpell = itr->first;
|
||||
Entity* target = itr->second;
|
||||
if(!target)
|
||||
{
|
||||
target = client->GetPlayer()->GetPet();
|
||||
if(!target)
|
||||
continue;
|
||||
}
|
||||
|
||||
Entity* caster = tmpSpell->caster;
|
||||
if(!caster)
|
||||
caster = client->GetPlayer();
|
||||
|
||||
if(caster != target && caster->GetPet() != target &&
|
||||
tmpSpell->spell->GetSpellData()->group_spell && tmpSpell->spell->GetSpellData()->friendly_spell && (caster->group_id == 0 || target->group_id == 0 || caster->group_id != target->group_id))
|
||||
{
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: %s player no longer grouped with %s to reload bonuses for spell %s.", target->GetName(), caster ? caster->GetName() : "?", tmpSpell->spell->GetName());
|
||||
continue;
|
||||
}
|
||||
|
||||
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: %s using caster %s to reload bonuses for spell %s.", player->GetName(), caster ? caster->GetName() : "?", tmpSpell->spell->GetName());
|
||||
|
||||
target->AddSpellEffect(tmpSpell, tmpSpell->timer.GetRemainingTime() != 0 ? tmpSpell->timer.GetRemainingTime() : 0);
|
||||
vector<BonusValues*>* sb_list = caster->GetAllSpellBonuses(tmpSpell);
|
||||
for (int32 x = 0; x < sb_list->size(); x++) {
|
||||
BonusValues* bv = sb_list->at(x);
|
||||
target->AddSpellBonus(tmpSpell, bv->type, bv->value, bv->class_req, bv->race_req, bv->faction_req);
|
||||
}
|
||||
sb_list->clear();
|
||||
safe_delete(sb_list);
|
||||
// look for a skill bonus on the caster's spell
|
||||
if(caster->IsPlayer())
|
||||
{
|
||||
SkillBonus* sb = ((Player*)caster)->GetSkillBonus(tmpSpell->spell->GetSpellID());
|
||||
if (sb) {
|
||||
map<int32, SkillBonusValue*>::iterator itr_skills;
|
||||
for (itr_skills = sb->skills.begin(); itr_skills != sb->skills.end(); itr_skills++)
|
||||
target->AddSkillBonus(sb->spell_id, (*itr_skills).second->skill_id, (*itr_skills).second->value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -3018,6 +3018,8 @@ void ZoneServer::RemoveClient(Client* client)
|
|||
LogWrite(MISC__TODO, 1, "TODO", "Put Player Online Status updates in a timer eventually\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
|
||||
database.ToggleCharacterOnline(client, 0);
|
||||
|
||||
client->GetPlayer()->DeleteSpellEffects(true);
|
||||
|
||||
RemoveSpawn(client->GetPlayer(), false);
|
||||
connected_clients.Remove(client, true, DisconnectClientTimer); // changed from a hardcoded 30000 (30 sec) to the DisconnectClientTimer rule
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue