Fix #38 address issues with food/drink cross zone
Custom spells now survive cross zone with their modified spell stats saved to the database for reloading later. The design is such that a spell can be custom defined for its spell stats, but a character/player cannot have more than one of that spell (eg. food can share a spell id since only one food can be applied to you, but you can't have many spells apply using the same custom spell id). CREATE TABLE character_custom_spell_dataindex ( charid INT UNSIGNED NOT NULL, spell_id INT UNSIGNED NOT NULL, idx INT UNSIGNED NOT NULL, type ENUM('int', 'float', 'bool', 'string') NOT NULL, value1 TEXT, value2 TEXT, PRIMARY KEY (charid, spell_id, idx) ); CREATE TABLE character_custom_spell_display ( charid INT UNSIGNED NOT NULL, spell_id INT UNSIGNED NOT NULL, idx INT UNSIGNED NOT NULL, field VARCHAR(64) NOT NULL, value TEXT, PRIMARY KEY (charid, spell_id, idx, field) ); CREATE TABLE character_custom_spell_data ( charid INT UNSIGNED NOT NULL, spell_id INT UNSIGNED NOT NULL, field VARCHAR(64) NOT NULL, type ENUM('int', 'float', 'bool', 'string') NOT NULL, value TEXT NOT NULL, PRIMARY KEY (charid, spell_id, field) );
This commit is contained in:
parent
11a6a80647
commit
260a48be1e
@ -127,6 +127,7 @@ void Entity::DeleteSpellEffects(bool removeClient)
|
|||||||
if (IsPlayer())
|
if (IsPlayer())
|
||||||
GetInfoStruct()->maintained_effects[i].icon = 0xFFFF;
|
GetInfoStruct()->maintained_effects[i].icon = 0xFFFF;
|
||||||
GetInfoStruct()->maintained_effects[i].spell_id = 0xFFFFFFFF;
|
GetInfoStruct()->maintained_effects[i].spell_id = 0xFFFFFFFF;
|
||||||
|
GetInfoStruct()->maintained_effects[i].inherited_spell_id = 0;
|
||||||
GetInfoStruct()->maintained_effects[i].spell = nullptr;
|
GetInfoStruct()->maintained_effects[i].spell = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,6 +140,7 @@ void Entity::DeleteSpellEffects(bool removeClient)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
GetInfoStruct()->spell_effects[i].spell_id = 0xFFFFFFFF;
|
GetInfoStruct()->spell_effects[i].spell_id = 0xFFFFFFFF;
|
||||||
|
GetInfoStruct()->spell_effects[i].inherited_spell_id = 0;
|
||||||
GetInfoStruct()->spell_effects[i].icon = 0;
|
GetInfoStruct()->spell_effects[i].icon = 0;
|
||||||
GetInfoStruct()->spell_effects[i].icon_backdrop = 0;
|
GetInfoStruct()->spell_effects[i].icon_backdrop = 0;
|
||||||
GetInfoStruct()->spell_effects[i].tier = 0;
|
GetInfoStruct()->spell_effects[i].tier = 0;
|
||||||
@ -1177,6 +1179,7 @@ void Entity::RemoveMaintainedSpell(LuaSpell* luaspell){
|
|||||||
if (found) {
|
if (found) {
|
||||||
memset(&GetInfoStruct()->maintained_effects[29], 0, sizeof(MaintainedEffects));
|
memset(&GetInfoStruct()->maintained_effects[29], 0, sizeof(MaintainedEffects));
|
||||||
GetInfoStruct()->maintained_effects[29].spell_id = 0xFFFFFFFF;
|
GetInfoStruct()->maintained_effects[29].spell_id = 0xFFFFFFFF;
|
||||||
|
GetInfoStruct()->maintained_effects[29].inherited_spell_id = 0;
|
||||||
GetInfoStruct()->maintained_effects[29].icon = 0xFFFF;
|
GetInfoStruct()->maintained_effects[29].icon = 0xFFFF;
|
||||||
GetInfoStruct()->maintained_effects[29].spell = nullptr;
|
GetInfoStruct()->maintained_effects[29].spell = nullptr;
|
||||||
}
|
}
|
||||||
@ -1198,6 +1201,7 @@ void Entity::RemoveSpellEffect(LuaSpell* spell) {
|
|||||||
GetZone()->GetSpellProcess()->RemoveTargetFromSpell(spell, this);
|
GetZone()->GetSpellProcess()->RemoveTargetFromSpell(spell, this);
|
||||||
memset(&GetInfoStruct()->spell_effects[44], 0, sizeof(SpellEffects));
|
memset(&GetInfoStruct()->spell_effects[44], 0, sizeof(SpellEffects));
|
||||||
GetInfoStruct()->spell_effects[44].spell_id = 0xFFFFFFFF;
|
GetInfoStruct()->spell_effects[44].spell_id = 0xFFFFFFFF;
|
||||||
|
GetInfoStruct()->spell_effects[44].inherited_spell_id = 0;
|
||||||
GetInfoStruct()->spell_effects[44].spell = nullptr;
|
GetInfoStruct()->spell_effects[44].spell = nullptr;
|
||||||
changed = true;
|
changed = true;
|
||||||
info_changed = true;
|
info_changed = true;
|
||||||
@ -1227,12 +1231,12 @@ MaintainedEffects* Entity::GetFreeMaintainedSpellSlot(){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaintainedEffects* Entity::GetMaintainedSpell(int32 spell_id){
|
MaintainedEffects* Entity::GetMaintainedSpell(int32 spell_id, bool on_char_load){
|
||||||
MaintainedEffects* ret = 0;
|
MaintainedEffects* ret = 0;
|
||||||
InfoStruct* info = GetInfoStruct();
|
InfoStruct* info = GetInfoStruct();
|
||||||
MMaintainedSpells.readlock(__FUNCTION__, __LINE__);
|
MMaintainedSpells.readlock(__FUNCTION__, __LINE__);
|
||||||
for (int i = 0; i<NUM_MAINTAINED_EFFECTS; i++){
|
for (int i = 0; i<NUM_MAINTAINED_EFFECTS; i++){
|
||||||
if (info->maintained_effects[i].spell_id == spell_id){
|
if (info->maintained_effects[i].spell_id == spell_id || (on_char_load && info->maintained_effects[i].inherited_spell_id == id)){
|
||||||
ret = &info->maintained_effects[i];
|
ret = &info->maintained_effects[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1256,12 +1260,12 @@ SpellEffects* Entity::GetFreeSpellEffectSlot(){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpellEffects* Entity::GetSpellEffect(int32 id, Entity* caster) {
|
SpellEffects* Entity::GetSpellEffect(int32 id, Entity* caster, bool on_char_load) {
|
||||||
SpellEffects* ret = 0;
|
SpellEffects* ret = 0;
|
||||||
InfoStruct* info = GetInfoStruct();
|
InfoStruct* info = GetInfoStruct();
|
||||||
MSpellEffects.readlock(__FUNCTION__, __LINE__);
|
MSpellEffects.readlock(__FUNCTION__, __LINE__);
|
||||||
for(int i = 0; i < 45; i++) {
|
for(int i = 0; i < 45; i++) {
|
||||||
if(info->spell_effects[i].spell_id == id) {
|
if(info->spell_effects[i].spell_id == id || (on_char_load && info->maintained_effects[i].inherited_spell_id == id)) {
|
||||||
if (!caster || info->spell_effects[i].caster == caster){
|
if (!caster || info->spell_effects[i].caster == caster){
|
||||||
ret = &info->spell_effects[i];
|
ret = &info->spell_effects[i];
|
||||||
break;
|
break;
|
||||||
@ -2743,6 +2747,7 @@ void Entity::AddDetrimentalSpell(LuaSpell* luaspell, int32 override_expire_times
|
|||||||
new_det.det_type = data->det_type;
|
new_det.det_type = data->det_type;
|
||||||
new_det.incurable = data->incurable;
|
new_det.incurable = data->incurable;
|
||||||
new_det.spell_id = spell->GetSpellID();
|
new_det.spell_id = spell->GetSpellID();
|
||||||
|
new_det.inherited_spell_id = data->inherited_spell_id;
|
||||||
new_det.control_effect = data->control_effect_type;
|
new_det.control_effect = data->control_effect_type;
|
||||||
new_det.total_time = spell->GetSpellDuration()/10;
|
new_det.total_time = spell->GetSpellDuration()/10;
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ struct MaintainedEffects{
|
|||||||
int32 target;
|
int32 target;
|
||||||
int8 target_type;
|
int8 target_type;
|
||||||
int32 spell_id;
|
int32 spell_id;
|
||||||
|
int32 inherited_spell_id;
|
||||||
int32 slot_pos;
|
int32 slot_pos;
|
||||||
int16 icon;
|
int16 icon;
|
||||||
int16 icon_backdrop;
|
int16 icon_backdrop;
|
||||||
@ -67,6 +68,7 @@ struct MaintainedEffects{
|
|||||||
|
|
||||||
struct SpellEffects{
|
struct SpellEffects{
|
||||||
int32 spell_id;
|
int32 spell_id;
|
||||||
|
int32 inherited_spell_id;
|
||||||
Entity* caster;
|
Entity* caster;
|
||||||
float total_time;
|
float total_time;
|
||||||
int32 expire_timestamp;
|
int32 expire_timestamp;
|
||||||
@ -78,6 +80,7 @@ struct SpellEffects{
|
|||||||
|
|
||||||
struct DetrimentalEffects {
|
struct DetrimentalEffects {
|
||||||
int32 spell_id;
|
int32 spell_id;
|
||||||
|
int32 inherited_spell_id;
|
||||||
Entity* caster;
|
Entity* caster;
|
||||||
int32 expire_timestamp;
|
int32 expire_timestamp;
|
||||||
int16 icon;
|
int16 icon;
|
||||||
@ -1067,6 +1070,7 @@ struct InfoStruct{
|
|||||||
for(int i=0;i<45;i++){
|
for(int i=0;i<45;i++){
|
||||||
if(i<30){
|
if(i<30){
|
||||||
maintained_effects[i].spell_id = 0xFFFFFFFF;
|
maintained_effects[i].spell_id = 0xFFFFFFFF;
|
||||||
|
maintained_effects[i].inherited_spell_id = 0;
|
||||||
if (spawn->IsPlayer())
|
if (spawn->IsPlayer())
|
||||||
maintained_effects[i].icon = 0xFFFF;
|
maintained_effects[i].icon = 0xFFFF;
|
||||||
|
|
||||||
@ -1074,6 +1078,7 @@ struct InfoStruct{
|
|||||||
}
|
}
|
||||||
spell_effects[i].icon = 0;
|
spell_effects[i].icon = 0;
|
||||||
spell_effects[i].spell_id = 0xFFFFFFFF;
|
spell_effects[i].spell_id = 0xFFFFFFFF;
|
||||||
|
spell_effects[i].inherited_spell_id = 0;
|
||||||
spell_effects[i].icon_backdrop = 0;
|
spell_effects[i].icon_backdrop = 0;
|
||||||
spell_effects[i].tier = 0;
|
spell_effects[i].tier = 0;
|
||||||
spell_effects[i].total_time = 0.0f;
|
spell_effects[i].total_time = 0.0f;
|
||||||
@ -1425,7 +1430,7 @@ public:
|
|||||||
virtual void AddSkillBonus(int32 spell_id, int32 skill_id, float value);
|
virtual void AddSkillBonus(int32 spell_id, int32 skill_id, float value);
|
||||||
void AddDetrimentalSpell(LuaSpell* spell, int32 override_expire_timestamp = 0);
|
void AddDetrimentalSpell(LuaSpell* spell, int32 override_expire_timestamp = 0);
|
||||||
DetrimentalEffects* GetDetrimentalEffect(int32 spell_id, Entity* caster);
|
DetrimentalEffects* GetDetrimentalEffect(int32 spell_id, Entity* caster);
|
||||||
virtual MaintainedEffects* GetMaintainedSpell(int32 spell_id);
|
virtual MaintainedEffects* GetMaintainedSpell(int32 spell_id, bool on_char_load = false);
|
||||||
void RemoveDetrimentalSpell(LuaSpell* spell);
|
void RemoveDetrimentalSpell(LuaSpell* spell);
|
||||||
void SetDeity(int8 new_deity){
|
void SetDeity(int8 new_deity){
|
||||||
deity = new_deity;
|
deity = new_deity;
|
||||||
@ -1489,7 +1494,7 @@ public:
|
|||||||
void DoRegenUpdate();
|
void DoRegenUpdate();
|
||||||
MaintainedEffects* GetFreeMaintainedSpellSlot();
|
MaintainedEffects* GetFreeMaintainedSpellSlot();
|
||||||
SpellEffects* GetFreeSpellEffectSlot();
|
SpellEffects* GetFreeSpellEffectSlot();
|
||||||
SpellEffects* GetSpellEffect(int32 id, Entity* caster = 0);
|
SpellEffects* GetSpellEffect(int32 id, Entity* caster = 0, bool on_char_load = false);
|
||||||
SpellEffects* GetSpellEffectBySpellType(int8 spell_type);
|
SpellEffects* GetSpellEffectBySpellType(int8 spell_type);
|
||||||
SpellEffects* GetSpellEffectWithLinkedTimer(int32 id, int32 linked_timer = 0, sint32 type_group_spell_id = 0, Entity* caster = 0);
|
SpellEffects* GetSpellEffectWithLinkedTimer(int32 id, int32 linked_timer = 0, sint32 type_group_spell_id = 0, Entity* caster = 0);
|
||||||
LuaSpell* HasLinkedTimerID(LuaSpell* spell, Spawn* target = nullptr, bool stackWithOtherPlayers = true);
|
LuaSpell* HasLinkedTimerID(LuaSpell* spell, Spawn* target = nullptr, bool stackWithOtherPlayers = true);
|
||||||
|
@ -12436,12 +12436,16 @@ int EQ2Emu_lua_SetSpellData(lua_State* state) {
|
|||||||
|
|
||||||
boost::to_lower(field);
|
boost::to_lower(field);
|
||||||
|
|
||||||
bool valSet = false;
|
bool setVal = false;
|
||||||
|
|
||||||
spell->spell->SetSpellData(state, field, fieldArg);
|
setVal = spell->spell->SetSpellData(state, field, fieldArg);
|
||||||
lua_interface->ResetFunctionStack(state);
|
lua_interface->ResetFunctionStack(state);
|
||||||
|
if(setVal) {
|
||||||
return valSet;
|
spell->MarkFieldModified(field);
|
||||||
|
}
|
||||||
|
lua_interface->SetBooleanValue(state, setVal);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int EQ2Emu_lua_SetSpellDataIndex(lua_State* state) {
|
int EQ2Emu_lua_SetSpellDataIndex(lua_State* state) {
|
||||||
@ -12509,8 +12513,14 @@ int EQ2Emu_lua_SetSpellDataIndex(lua_State* state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lua_interface->ResetFunctionStack(state);
|
lua_interface->ResetFunctionStack(state);
|
||||||
|
|
||||||
|
lua_interface->SetBooleanValue(state, setVal);
|
||||||
|
|
||||||
return setVal;
|
if(setVal) {
|
||||||
|
data->needs_db_save = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -12607,22 +12617,30 @@ int EQ2Emu_lua_SetSpellDisplayEffect(lua_State* state) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool setVal = true;
|
||||||
// do we need to lock? eh probably not this should only be used before use of the custom spell
|
// do we need to lock? eh probably not this should only be used before use of the custom spell
|
||||||
SpellDisplayEffect* effect = spell->spell->effects[idx];
|
SpellDisplayEffect* effect = spell->spell->effects[idx];
|
||||||
|
|
||||||
if (field == "description")
|
if (field == "description") {
|
||||||
effect->description = string(lua_interface->GetStringValue(state, 4));
|
effect->description = string(lua_interface->GetStringValue(state, 4));
|
||||||
else if (field == "bullet")
|
effect->needs_db_save = true;
|
||||||
effect->subbullet = lua_interface->GetInt8Value(state, 4);
|
|
||||||
else if (field == "percentage")
|
|
||||||
effect->percentage = lua_interface->GetInt8Value(state, 4);
|
|
||||||
else { // no match
|
|
||||||
lua_interface->ResetFunctionStack(state);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
else if (field == "bullet") {
|
||||||
|
effect->subbullet = lua_interface->GetInt8Value(state, 4);
|
||||||
|
effect->needs_db_save = true;
|
||||||
|
}
|
||||||
|
else if (field == "percentage") {
|
||||||
|
effect->percentage = lua_interface->GetInt8Value(state, 4);
|
||||||
|
effect->needs_db_save = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setVal = false;
|
||||||
|
}
|
||||||
|
|
||||||
lua_interface->ResetFunctionStack(state);
|
lua_interface->ResetFunctionStack(state);
|
||||||
|
|
||||||
|
lua_interface->SetBooleanValue(state, setVal);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,149 @@ extern WorldDatabase database;
|
|||||||
extern ZoneList zone_list;
|
extern ZoneList zone_list;
|
||||||
|
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, std::pair<SpellFieldType, SpellFieldGetter>> SpellDataFieldAccessors = {
|
||||||
|
{"spell_book_type", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->spell_book_type); }}},
|
||||||
|
{"icon", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->icon); }}},
|
||||||
|
{"icon_heroic_op", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->icon_heroic_op); }}},
|
||||||
|
{"icon_backdrop", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->icon_backdrop); }}},
|
||||||
|
{"type", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->type); }}},
|
||||||
|
{"class_skill", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->class_skill); }}},
|
||||||
|
{"min_class_skill_req", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->min_class_skill_req); }}},
|
||||||
|
{"mastery_skill", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->mastery_skill); }}},
|
||||||
|
{"ts_loc_index", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->ts_loc_index); }}},
|
||||||
|
{"num_levels", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->num_levels); }}},
|
||||||
|
{"tier", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->tier); }}},
|
||||||
|
{"hp_req", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->hp_req); }}},
|
||||||
|
{"hp_upkeep", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->hp_upkeep); }}},
|
||||||
|
{"power_req", {SpellFieldType::Float, [](SpellData* d) { return std::to_string(d->power_req); }}},
|
||||||
|
{"power_by_level", {SpellFieldType::Boolean, [](SpellData* d) { return d->power_by_level ? "1" : "0"; }}},
|
||||||
|
{"power_upkeep", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->power_upkeep); }}},
|
||||||
|
{"savagery_req", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->savagery_req); }}},
|
||||||
|
{"savagery_upkeep", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->savagery_upkeep); }}},
|
||||||
|
{"dissonance_req", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->dissonance_req); }}},
|
||||||
|
{"dissonance_upkeep", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->dissonance_upkeep); }}},
|
||||||
|
{"target_type", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->target_type); }}},
|
||||||
|
{"cast_time", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->cast_time); }}},
|
||||||
|
{"recovery", {SpellFieldType::Float, [](SpellData* d) { return std::to_string(d->recovery); }}},
|
||||||
|
{"recast", {SpellFieldType::Float, [](SpellData* d) { return std::to_string(d->recast); }}},
|
||||||
|
{"linked_timer", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->linked_timer); }}},
|
||||||
|
{"radius", {SpellFieldType::Float, [](SpellData* d) { return std::to_string(d->radius); }}},
|
||||||
|
{"max_aoe_targets", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->max_aoe_targets); }}},
|
||||||
|
{"friendly_spell", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->friendly_spell); }}},
|
||||||
|
{"req_concentration", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->req_concentration); }}},
|
||||||
|
{"range", {SpellFieldType::Float, [](SpellData* d) { return std::to_string(d->range); }}},
|
||||||
|
{"duration1", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->duration1); }}},
|
||||||
|
{"duration2", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->duration2); }}},
|
||||||
|
{"resistibility", {SpellFieldType::Float, [](SpellData* d) { return std::to_string(d->resistibility); }}},
|
||||||
|
{"duration_until_cancel", {SpellFieldType::Boolean, [](SpellData* d) { return d->duration_until_cancel ? "1" : "0"; }}},
|
||||||
|
{"power_req_percent", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->power_req_percent); }}},
|
||||||
|
{"hp_req_percent", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->hp_req_percent); }}},
|
||||||
|
{"savagery_req_percent", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->savagery_req_percent); }}},
|
||||||
|
{"dissonance_req_percent", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->dissonance_req_percent); }}},
|
||||||
|
{"name", {SpellFieldType::String, [](SpellData* d) { return d->name.data; }}},
|
||||||
|
{"description", {SpellFieldType::String, [](SpellData* d) { return d->description.data; }}},
|
||||||
|
{"success_message", {SpellFieldType::String, [](SpellData* d) { return d->success_message; }}},
|
||||||
|
{"fade_message", {SpellFieldType::String, [](SpellData* d) { return d->fade_message; }}},
|
||||||
|
{"fade_message_others", {SpellFieldType::String, [](SpellData* d) { return d->fade_message_others; }}},
|
||||||
|
{"cast_type", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->cast_type).c_str(); }}},
|
||||||
|
{"lua_script", {SpellFieldType::String, [](SpellData* d) { return d->lua_script; }}},
|
||||||
|
{"interruptable", {SpellFieldType::Boolean, [](SpellData* d) { return d->interruptable ? "1" : "0"; }}},
|
||||||
|
{"spell_visual", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->spell_visual); }}},
|
||||||
|
{"effect_message", {SpellFieldType::String, [](SpellData* d) { return d->effect_message; }}},
|
||||||
|
{"min_range", {SpellFieldType::Float, [](SpellData* d) { return std::to_string(d->min_range); }}},
|
||||||
|
{"can_effect_raid", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->can_effect_raid); }}},
|
||||||
|
{"affect_only_group_members", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->affect_only_group_members); }}},
|
||||||
|
{"group_spell", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->group_spell); }}},
|
||||||
|
{"hit_bonus", {SpellFieldType::Float, [](SpellData* d) { return std::to_string(d->hit_bonus); }}},
|
||||||
|
{"display_spell_tier", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->display_spell_tier); }}},
|
||||||
|
{"is_active", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->is_active); }}},
|
||||||
|
{"det_type", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->det_type); }}},
|
||||||
|
{"incurable", {SpellFieldType::Boolean, [](SpellData* d) { return d->incurable ? "1" : "0"; }}},
|
||||||
|
{"control_effect_type", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->control_effect_type); }}},
|
||||||
|
{"casting_flags", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->casting_flags); }}},
|
||||||
|
{"cast_while_moving", {SpellFieldType::Boolean, [](SpellData* d) { return d->cast_while_moving ? "1" : "0"; }}},
|
||||||
|
{"persist_through_death", {SpellFieldType::Boolean, [](SpellData* d) { return d->persist_through_death ? "1" : "0"; }}},
|
||||||
|
{"not_maintained", {SpellFieldType::Boolean, [](SpellData* d) { return d->not_maintained ? "1" : "0"; }}},
|
||||||
|
{"is_aa", {SpellFieldType::Boolean, [](SpellData* d) { return d->is_aa ? "1" : "0"; }}},
|
||||||
|
{"savage_bar", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->savage_bar); }}},
|
||||||
|
{"savage_bar_slot", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->savage_bar_slot); }}},
|
||||||
|
{"soe_spell_crc", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->soe_spell_crc); }}},
|
||||||
|
{"spell_type", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->spell_type); }}},
|
||||||
|
{"spell_name_crc", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->spell_name_crc); }}},
|
||||||
|
{"type_group_spell_id", {SpellFieldType::Integer, [](SpellData* d) { return std::to_string(d->type_group_spell_id); }}},
|
||||||
|
{"can_fizzle", {SpellFieldType::Boolean, [](SpellData* d) { return d->can_fizzle ? "1" : "0"; }}}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, std::function<void(Spell*, const std::string&)>> SpellFieldGenericSetters = {
|
||||||
|
{ "spell_book_type", [](Spell* spell, const std::string& val) { spell->GetSpellData()->spell_book_type = static_cast<int32>(std::stoi(val)); } },
|
||||||
|
{ "icon", [](Spell* spell, const std::string& val) { spell->GetSpellData()->icon = static_cast<sint16>(std::stoi(val)); } },
|
||||||
|
{ "icon_heroic_op", [](Spell* spell, const std::string& val) { spell->GetSpellData()->icon_heroic_op = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "icon_backdrop", [](Spell* spell, const std::string& val) { spell->GetSpellData()->icon_backdrop = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "type", [](Spell* spell, const std::string& val) { spell->GetSpellData()->type = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "class_skill", [](Spell* spell, const std::string& val) { spell->GetSpellData()->class_skill = static_cast<int32>(std::stoi(val)); } },
|
||||||
|
{ "min_class_skill_req", [](Spell* spell, const std::string& val) { spell->GetSpellData()->min_class_skill_req = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "mastery_skill", [](Spell* spell, const std::string& val) { spell->GetSpellData()->mastery_skill = static_cast<int32>(std::stoi(val)); } },
|
||||||
|
{ "ts_loc_index", [](Spell* spell, const std::string& val) { spell->GetSpellData()->ts_loc_index = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "num_levels", [](Spell* spell, const std::string& val) { spell->GetSpellData()->num_levels = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "tier", [](Spell* spell, const std::string& val) { spell->GetSpellData()->tier = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "hp_req", [](Spell* spell, const std::string& val) { spell->GetSpellData()->hp_req = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "hp_upkeep", [](Spell* spell, const std::string& val) { spell->GetSpellData()->hp_upkeep = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "power_req", [](Spell* spell, const std::string& val) { spell->GetSpellData()->power_req = std::stof(val); } },
|
||||||
|
{ "power_by_level", [](Spell* spell, const std::string& val) { spell->GetSpellData()->power_by_level = (val == "1" || val == "true"); } },
|
||||||
|
{ "power_upkeep", [](Spell* spell, const std::string& val) { spell->GetSpellData()->power_upkeep = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "savagery_req", [](Spell* spell, const std::string& val) { spell->GetSpellData()->savagery_req = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "savagery_upkeep", [](Spell* spell, const std::string& val) { spell->GetSpellData()->savagery_upkeep = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "dissonance_req", [](Spell* spell, const std::string& val) { spell->GetSpellData()->dissonance_req = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "dissonance_upkeep", [](Spell* spell, const std::string& val) { spell->GetSpellData()->dissonance_upkeep = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "target_type", [](Spell* spell, const std::string& val) { spell->GetSpellData()->target_type = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "cast_time", [](Spell* spell, const std::string& val) { spell->GetSpellData()->cast_time = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "recovery", [](Spell* spell, const std::string& val) { spell->GetSpellData()->recovery = std::stof(val); } },
|
||||||
|
{ "recast", [](Spell* spell, const std::string& val) { spell->GetSpellData()->recast = std::stof(val); } },
|
||||||
|
{ "linked_timer", [](Spell* spell, const std::string& val) { spell->GetSpellData()->linked_timer = static_cast<int32>(std::stoi(val)); } },
|
||||||
|
{ "radius", [](Spell* spell, const std::string& val) { spell->GetSpellData()->radius = std::stof(val); } },
|
||||||
|
{ "max_aoe_targets", [](Spell* spell, const std::string& val) { spell->GetSpellData()->max_aoe_targets = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "friendly_spell", [](Spell* spell, const std::string& val) { spell->GetSpellData()->friendly_spell = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "req_concentration", [](Spell* spell, const std::string& val) { spell->GetSpellData()->req_concentration = static_cast<int16>(std::stoi(val)); } },
|
||||||
|
{ "range", [](Spell* spell, const std::string& val) { spell->GetSpellData()->range = std::stof(val); } },
|
||||||
|
{ "duration1", [](Spell* spell, const std::string& val) { spell->GetSpellData()->duration1 = static_cast<sint32>(std::stoi(val)); } },
|
||||||
|
{ "duration2", [](Spell* spell, const std::string& val) { spell->GetSpellData()->duration2 = static_cast<sint32>(std::stoi(val)); } },
|
||||||
|
{ "resistibility", [](Spell* spell, const std::string& val) { spell->GetSpellData()->resistibility = std::stof(val); } },
|
||||||
|
{ "duration_until_cancel", [](Spell* spell, const std::string& val) { spell->GetSpellData()->duration_until_cancel = (val == "1" || val == "true"); } },
|
||||||
|
{ "power_req_percent", [](Spell* spell, const std::string& val) { spell->GetSpellData()->power_req_percent = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "hp_req_percent", [](Spell* spell, const std::string& val) { spell->GetSpellData()->hp_req_percent = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "savagery_req_percent", [](Spell* spell, const std::string& val) { spell->GetSpellData()->savagery_req_percent = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "dissonance_req_percent", [](Spell* spell, const std::string& val) { spell->GetSpellData()->dissonance_req_percent = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "name", [](Spell* spell, const std::string& val) { spell->GetSpellData()->name.data = val; } },
|
||||||
|
{ "description", [](Spell* spell, const std::string& val) { spell->GetSpellData()->description.data = val; } },
|
||||||
|
{ "success_message", [](Spell* spell, const std::string& val) { spell->GetSpellData()->success_message = val; } },
|
||||||
|
{ "fade_message", [](Spell* spell, const std::string& val) { spell->GetSpellData()->fade_message = val; } },
|
||||||
|
{ "fade_message_others", [](Spell* spell, const std::string& val) { spell->GetSpellData()->fade_message_others = val; } },
|
||||||
|
{ "cast_type", [](Spell* spell, const std::string& val) { spell->GetSpellData()->cast_type = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "call_frequency", [](Spell* spell, const std::string& val) { spell->GetSpellData()->call_frequency = static_cast<int32>(std::stoi(val)); } },
|
||||||
|
{ "interruptable", [](Spell* spell, const std::string& val) { spell->GetSpellData()->interruptable = (val == "1" || val == "true"); } },
|
||||||
|
{ "spell_visual", [](Spell* spell, const std::string& val) { spell->GetSpellData()->spell_visual = static_cast<int32>(std::stoi(val)); } },
|
||||||
|
{ "effect_message", [](Spell* spell, const std::string& val) { spell->GetSpellData()->effect_message = val; } },
|
||||||
|
{ "min_range", [](Spell* spell, const std::string& val) { spell->GetSpellData()->min_range = std::stof(val); } },
|
||||||
|
{ "can_effect_raid", [](Spell* spell, const std::string& val) { spell->GetSpellData()->can_effect_raid = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "affect_only_group_members", [](Spell* spell, const std::string& val) { spell->GetSpellData()->affect_only_group_members = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "group_spell", [](Spell* spell, const std::string& val) { spell->GetSpellData()->group_spell = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "hit_bonus", [](Spell* spell, const std::string& val) { spell->GetSpellData()->hit_bonus = std::stof(val); } },
|
||||||
|
{ "display_spell_tier", [](Spell* spell, const std::string& val) { spell->GetSpellData()->display_spell_tier = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "is_active", [](Spell* spell, const std::string& val) { spell->GetSpellData()->is_active = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "det_type", [](Spell* spell, const std::string& val) { spell->GetSpellData()->det_type = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "incurable", [](Spell* spell, const std::string& val) { spell->GetSpellData()->incurable = (val == "1" || val == "true"); } },
|
||||||
|
{ "control_effect_type", [](Spell* spell, const std::string& val) { spell->GetSpellData()->control_effect_type = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "casting_flags", [](Spell* spell, const std::string& val) { spell->GetSpellData()->casting_flags = static_cast<int32>(std::stoi(val)); } },
|
||||||
|
{ "cast_while_moving", [](Spell* spell, const std::string& val) { spell->GetSpellData()->cast_while_moving = (val == "1" || val == "true"); } },
|
||||||
|
{ "persist_through_death", [](Spell* spell, const std::string& val) { spell->GetSpellData()->persist_through_death = (val == "1" || val == "true"); } },
|
||||||
|
{ "not_maintained", [](Spell* spell, const std::string& val) { spell->GetSpellData()->not_maintained = (val == "1" || val == "true"); } },
|
||||||
|
{ "is_aa", [](Spell* spell, const std::string& val) { spell->GetSpellData()->is_aa = (val == "1" || val == "true"); } },
|
||||||
|
{ "savage_bar", [](Spell* spell, const std::string& val) { spell->GetSpellData()->savage_bar = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "spell_type", [](Spell* spell, const std::string& val) { spell->GetSpellData()->spell_type = static_cast<int8>(std::stoi(val)); } },
|
||||||
|
{ "type_group_spell_id", [](Spell* spell, const std::string& val) { spell->GetSpellData()->type_group_spell_id = static_cast<sint32>(std::stoi(val)); } },
|
||||||
|
{ "can_fizzle", [](Spell* spell, const std::string& val) { spell->GetSpellData()->can_fizzle = (val == "1" || val == "true"); } },
|
||||||
|
};
|
||||||
|
|
||||||
LuaInterface::LuaInterface() {
|
LuaInterface::LuaInterface() {
|
||||||
shutting_down = false;
|
shutting_down = false;
|
||||||
lua_system_reloading = false;
|
lua_system_reloading = false;
|
||||||
@ -3066,4 +3209,41 @@ LUASpellWrapper::LUASpellWrapper() {
|
|||||||
|
|
||||||
bool LUASpellWrapper::IsSpell() {
|
bool LUASpellWrapper::IsSpell() {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LuaSpell::SetSpellDataIndex(int idx, const std::string& value, const std::string& value2) {
|
||||||
|
if (!spell || spell->lua_data.size() <= idx)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LUAData* data = spell->lua_data[idx];
|
||||||
|
if (!data)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool setVal = true;
|
||||||
|
|
||||||
|
switch (data->type) {
|
||||||
|
case 0: // int + int
|
||||||
|
data->int_value = std::stoi(value);
|
||||||
|
data->int_value2 = std::stoi(value2);
|
||||||
|
break;
|
||||||
|
case 1: // float + float
|
||||||
|
data->float_value = std::stof(value);
|
||||||
|
data->float_value2 = std::stof(value2);
|
||||||
|
break;
|
||||||
|
case 2: // bool
|
||||||
|
data->bool_value = (value == "1" || value == "true");
|
||||||
|
break;
|
||||||
|
case 3: // string + string
|
||||||
|
data->string_value = value;
|
||||||
|
data->string_value2 = value2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setVal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setVal)
|
||||||
|
data->needs_db_save = true;
|
||||||
|
|
||||||
|
return setVal;
|
||||||
}
|
}
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "Spawn.h"
|
#include "Spawn.h"
|
||||||
#include "Spells.h"
|
#include "Spells.h"
|
||||||
@ -73,6 +74,18 @@ struct OptionWindowOption {
|
|||||||
#define EFFECT_FLAG_FEAR_IMMUNE 2097152
|
#define EFFECT_FLAG_FEAR_IMMUNE 2097152
|
||||||
#define EFFECT_FLAG_SAFEFALL 4194304
|
#define EFFECT_FLAG_SAFEFALL 4194304
|
||||||
|
|
||||||
|
enum class SpellFieldType {
|
||||||
|
Integer,
|
||||||
|
Float,
|
||||||
|
Boolean,
|
||||||
|
String
|
||||||
|
};
|
||||||
|
|
||||||
|
using SpellFieldGetter = std::function<std::string(SpellData*)>;
|
||||||
|
extern const std::unordered_map<std::string, std::function<void(Spell*, const std::string&)>> SpellFieldGenericSetters;
|
||||||
|
extern const std::unordered_map<std::string, std::pair<SpellFieldType, SpellFieldGetter>> SpellDataFieldAccessors;
|
||||||
|
extern std::unordered_map<std::string, std::function<void(Spell*, const std::string&)>> SpellDataFieldSetters;
|
||||||
|
|
||||||
struct LuaSpell{
|
struct LuaSpell{
|
||||||
Entity* caster;
|
Entity* caster;
|
||||||
int32 initial_caster_char_id;
|
int32 initial_caster_char_id;
|
||||||
@ -108,6 +121,9 @@ struct LuaSpell{
|
|||||||
ZoneServer* zone;
|
ZoneServer* zone;
|
||||||
int16 initial_caster_level;
|
int16 initial_caster_level;
|
||||||
|
|
||||||
|
std::unordered_set<std::string> modified_fields;
|
||||||
|
mutable std::shared_mutex spell_modify_mutex;
|
||||||
|
|
||||||
void AddTarget(int32 target_id) {
|
void AddTarget(int32 target_id) {
|
||||||
std::unique_lock lock(targets_mutex);
|
std::unique_lock lock(targets_mutex);
|
||||||
targets.push_back(target_id);
|
targets.push_back(target_id);
|
||||||
@ -212,6 +228,63 @@ struct LuaSpell{
|
|||||||
char_id_targets.clear();
|
char_id_targets.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkFieldModified(const std::string& field) {
|
||||||
|
std::unique_lock lock(spell_modify_mutex);
|
||||||
|
modified_fields.insert(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsFieldModified(const std::string& field) const {
|
||||||
|
std::shared_lock lock(spell_modify_mutex);
|
||||||
|
return modified_fields.find(field) != modified_fields.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearFieldModifications() {
|
||||||
|
std::unique_lock lock(spell_modify_mutex);
|
||||||
|
modified_fields.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<std::string> GetModifiedFieldsCopy() const {
|
||||||
|
std::shared_lock lock(spell_modify_mutex);
|
||||||
|
return modified_fields; // safe shallow copy
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetSpellDataGeneric(const std::string& field, int value) {
|
||||||
|
return SetSpellDataGeneric(field, std::to_string(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetSpellDataGeneric(const std::string& field, float value) {
|
||||||
|
return SetSpellDataGeneric(field, std::to_string(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetSpellDataGeneric(const std::string& field, bool value) {
|
||||||
|
return SetSpellDataGeneric(field, value ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetSpellDataGeneric(const std::string& field, const std::string& value) {
|
||||||
|
auto it = SpellFieldGenericSetters.find(field);
|
||||||
|
if (it == SpellFieldGenericSetters.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!spell)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
it->second(spell, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetSpellDataIndex(int idx, const std::string& value, const std::string& value2 = "");
|
||||||
|
|
||||||
|
bool SetSpellDataIndex(int idx, int value, int value2) {
|
||||||
|
return SetSpellDataIndex(idx, std::to_string(value), std::to_string(value2));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetSpellDataIndex(int idx, float value, float value2) {
|
||||||
|
return SetSpellDataIndex(idx, std::to_string(value), std::to_string(value2));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetSpellDataIndex(int idx, bool value) {
|
||||||
|
return SetSpellDataIndex(idx, value ? "1" : "0");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LuaArgType { SINT64, INT64, SINT, INT, FLOAT, STRING, BOOL, SPAWN, ZONE, SKILL, ITEM, QUEST, SPELL /* etc */ };
|
enum class LuaArgType { SINT64, INT64, SINT, INT, FLOAT, STRING, BOOL, SPAWN, ZONE, SKILL, ITEM, QUEST, SPELL /* etc */ };
|
||||||
|
@ -3284,10 +3284,12 @@ PlayerInfo::PlayerInfo(Player* in_player){
|
|||||||
for(int i=0;i<45;i++){
|
for(int i=0;i<45;i++){
|
||||||
if(i<30){
|
if(i<30){
|
||||||
info_struct->maintained_effects[i].spell_id = 0xFFFFFFFF;
|
info_struct->maintained_effects[i].spell_id = 0xFFFFFFFF;
|
||||||
|
info_struct->maintained_effects[i].inherited_spell_id = 0;
|
||||||
info_struct->maintained_effects[i].icon = 0xFFFF;
|
info_struct->maintained_effects[i].icon = 0xFFFF;
|
||||||
info_struct->maintained_effects[i].spell = nullptr;
|
info_struct->maintained_effects[i].spell = nullptr;
|
||||||
}
|
}
|
||||||
info_struct->spell_effects[i].spell_id = 0xFFFFFFFF;
|
info_struct->spell_effects[i].spell_id = 0xFFFFFFFF;
|
||||||
|
info_struct->spell_effects[i].inherited_spell_id = 0;
|
||||||
info_struct->spell_effects[i].icon = 0;
|
info_struct->spell_effects[i].icon = 0;
|
||||||
info_struct->spell_effects[i].icon_backdrop = 0;
|
info_struct->spell_effects[i].icon_backdrop = 0;
|
||||||
info_struct->spell_effects[i].tier = 0;
|
info_struct->spell_effects[i].tier = 0;
|
||||||
@ -3324,12 +3326,12 @@ MaintainedEffects* Player::GetFreeMaintainedSpellSlot(){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaintainedEffects* Player::GetMaintainedSpell(int32 id){
|
MaintainedEffects* Player::GetMaintainedSpell(int32 id, bool on_char_load){
|
||||||
MaintainedEffects* ret = 0;
|
MaintainedEffects* ret = 0;
|
||||||
InfoStruct* info = GetInfoStruct();
|
InfoStruct* info = GetInfoStruct();
|
||||||
GetMaintainedMutex()->readlock(__FUNCTION__, __LINE__);
|
GetMaintainedMutex()->readlock(__FUNCTION__, __LINE__);
|
||||||
for(int i=0;i<NUM_MAINTAINED_EFFECTS;i++){
|
for(int i=0;i<NUM_MAINTAINED_EFFECTS;i++){
|
||||||
if(info->maintained_effects[i].spell_id == id){
|
if(info->maintained_effects[i].spell_id == id || (on_char_load && info->maintained_effects[i].inherited_spell_id == id)){
|
||||||
ret = &info->maintained_effects[i];
|
ret = &info->maintained_effects[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3560,6 +3562,7 @@ void Player::RemoveMaintainedSpell(LuaSpell* luaspell){
|
|||||||
if (found) {
|
if (found) {
|
||||||
memset(&GetInfoStruct()->maintained_effects[29], 0, sizeof(MaintainedEffects));
|
memset(&GetInfoStruct()->maintained_effects[29], 0, sizeof(MaintainedEffects));
|
||||||
GetInfoStruct()->maintained_effects[29].spell_id = 0xFFFFFFFF;
|
GetInfoStruct()->maintained_effects[29].spell_id = 0xFFFFFFFF;
|
||||||
|
GetInfoStruct()->maintained_effects[29].inherited_spell_id = 0;
|
||||||
GetInfoStruct()->maintained_effects[29].icon = 0xFFFF;
|
GetInfoStruct()->maintained_effects[29].icon = 0xFFFF;
|
||||||
GetInfoStruct()->maintained_effects[29].spell = nullptr;
|
GetInfoStruct()->maintained_effects[29].spell = nullptr;
|
||||||
charsheet_changed = true;
|
charsheet_changed = true;
|
||||||
@ -3580,6 +3583,7 @@ void Player::RemoveSpellEffect(LuaSpell* spell){
|
|||||||
if (found) {
|
if (found) {
|
||||||
memset(&GetInfoStruct()->spell_effects[44], 0, sizeof(SpellEffects));
|
memset(&GetInfoStruct()->spell_effects[44], 0, sizeof(SpellEffects));
|
||||||
GetInfoStruct()->spell_effects[44].spell_id = 0xFFFFFFFF;
|
GetInfoStruct()->spell_effects[44].spell_id = 0xFFFFFFFF;
|
||||||
|
GetInfoStruct()->spell_effects[44].inherited_spell_id = 0;
|
||||||
GetInfoStruct()->spell_effects[44].spell = nullptr;
|
GetInfoStruct()->spell_effects[44].spell = nullptr;
|
||||||
changed = true;
|
changed = true;
|
||||||
info_changed = true;
|
info_changed = true;
|
||||||
@ -7331,6 +7335,110 @@ NPC* Player::InstantiateSpiritShard(float origX, float origY, float origZ, float
|
|||||||
return npc;
|
return npc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::SaveCustomSpellFields(LuaSpell* luaspell) {
|
||||||
|
if (!luaspell || !luaspell->spell || !luaspell->spell->IsCopiedSpell())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto spell_data = luaspell->spell->GetSpellData();
|
||||||
|
std::unordered_set<std::string> modified_fields = luaspell->GetModifiedFieldsCopy();
|
||||||
|
|
||||||
|
Query savedEffects;
|
||||||
|
for (const std::string& field : modified_fields) {
|
||||||
|
auto it = SpellDataFieldAccessors.find(field);
|
||||||
|
if (it == SpellDataFieldAccessors.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto& [type, getter] = it->second;
|
||||||
|
std::string value = getter(spell_data);
|
||||||
|
|
||||||
|
std::string type_str;
|
||||||
|
switch (type) {
|
||||||
|
case SpellFieldType::Integer: type_str = "int"; break;
|
||||||
|
case SpellFieldType::Float: type_str = "float"; break;
|
||||||
|
case SpellFieldType::Boolean: type_str = "bool"; break;
|
||||||
|
case SpellFieldType::String: type_str = "string"; break;
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_data (charid, spell_id, field, type, value) VALUES (%u, %u, '%s', '%s', '%s')",
|
||||||
|
GetCharacterID(),
|
||||||
|
luaspell->spell->GetSpellData()->inherited_spell_id,
|
||||||
|
database.getSafeEscapeString(field.c_str()).c_str(),
|
||||||
|
type_str.c_str(),
|
||||||
|
database.getSafeEscapeString(value.c_str()).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Player::SaveCustomSpellDataIndex(LuaSpell* luaspell) {
|
||||||
|
if (!luaspell || !luaspell->spell || !luaspell->spell->IsCopiedSpell())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& vec = luaspell->spell->lua_data;
|
||||||
|
|
||||||
|
Query savedEffects;
|
||||||
|
for (int i = 0; i < vec.size(); ++i) {
|
||||||
|
LUAData* data = vec[i];
|
||||||
|
if (!data || !data->needs_db_save)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string value1, value2, type;
|
||||||
|
switch (data->type) {
|
||||||
|
case 0:
|
||||||
|
value1 = std::to_string(data->int_value);
|
||||||
|
value2 = std::to_string(data->int_value2);
|
||||||
|
type = "int";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
value1 = std::to_string(data->float_value);
|
||||||
|
value2 = std::to_string(data->float_value2);
|
||||||
|
type = "float";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value1 = data->bool_value ? "1" : "0";
|
||||||
|
type = "bool";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
value1 = database.getSafeEscapeString(data->string_value.c_str());
|
||||||
|
value2 = database.getSafeEscapeString(data->string_value2.c_str());
|
||||||
|
type = "string";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_dataindex (charid, spell_id, idx, type, value1, value2) VALUES (%u, %u, %d, '%s', '%s', '%s')", GetCharacterID(),
|
||||||
|
luaspell->spell->GetSpellData()->inherited_spell_id,
|
||||||
|
i,
|
||||||
|
type.c_str(), value1.c_str(), value2.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::SaveCustomSpellEffectsDisplay(LuaSpell* luaspell) {
|
||||||
|
if (!luaspell || !luaspell->spell || !luaspell->spell->IsCopiedSpell())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& vec = luaspell->spell->effects;
|
||||||
|
|
||||||
|
Query savedEffects;
|
||||||
|
for (int i = 0; i < vec.size(); ++i) {
|
||||||
|
SpellDisplayEffect* eff = vec[i];
|
||||||
|
if (!eff || !eff->needs_db_save)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string charid = std::to_string(GetCharacterID());
|
||||||
|
|
||||||
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'description', '%s')",
|
||||||
|
GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i,
|
||||||
|
database.getSafeEscapeString(eff->description.c_str()).c_str());
|
||||||
|
|
||||||
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'bullet', '%d')",
|
||||||
|
GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i, eff->subbullet);
|
||||||
|
|
||||||
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'percentage', '%d')",
|
||||||
|
GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i, eff->percentage);
|
||||||
|
}
|
||||||
|
}
|
||||||
void Player::SaveSpellEffects()
|
void Player::SaveSpellEffects()
|
||||||
{
|
{
|
||||||
if(stop_save_spell_effects)
|
if(stop_save_spell_effects)
|
||||||
@ -7346,6 +7454,9 @@ void Player::SaveSpellEffects()
|
|||||||
Query savedEffects;
|
Query savedEffects;
|
||||||
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_DELETE, "delete from character_spell_effects where charid=%u", GetCharacterID());
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_DELETE, "delete from character_spell_effects where charid=%u", GetCharacterID());
|
||||||
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_DELETE, "delete from character_spell_effect_targets where caster_char_id=%u", GetCharacterID());
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_DELETE, "delete from character_spell_effect_targets where caster_char_id=%u", GetCharacterID());
|
||||||
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_DELETE, "delete from character_custom_spell_dataindex where charid=%u", GetCharacterID());
|
||||||
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_DELETE, "delete from character_custom_spell_display where charid=%u", GetCharacterID());
|
||||||
|
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_DELETE, "delete from character_custom_spell_data where charid=%u", GetCharacterID());
|
||||||
InfoStruct* info = GetInfoStruct();
|
InfoStruct* info = GetInfoStruct();
|
||||||
MSpellEffects.readlock(__FUNCTION__, __LINE__);
|
MSpellEffects.readlock(__FUNCTION__, __LINE__);
|
||||||
MMaintainedSpells.readlock(__FUNCTION__, __LINE__);
|
MMaintainedSpells.readlock(__FUNCTION__, __LINE__);
|
||||||
@ -7376,6 +7487,10 @@ 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].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->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->spell_effects[i].spell->has_damaged, (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->initial_caster_level);
|
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->spell_effects[i].spell->has_damaged, (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->initial_caster_level);
|
||||||
|
|
||||||
|
SaveCustomSpellFields(info->spell_effects[i].spell);
|
||||||
|
SaveCustomSpellDataIndex(info->spell_effects[i].spell);
|
||||||
|
SaveCustomSpellEffectsDisplay(info->spell_effects[i].spell);
|
||||||
}
|
}
|
||||||
if (i < NUM_MAINTAINED_EFFECTS && info->maintained_effects[i].spell_id != 0xFFFFFFFF){
|
if (i < NUM_MAINTAINED_EFFECTS && info->maintained_effects[i].spell_id != 0xFFFFFFFF){
|
||||||
Spawn* spawn = GetZone()->GetSpawnByID(info->maintained_effects[i].spell->initial_target);
|
Spawn* spawn = GetZone()->GetSpawnByID(info->maintained_effects[i].spell->initial_target);
|
||||||
@ -7404,6 +7519,10 @@ void Player::SaveSpellEffects()
|
|||||||
info->maintained_effects[i].spell->damage_remaining, info->maintained_effects[i].spell->effect_bitmask, info->maintained_effects[i].spell->num_triggers, info->maintained_effects[i].spell->had_triggers, info->maintained_effects[i].spell->cancel_after_all_triggers,
|
info->maintained_effects[i].spell->damage_remaining, info->maintained_effects[i].spell->effect_bitmask, info->maintained_effects[i].spell->num_triggers, info->maintained_effects[i].spell->had_triggers, info->maintained_effects[i].spell->cancel_after_all_triggers,
|
||||||
info->maintained_effects[i].spell->crit, info->maintained_effects[i].spell->last_spellattack_hit, info->maintained_effects[i].spell->interrupted, info->maintained_effects[i].spell->resisted, info->maintained_effects[i].spell->has_damaged, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->maintained_effects[i].spell).c_str()).c_str(), info->maintained_effects[i].spell->initial_caster_level);
|
info->maintained_effects[i].spell->crit, info->maintained_effects[i].spell->last_spellattack_hit, info->maintained_effects[i].spell->interrupted, info->maintained_effects[i].spell->resisted, info->maintained_effects[i].spell->has_damaged, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->maintained_effects[i].spell).c_str()).c_str(), info->maintained_effects[i].spell->initial_caster_level);
|
||||||
|
|
||||||
|
SaveCustomSpellFields(info->maintained_effects[i].spell);
|
||||||
|
SaveCustomSpellDataIndex(info->maintained_effects[i].spell);
|
||||||
|
SaveCustomSpellEffectsDisplay(info->maintained_effects[i].spell);
|
||||||
|
|
||||||
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 ");
|
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;
|
bool firstTarget = true;
|
||||||
map<Spawn*, int8> targetsInserted;
|
map<Spawn*, int8> targetsInserted;
|
||||||
|
@ -589,7 +589,7 @@ public:
|
|||||||
EQ2Packet* MoveInventoryItem(sint32 to_bag_id, int16 from_index, int8 new_slot, int8 charges, int8 appearance_type, bool* item_deleted, int16 version = 1);
|
EQ2Packet* MoveInventoryItem(sint32 to_bag_id, int16 from_index, int8 new_slot, int8 charges, int8 appearance_type, bool* item_deleted, int16 version = 1);
|
||||||
bool IsPlayer(){ return true; }
|
bool IsPlayer(){ return true; }
|
||||||
MaintainedEffects* GetFreeMaintainedSpellSlot();
|
MaintainedEffects* GetFreeMaintainedSpellSlot();
|
||||||
MaintainedEffects* GetMaintainedSpell(int32 id);
|
MaintainedEffects* GetMaintainedSpell(int32 id, bool on_char_load = false);
|
||||||
MaintainedEffects* GetMaintainedSpellBySlot(int8 slot);
|
MaintainedEffects* GetMaintainedSpellBySlot(int8 slot);
|
||||||
MaintainedEffects* GetMaintainedSpells();
|
MaintainedEffects* GetMaintainedSpells();
|
||||||
SpellEffects* GetFreeSpellEffectSlot();
|
SpellEffects* GetFreeSpellEffectSlot();
|
||||||
@ -1050,7 +1050,10 @@ public:
|
|||||||
void DismissAllPets();
|
void DismissAllPets();
|
||||||
|
|
||||||
void SaveSpellEffects();
|
void SaveSpellEffects();
|
||||||
|
void SaveCustomSpellFields(LuaSpell* luaspell);
|
||||||
|
void SaveCustomSpellDataIndex(LuaSpell* luaspell);
|
||||||
|
void SaveCustomSpellEffectsDisplay(LuaSpell* luaspell);
|
||||||
|
|
||||||
void SetSaveSpellEffects(bool val) { stop_save_spell_effects = val; }
|
void SetSaveSpellEffects(bool val) { stop_save_spell_effects = val; }
|
||||||
AppearanceData SavedApp;
|
AppearanceData SavedApp;
|
||||||
CharFeatures SavedFeatures;
|
CharFeatures SavedFeatures;
|
||||||
|
@ -222,7 +222,7 @@ void Spell::AddSpellLuaData(int8 type, int int_value, int int_value2, float floa
|
|||||||
data->string_value = string_value;
|
data->string_value = string_value;
|
||||||
data->string_value2 = string_value2;
|
data->string_value2 = string_value2;
|
||||||
data->string_helper = helper;
|
data->string_helper = helper;
|
||||||
|
data->needs_db_save = false;
|
||||||
lua_data.push_back(data);
|
lua_data.push_back(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +237,7 @@ void Spell::AddSpellLuaDataInt(int value, int value2, string helper) {
|
|||||||
data->float_value2 = 0;
|
data->float_value2 = 0;
|
||||||
data->bool_value = false;
|
data->bool_value = false;
|
||||||
data->string_helper = helper;
|
data->string_helper = helper;
|
||||||
|
data->needs_db_save = false;
|
||||||
|
|
||||||
lua_data.push_back(data);
|
lua_data.push_back(data);
|
||||||
}
|
}
|
||||||
@ -252,6 +253,7 @@ void Spell::AddSpellLuaDataFloat(float value, float value2, string helper) {
|
|||||||
data->float_value2 = value2;
|
data->float_value2 = value2;
|
||||||
data->bool_value = false;
|
data->bool_value = false;
|
||||||
data->string_helper = helper;
|
data->string_helper = helper;
|
||||||
|
data->needs_db_save = false;
|
||||||
|
|
||||||
lua_data.push_back(data);
|
lua_data.push_back(data);
|
||||||
}
|
}
|
||||||
@ -265,6 +267,7 @@ void Spell::AddSpellLuaDataBool(bool value, string helper) {
|
|||||||
data->float_value = 0;
|
data->float_value = 0;
|
||||||
data->bool_value = value;
|
data->bool_value = value;
|
||||||
data->string_helper = helper;
|
data->string_helper = helper;
|
||||||
|
data->needs_db_save = false;
|
||||||
|
|
||||||
lua_data.push_back(data);
|
lua_data.push_back(data);
|
||||||
}
|
}
|
||||||
@ -282,6 +285,7 @@ void Spell::AddSpellLuaDataString(string value, string value2,string helper) {
|
|||||||
data->string_value = value;
|
data->string_value = value;
|
||||||
data->string_value2 = value2;
|
data->string_value2 = value2;
|
||||||
data->string_helper = helper;
|
data->string_helper = helper;
|
||||||
|
data->needs_db_save = false;
|
||||||
|
|
||||||
lua_data.push_back(data);
|
lua_data.push_back(data);
|
||||||
}
|
}
|
||||||
@ -1154,6 +1158,7 @@ void Spell::AddSpellEffect(int8 percentage, int8 subbullet, string description){
|
|||||||
effect->description = description;
|
effect->description = description;
|
||||||
effect->subbullet = subbullet;
|
effect->subbullet = subbullet;
|
||||||
effect->percentage = percentage;
|
effect->percentage = percentage;
|
||||||
|
effect->needs_db_save = false;
|
||||||
|
|
||||||
effects.push_back(effect);
|
effects.push_back(effect);
|
||||||
}
|
}
|
||||||
|
@ -205,6 +205,7 @@ struct LUAData{
|
|||||||
sint32 int_value2;
|
sint32 int_value2;
|
||||||
float float_value2;
|
float float_value2;
|
||||||
string string_helper;
|
string string_helper;
|
||||||
|
bool needs_db_save;
|
||||||
};
|
};
|
||||||
struct SpellScriptTimer {
|
struct SpellScriptTimer {
|
||||||
LuaSpell* spell;
|
LuaSpell* spell;
|
||||||
@ -224,6 +225,7 @@ struct SpellDisplayEffect{
|
|||||||
int8 percentage;
|
int8 percentage;
|
||||||
int8 subbullet;
|
int8 subbullet;
|
||||||
string description;
|
string description;
|
||||||
|
bool needs_db_save;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GivenByType {
|
enum GivenByType {
|
||||||
@ -352,6 +354,12 @@ public:
|
|||||||
int16 GetSavageryRequired(Spawn* spawn);
|
int16 GetSavageryRequired(Spawn* spawn);
|
||||||
int16 GetDissonanceRequired(Spawn* spawn);
|
int16 GetDissonanceRequired(Spawn* spawn);
|
||||||
SpellData* GetSpellData();
|
SpellData* GetSpellData();
|
||||||
|
SpellDisplayEffect* GetSpellDisplayEffectSafe(int index) const {
|
||||||
|
if (index < 0 || index >= effects.size())
|
||||||
|
return nullptr;
|
||||||
|
return effects[index];
|
||||||
|
}
|
||||||
|
|
||||||
bool GetSpellData(lua_State* state, std::string field);
|
bool GetSpellData(lua_State* state, std::string field);
|
||||||
bool SetSpellData(lua_State* state, std::string field, int8 fieldArg);
|
bool SetSpellData(lua_State* state, std::string field, int8 fieldArg);
|
||||||
bool ScribeAllowed(Player* player);
|
bool ScribeAllowed(Player* player);
|
||||||
|
@ -5283,6 +5283,11 @@ bool WorldDatabase::DeleteCharacter(int32 account_id, int32 character_id){
|
|||||||
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from character_titles where char_id = %u", character_id);
|
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from character_titles where char_id = %u", character_id);
|
||||||
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from char_colors where char_id = %u", character_id);
|
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from char_colors where char_id = %u", character_id);
|
||||||
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from statistics where char_id = %u", character_id);
|
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from statistics where char_id = %u", character_id);
|
||||||
|
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from character_spell_effects where charid=%u", character_id);
|
||||||
|
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from character_spell_effect_targets where caster_char_id=%u", character_id);
|
||||||
|
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from character_custom_spell_dataindex where charid=%u", character_id);
|
||||||
|
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from character_custom_spell_display where charid=%u", character_id);
|
||||||
|
query.AddQueryAsync(character_id, this, Q_DELETE, "delete from character_custom_spell_data where charid=%u", character_id);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -7970,6 +7975,94 @@ int32 WorldDatabase::CreateSpiritShard(const char* name, int32 level, int8 race,
|
|||||||
return query.GetLastInsertedID();
|
return query.GetLastInsertedID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldDatabase::LoadCustomSpellData(Client* client, LuaSpell* luaspell) {
|
||||||
|
if (!luaspell || !luaspell->spell || !luaspell->spell->GetSpellData() || !luaspell->spell->IsCopiedSpell())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto spell_data = luaspell->spell->GetSpellData();
|
||||||
|
|
||||||
|
DatabaseResult result;
|
||||||
|
if (!database_new.Select(&result, "SELECT field, type, value FROM character_custom_spell_data WHERE charid = %u AND spell_id = %u",
|
||||||
|
client->GetPlayer()->GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (result.Next()) {
|
||||||
|
std::string field = result.GetStringStr("field");
|
||||||
|
std::string type = result.GetStringStr("type");
|
||||||
|
std::string value = result.GetStringStr("value");
|
||||||
|
|
||||||
|
if (type == "int")
|
||||||
|
luaspell->SetSpellDataGeneric(field, atoi(value.c_str()));
|
||||||
|
else if (type == "float")
|
||||||
|
luaspell->SetSpellDataGeneric(field, static_cast<float>(atof(value.c_str())));
|
||||||
|
else if (type == "bool")
|
||||||
|
luaspell->SetSpellDataGeneric(field, value == "1");
|
||||||
|
else if (type == "string")
|
||||||
|
luaspell->SetSpellDataGeneric(field, value);
|
||||||
|
|
||||||
|
luaspell->MarkFieldModified(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldDatabase::LoadCustomSpellDataIndex(Client* client, LuaSpell* luaspell) {
|
||||||
|
if (!luaspell || !luaspell->spell || !luaspell->spell->GetSpellData() || !luaspell->spell->IsCopiedSpell())
|
||||||
|
return;
|
||||||
|
|
||||||
|
DatabaseResult result;
|
||||||
|
if (!database_new.Select(&result, "SELECT idx, type, value1, value2 FROM character_custom_spell_dataindex WHERE charid = %u AND spell_id = %u",
|
||||||
|
client->GetPlayer()->GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (result.Next()) {
|
||||||
|
int idx = result.GetInt32Str("idx");
|
||||||
|
std::string type = result.GetStringStr("type");
|
||||||
|
std::string v1 = result.GetStringStr("value1");
|
||||||
|
std::string v2 = result.GetStringStr("value2");
|
||||||
|
|
||||||
|
if (type == "int")
|
||||||
|
luaspell->SetSpellDataIndex(idx, atoi(v1.c_str()), atoi(v2.c_str()));
|
||||||
|
else if (type == "float")
|
||||||
|
luaspell->SetSpellDataIndex(idx, static_cast<float>(atof(v1.c_str())), static_cast<float>(atof(v2.c_str())));
|
||||||
|
else if (type == "bool")
|
||||||
|
luaspell->SetSpellDataIndex(idx, v1 == "1");
|
||||||
|
else if (type == "string")
|
||||||
|
luaspell->SetSpellDataIndex(idx, v1, v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldDatabase::LoadCustomSpellDisplayEffects(Client* client, LuaSpell* luaspell) {
|
||||||
|
if (!luaspell || !luaspell->spell || !luaspell->spell->GetSpellData() || !luaspell->spell->IsCopiedSpell())
|
||||||
|
return;
|
||||||
|
|
||||||
|
DatabaseResult result;
|
||||||
|
if (!database_new.Select(&result, "SELECT idx, field, value FROM character_custom_spell_display WHERE charid = %u AND spell_id = %u",
|
||||||
|
client->GetPlayer()->GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (result.Next()) {
|
||||||
|
int idx = result.GetInt32Str("idx");
|
||||||
|
std::string field = result.GetStringStr("field");
|
||||||
|
std::string value = result.GetStringStr("value");
|
||||||
|
|
||||||
|
SpellDisplayEffect* effect = luaspell->spell->GetSpellDisplayEffectSafe(idx);
|
||||||
|
if (!effect)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (field == "description") {
|
||||||
|
effect->description = value;
|
||||||
|
effect->needs_db_save = true;
|
||||||
|
}
|
||||||
|
else if (field == "bullet") {
|
||||||
|
effect->subbullet = atoi(value.c_str());
|
||||||
|
effect->needs_db_save = true;
|
||||||
|
}
|
||||||
|
else if (field == "percentage") {
|
||||||
|
effect->percentage = atoi(value.c_str());
|
||||||
|
effect->needs_db_save = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int8 db_spell_type)
|
void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int8 db_spell_type)
|
||||||
{
|
{
|
||||||
SpellProcess* spellProcess = client->GetCurrentZone()->GetSpellProcess();
|
SpellProcess* spellProcess = client->GetCurrentZone()->GetSpellProcess();
|
||||||
@ -8049,7 +8142,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||||||
bool isExistingLuaSpell = false;
|
bool isExistingLuaSpell = false;
|
||||||
MaintainedEffects* effect = nullptr;
|
MaintainedEffects* effect = nullptr;
|
||||||
Client* tmpCaster = nullptr;
|
Client* tmpCaster = nullptr;
|
||||||
if(caster_char_id == player->GetCharacterID() && (target_char_id == 0xFFFFFFFF || 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, true)) != nullptr)
|
||||||
{
|
{
|
||||||
safe_delete(lua_spell);
|
safe_delete(lua_spell);
|
||||||
lua_spell = effect->spell;
|
lua_spell = effect->spell;
|
||||||
@ -8059,9 +8152,9 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||||||
isExistingLuaSpell = true;
|
isExistingLuaSpell = true;
|
||||||
}
|
}
|
||||||
else if ( caster_char_id != player->GetCharacterID() && (tmpCaster = zone_list.GetClientByCharID(caster_char_id)) != nullptr
|
else if ( caster_char_id != player->GetCharacterID() && (tmpCaster = zone_list.GetClientByCharID(caster_char_id)) != nullptr
|
||||||
&& tmpCaster->GetPlayer() && (effect = tmpCaster->GetPlayer()->GetMaintainedSpell(spell_id)) != nullptr)
|
&& tmpCaster->GetPlayer() && (effect = tmpCaster->GetPlayer()->GetMaintainedSpell(spell_id, true)) != nullptr)
|
||||||
{
|
{
|
||||||
if(effect->spell && effect->spell_id == spell_id)
|
if(effect->spell && (effect->spell_id == spell_id || effect->inherited_spell_id == spell_id))
|
||||||
{
|
{
|
||||||
safe_delete(lua_spell);
|
safe_delete(lua_spell);
|
||||||
if(tmpCaster->GetCurrentZone() == player->GetZone())
|
if(tmpCaster->GetCurrentZone() == player->GetZone())
|
||||||
@ -8155,6 +8248,10 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||||||
//lua_spell->num_calls ??
|
//lua_spell->num_calls ??
|
||||||
//if(target_char_id == player->GetCharacterID())
|
//if(target_char_id == player->GetCharacterID())
|
||||||
// lua_spell->targets.push_back(player->GetID());
|
// lua_spell->targets.push_back(player->GetID());
|
||||||
|
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCustomSpell: %s (%u) lua_spell caster %s (%u), caster char id: %u. IsCopiedSpell: %u", lua_spell->spell->GetName(), lua_spell->spell->GetSpellID(), lua_spell->caster ? lua_spell->caster->GetName() : "", lua_spell->caster ? lua_spell->caster->GetID() : 0, caster_char_id, lua_spell->spell->IsCopiedSpell());
|
||||||
|
LoadCustomSpellData(client, lua_spell);
|
||||||
|
LoadCustomSpellDataIndex(client, lua_spell);
|
||||||
|
LoadCustomSpellDisplayEffects(client, lua_spell);
|
||||||
|
|
||||||
if(db_spell_type == DB_TYPE_SPELLEFFECTS)
|
if(db_spell_type == DB_TYPE_SPELLEFFECTS)
|
||||||
{
|
{
|
||||||
@ -8212,7 +8309,8 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||||||
info->spell_effects[effect_slot].expire_timestamp = Timer::GetCurrentTime2() + expire_timestamp;
|
info->spell_effects[effect_slot].expire_timestamp = Timer::GetCurrentTime2() + expire_timestamp;
|
||||||
info->spell_effects[effect_slot].icon = icon;
|
info->spell_effects[effect_slot].icon = icon;
|
||||||
info->spell_effects[effect_slot].icon_backdrop = icon_backdrop;
|
info->spell_effects[effect_slot].icon_backdrop = icon_backdrop;
|
||||||
info->spell_effects[effect_slot].spell_id = spell_id;
|
info->spell_effects[effect_slot].spell_id = lua_spell->spell->GetSpellID();
|
||||||
|
info->spell_effects[effect_slot].inherited_spell_id = lua_spell->spell->GetSpellData()->inherited_spell_id;
|
||||||
info->spell_effects[effect_slot].tier = tier;
|
info->spell_effects[effect_slot].tier = tier;
|
||||||
info->spell_effects[effect_slot].total_time = total_time;
|
info->spell_effects[effect_slot].total_time = total_time;
|
||||||
info->spell_effects[effect_slot].spell = lua_spell;
|
info->spell_effects[effect_slot].spell = lua_spell;
|
||||||
@ -8315,7 +8413,8 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||||||
info->maintained_effects[effect_slot].expire_timestamp = Timer::GetCurrentTime2() + expire_timestamp;
|
info->maintained_effects[effect_slot].expire_timestamp = Timer::GetCurrentTime2() + expire_timestamp;
|
||||||
info->maintained_effects[effect_slot].icon = icon;
|
info->maintained_effects[effect_slot].icon = icon;
|
||||||
info->maintained_effects[effect_slot].icon_backdrop = icon_backdrop;
|
info->maintained_effects[effect_slot].icon_backdrop = icon_backdrop;
|
||||||
info->maintained_effects[effect_slot].spell_id = spell_id;
|
info->maintained_effects[effect_slot].spell_id = lua_spell->spell->GetSpellID();
|
||||||
|
info->maintained_effects[effect_slot].inherited_spell_id = lua_spell->spell->GetSpellData()->inherited_spell_id;
|
||||||
info->maintained_effects[effect_slot].tier = tier;
|
info->maintained_effects[effect_slot].tier = tier;
|
||||||
info->maintained_effects[effect_slot].total_time = total_time;
|
info->maintained_effects[effect_slot].total_time = total_time;
|
||||||
info->maintained_effects[effect_slot].spell = lua_spell;
|
info->maintained_effects[effect_slot].spell = lua_spell;
|
||||||
@ -8387,7 +8486,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||||||
Client* tmpCaster = nullptr;
|
Client* tmpCaster = nullptr;
|
||||||
MaintainedEffects* effect = nullptr;
|
MaintainedEffects* effect = nullptr;
|
||||||
if (caster_char_id != player->GetCharacterID() && (tmpCaster = zone_list.GetClientByCharID(caster_char_id)) != nullptr && (cross_zone_target_buff ||
|
if (caster_char_id != player->GetCharacterID() && (tmpCaster = zone_list.GetClientByCharID(caster_char_id)) != nullptr && (cross_zone_target_buff ||
|
||||||
tmpCaster->GetCurrentZone() == player->GetZone()) && tmpCaster->GetPlayer() && (effect = tmpCaster->GetPlayer()->GetMaintainedSpell(in_spell_id)) != nullptr)
|
tmpCaster->GetCurrentZone() == player->GetZone()) && tmpCaster->GetPlayer() && (effect = tmpCaster->GetPlayer()->GetMaintainedSpell(in_spell_id, true)) != nullptr)
|
||||||
{
|
{
|
||||||
if(prev_target_type > 0)
|
if(prev_target_type > 0)
|
||||||
{
|
{
|
||||||
@ -8399,7 +8498,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
|
|||||||
restoreSpells.insert(make_pair(effect->spell, player->GetCharmedPet()));
|
restoreSpells.insert(make_pair(effect->spell, player->GetCharmedPet()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(!player->GetSpellEffect(effect->spell_id, tmpCaster->GetPlayer()))
|
else if(!player->GetSpellEffect(effect->spell_id, tmpCaster->GetPlayer(), true))
|
||||||
{
|
{
|
||||||
if(effect->spell->initial_target_char_id == player->GetCharacterID())
|
if(effect->spell->initial_target_char_id == player->GetCharacterID())
|
||||||
effect->spell->initial_target = player->GetID();
|
effect->spell->initial_target = player->GetID();
|
||||||
|
@ -656,6 +656,9 @@ public:
|
|||||||
float x, float y, float z, float heading, int32 gridid, int32 charid, int32 zoneid, int32 instanceid);
|
float x, float y, float z, float heading, int32 gridid, int32 charid, int32 zoneid, int32 instanceid);
|
||||||
bool DeleteSpiritShard(int32 id);
|
bool DeleteSpiritShard(int32 id);
|
||||||
|
|
||||||
|
void LoadCustomSpellData(Client* client, LuaSpell* luaspell);
|
||||||
|
void LoadCustomSpellDataIndex(Client* client, LuaSpell* luaspell);
|
||||||
|
void LoadCustomSpellDisplayEffects(Client* client, LuaSpell* luaspell);
|
||||||
void LoadCharacterSpellEffects(int32 char_id, Client *client, int8 db_spell_type);
|
void LoadCharacterSpellEffects(int32 char_id, Client *client, int8 db_spell_type);
|
||||||
|
|
||||||
int32 GetMysqlExpCurve(int level);
|
int32 GetMysqlExpCurve(int level);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user