Broke fixes, 1h/2h equip fixes, swapping equip works, more crash fixes

Partial Address Issue  - tier 0 items display, 2h now display

Fix  - can't equip a 1h while 2h is equipped.  Swapping equipment slots now works for both combat/appearance equip.

Fix  - when scribing, new tier spell will display on hover over of spellbook or hotbar

Fixed a crash with spell conflict doing double delete on lua spell

Fix  - addressed divine awakening, via new target_type (10) SPELL_TARGET_ALLGROUPTARGETS - this will call cast for each player instead of just the direct target
righteousness and decree now supported as a group target AE

Better connection closure from client to world on camping/zoning out
This commit is contained in:
Image 2021-03-25 09:14:35 -04:00
parent a972bf9325
commit 4c9197f54e
15 changed files with 199 additions and 59 deletions

View file

@ -1773,7 +1773,11 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
player->item_list.RemoveItem(item, true);
client->QueuePacket(player->GetSpellBookUpdatePacket(client->GetVersion()));
client->QueuePacket(player->SendInventoryUpdate(client->GetVersion()));
}
// force purge client cache and display updated spell for hover over
EQ2Packet* app = spell->SerializeSpell(client, false, false);
client->QueuePacket(app);
}
}
else
LogWrite(COMMAND__ERROR, 0, "Command", "Unknown spell ID: %u and tier: %u", item->skill_info->spell_id, item->skill_info->spell_tier);
@ -3669,6 +3673,8 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
if(sep && sep->arg[0][0]){
const char* values = sep->argplus[0];
if(values){
LogWrite(ITEM__WARNING, 0, "Item", "SearchStores: %s", values);
map<string, string> str_values = TranslateBrokerRequest(values);
vector<Item*>* items = master_item_list.GetItems(str_values);
if(items){
@ -6177,7 +6183,11 @@ void Commands::Command_Inventory(Client* client, Seperator* sep, EQ2_RemoteComma
LogWrite(MISC__TODO, 1, "TODO", " fix this, need to get how live does it\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
int16 index1 = atoi(sep->arg[1]);
int16 index2 = atoi(sep->arg[2]);
EQ2Packet* outapp = client->GetPlayer()->SwapEquippedItems(index1, index2, client->GetVersion());
int8 type = 0;
if(sep->IsNumber(3))
type = atoul(sep->arg[3]); // type 0 is combat, 3 = appearance
EQ2Packet* outapp = client->GetPlayer()->SwapEquippedItems(index1, index2, client->GetVersion(), type);
if(outapp)
client->QueuePacket(outapp);

View file

@ -88,7 +88,7 @@ MasterItemList::~MasterItemList(){
RemoveAll();
}
vector<Item*>* MasterItemList::GetItems(string name, int32 itype, int32 ltype, int32 btype, int64 minprice, int64 maxprice, int8 minskill, int8 maxskill, string seller, string adornment, int8 mintier, int8 maxtier, int16 minlevel, int16 maxlevel, sint8 itemclass){
vector<Item*>* MasterItemList::GetItems(string name, int64 itype, int32 ltype, int32 btype, int64 minprice, int64 maxprice, int8 minskill, int8 maxskill, string seller, string adornment, int8 mintier, int8 maxtier, int16 minlevel, int16 maxlevel, sint8 itemclass){
vector<Item*>* ret = new vector<Item*>;
map<int32,Item*>::iterator iter;
Item* item = 0;
@ -101,11 +101,12 @@ vector<Item*>* MasterItemList::GetItems(string name, int32 itype, int32 ltype, i
// chkseller = seller.c_str();
//if(adornment.length() > 0)
// chkadornment = adornment.c_str();
LogWrite(ITEM__WARNING, 0, "Item", "Get Items: %s (itype: %llu, ltype: %u, btype: %u, minskill: %u, maxskill: %u, mintier: %u, maxtier: %u, minlevel: %u, maxlevel: %u itemclass %i)", name.c_str(), itype, ltype, btype, minskill, maxskill, mintier, maxtier, minlevel, maxlevel, itemclass);
bool should_add = true;
for(iter = items.begin();iter != items.end(); iter++){
item = iter->second;
if(item){
if(itype != ITEM_BROKER_TYPE_ANY){
if(itype != ITEM_BROKER_TYPE_ANY && itype != ITEM_BROKER_TYPE_ANY64BIT){
should_add = false;
switch(itype){
case ITEM_BROKER_TYPE_ADORNMENT:{
@ -253,6 +254,18 @@ vector<Item*>* MasterItemList::GetItems(string name, int32 itype, int32 ltype, i
should_add = true;
break;
}
case ITEM_BROKER_TYPE_2H_CRUSH:{
should_add = item->IsWeapon() && item->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND && item->generic_info.skill_req1 == SKILL_ID_STAFF;
break;
}
case ITEM_BROKER_TYPE_2H_PIERCE:{
should_add = item->IsWeapon() && item->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND && item->generic_info.skill_req1 == SKILL_ID_GREATSPEAR;
break;
}
case ITEM_BROKER_TYPE_2H_SLASH:{
should_add = item->IsWeapon() && item->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND && item->generic_info.skill_req1 == SKILL_ID_GREATSWORD;
break;
}
}
if(!should_add)
continue;
@ -635,7 +648,8 @@ vector<Item*>* MasterItemList::GetItems(string name, int32 itype, int32 ltype, i
if(maxlevel > 0 && ((item->generic_info.adventure_default_level > 0 && item->generic_info.adventure_default_level > maxlevel) || (item->generic_info.tradeskill_default_level > 0 && item->generic_info.tradeskill_default_level > maxlevel)))
continue;
}
if(mintier > 0 && item->details.tier < mintier)
// mintier of 1 is 'ANY'
if(mintier > 1 && item->details.tier < mintier)
continue;
if(maxtier > 0 && item->details.tier > maxtier)
continue;
@ -651,7 +665,7 @@ vector<Item*>* MasterItemList::GetItems(string name, int32 itype, int32 ltype, i
vector<Item*>* MasterItemList::GetItems(map<string, string> criteria){
string name, seller, adornment;
int32 itype = 0xFFFFFFFF;
int64 itype = 0xFFFFFFFFFFFFFFFF;
int32 ltype = 0xFFFFFFFF;
int32 btype = 0xFFFFFFFF;
int64 minprice = 0;
@ -691,7 +705,7 @@ vector<Item*>* MasterItemList::GetItems(map<string, string> criteria){
if(criteria.count("MAXLEVEL") > 0)
maxlevel = (int16)ParseIntValue(criteria["MAXLEVEL"]);
if(criteria.count("ITYPE") > 0)
itype = ParseIntValue(criteria["ITYPE"]);
itype = ParseLongLongValue(criteria["ITYPE"]);
if(criteria.count("LTYPE") > 0)
ltype = ParseIntValue(criteria["LTYPE"]);
if(criteria.count("BTYPE") > 0)
@ -3910,6 +3924,12 @@ bool EquipmentItemList::CheckEquipSlot(Item* tmp, int8 slot){
if(tmp->slot_data[i] == slot){
Item* tmp_item = GetItem(tmp->slot_data[i]);
if(!tmp_item || tmp_item->details.item_id == 0){
if(slot == EQ2_SECONDARY_SLOT)
{
Item* primary = GetItem(EQ2_PRIMARY_SLOT);
if(primary && primary->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND)
continue;
}
MEquipmentItems.unlock();
return true;
}
@ -3927,6 +3947,12 @@ int8 EquipmentItemList::GetFreeSlot(Item* tmp, int8 slot_id){
if(slot_id == 255 || slot == slot_id){
Item* tmp_item = GetItem(slot);
if(!tmp_item || tmp_item->details.item_id == 0){
if(slot == EQ2_SECONDARY_SLOT)
{
Item* primary = GetItem(EQ2_PRIMARY_SLOT);
if(primary && primary->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND)
continue;
}
MEquipmentItems.unlock();
return slot;
}

View file

@ -264,6 +264,7 @@ extern MasterItemList master_item_list;
#define ITEM_TAG_MYTHICAL 12
#define ITEM_BROKER_TYPE_ANY 0xFFFFFFFF
#define ITEM_BROKER_TYPE_ANY64BIT 0xFFFFFFFFFFFFFFFF
#define ITEM_BROKER_TYPE_ADORNMENT 134217728
#define ITEM_BROKER_TYPE_AMMO 1024
#define ITEM_BROKER_TYPE_ATTUNEABLE 16384
@ -294,6 +295,10 @@ extern MasterItemList master_item_list;
#define ITEM_BROKER_TYPE_TINKERED 268435456
#define ITEM_BROKER_TYPE_TRADESKILL 256
#define ITEM_BROKER_TYPE_2H_CRUSH 17179869184
#define ITEM_BROKER_TYPE_2H_PIERCE 34359738368
#define ITEM_BROKER_TYPE_2H_SLASH 8589934592
#define ITEM_BROKER_SLOT_ANY 0xFFFFFFFF
#define ITEM_BROKER_SLOT_AMMO 65536
#define ITEM_BROKER_SLOT_CHARM 524288
@ -988,7 +993,7 @@ public:
Item* GetItemByName(const char *name);
ItemStatsValues* CalculateItemBonuses(int32 item_id, Entity* entity = 0);
ItemStatsValues* CalculateItemBonuses(Item* desc, Entity* entity = 0, ItemStatsValues* values = 0);
vector<Item*>* GetItems(string name, int32 itype, int32 ltype, int32 btype, int64 minprice, int64 maxprice, int8 minskill, int8 maxskill, string seller, string adornment, int8 mintier, int8 maxtier, int16 minlevel, int16 maxlevel, sint8 itemclass);
vector<Item*>* GetItems(string name, int64 itype, int32 ltype, int32 btype, int64 minprice, int64 maxprice, int8 minskill, int8 maxskill, string seller, string adornment, int8 mintier, int8 maxtier, int16 minlevel, int16 maxlevel, sint8 itemclass);
vector<Item*>* GetItems(map<string, string> criteria);
void AddItem(Item* item);
bool IsBag(int32 item_id);

View file

@ -535,7 +535,7 @@ bool LuaInterface::LoadRegionScript(string name) {
return LoadRegionScript(name.c_str());
}
std::string LuaInterface::AddSpawnPointers(LuaSpell* spell, bool first_cast, bool precast, const char* function, SpellScriptTimer* timer, bool passLuaSpell) {
std::string LuaInterface::AddSpawnPointers(LuaSpell* spell, bool first_cast, bool precast, const char* function, SpellScriptTimer* timer, bool passLuaSpell, Spawn* altTarget) {
std::string functionCalled = string("");
if (function)
{
@ -578,7 +578,11 @@ std::string LuaInterface::AddSpawnPointers(LuaSpell* spell, bool first_cast, boo
if (temp_spawn)
SetSpawnValue(spell->state, temp_spawn);
else {
if(spell->caster && spell->caster->GetZone() != nullptr && spell->initial_target)
if(altTarget)
{
SetSpawnValue(spell->state, altTarget);
}
else if(spell->caster && spell->caster->GetZone() != nullptr && spell->initial_target)
{
// easier to debug target id as ptr
Spawn* new_target = spell->caster->GetZone()->GetSpawnByID(spell->initial_target);

View file

@ -233,7 +233,7 @@ public:
void SetConversationValue(lua_State* state, vector<ConversationOption>* conversation);
void SetOptionWindowValue(lua_State* state, vector<OptionWindowOption>* optionWindow);
std::string AddSpawnPointers(LuaSpell* spell, bool first_cast, bool precast = false, const char* function = 0, SpellScriptTimer* timer = 0, bool passLuaSpell=false);
std::string AddSpawnPointers(LuaSpell* spell, bool first_cast, bool precast = false, const char* function = 0, SpellScriptTimer* timer = 0, bool passLuaSpell=false, Spawn* altTarget = 0);
LuaSpell* GetCurrentSpell(lua_State* state);
bool CallSpellProcess(LuaSpell* spell, int8 num_parameters, std::string functionCalled);
LuaSpell* GetSpell(const char* name);

View file

@ -2016,19 +2016,42 @@ void Player::SetEquippedItemAppearances(){
GetZone()->SendSpawnChanges(this);
}
EQ2Packet* Player::SwapEquippedItems(int8 slot1, int8 slot2, int16 version){
Item* item_from = equipment_list.items[slot1];
Item* item_to = equipment_list.items[slot2];
if(item_from && equipment_list.CanItemBeEquippedInSlot(item_from, slot2)){
EQ2Packet* Player::SwapEquippedItems(int8 slot1, int8 slot2, int16 version, int16 equip_type){
EquipmentItemList* equipList = &equipment_list;
// right now client seems to pass 3 for this? Not sure why when other fields has appearance equipment as type 1
if(equip_type == 3)
equipList = &appearance_equipment_list;
Item* item_from = equipList->items[slot1];
Item* item_to = equipList->items[slot2];
if(item_from && equipList->CanItemBeEquippedInSlot(item_from, slot2)){
if(item_to){
if(!equipment_list.CanItemBeEquippedInSlot(item_to, slot1))
if(!equipList->CanItemBeEquippedInSlot(item_to, slot1))
return 0;
item_to->details.slot_id = slot1;
}
equipList->items[slot1] = nullptr;
equipList->SetItem(slot2, item_from);
if(item_to)
{
equipList->SetItem(slot1, item_to);
item_to->save_needed = true;
}
item_from->save_needed = true;
item_from->details.slot_id = slot2;
return equipment_list.serialize(version, this);
if (GetClient())
{
//EquipmentItemList* equipList = &equipment_list;
//if(appearance_type)
// equipList = &appearance_equipment_list;
if(item_to)
GetClient()->QueuePacket(item_to->serialize(version, false, this));
GetClient()->QueuePacket(item_from->serialize(version, false, this));
GetClient()->QueuePacket(item_list.serialize(this, version));
}
return equipList->serialize(version, this);
}
return 0;
}

View file

@ -453,7 +453,7 @@ public:
vector<EQ2Packet*> UnequipItem(int16 index, sint32 bag_id, int8 slot, int16 version, int8 appearance_type = 0);
int8 ConvertSlotToClient(int8 slot, int16 version);
int8 ConvertSlotFromClient(int8 slot, int16 version);
EQ2Packet* SwapEquippedItems(int8 slot1, int8 slot2, int16 version);
EQ2Packet* SwapEquippedItems(int8 slot1, int8 slot2, int16 version, int16 equiptype);
EQ2Packet* RemoveInventoryItem(int8 bag_slot, int8 slot);
EQ2Packet* SendInventoryUpdate(int16 version);
EQ2Packet* SendBagUpdate(int32 bag_unique_id, int16 version);

View file

@ -66,6 +66,10 @@
#define SKILL_ID_DESTROYING 3429135390
#define SKILL_ID_MAGIC_AFFINITY 2072844078
#define SKILL_ID_GREATSWORD 2292577688 // aka 2h slashing
#define SKILL_ID_GREATSPEAR 2380184628 // aka 2h piercing
#define SKILL_ID_STAFF 3180399725 // aka 2h crushing
/* Each SkillBonus is comprised of multiple possible skill bonus values. This is so one spell can modify
more than one skill */
struct SkillBonusValue {

View file

@ -447,44 +447,69 @@ bool SpellProcess::DeleteCasterSpell(LuaSpell* spell, string reason, bool removi
return ret;
}
bool SpellProcess::ProcessSpell(LuaSpell* spell, bool first_cast, const char* function, SpellScriptTimer* timer) {
bool SpellProcess::ProcessSpell(LuaSpell* spell, bool first_cast, const char* function, SpellScriptTimer* timer, bool all_targets) {
bool ret = false;
if(!spell->state)
{
LogWrite(SPELL__ERROR, 0, "Spell", "Error: State is NULL! SpellProcess::ProcessSpell for Spell '%s'", (spell->spell != nullptr) ? spell->spell->GetName() : "Unknown");
}
else if(lua_interface && !spell->interrupted){
std::string functionCall = lua_interface->AddSpawnPointers(spell, first_cast, false, function, timer);
vector<LUAData*>* data = spell->spell->GetLUAData();
for(int32 i=0;i<data->size();i++){
switch(data->at(i)->type){
case 0:{
lua_interface->SetSInt32Value(spell->state, data->at(i)->int_value);
break;
}
case 1:{
lua_interface->SetFloatValue(spell->state, data->at(i)->float_value);
break;
}
case 2:{
lua_interface->SetBooleanValue(spell->state, data->at(i)->bool_value);
break;
}
case 3:{
lua_interface->SetStringValue(spell->state, data->at(i)->string_value.c_str());
break;
}
default:{
LogWrite(SPELL__ERROR, 0, "Spell", "Error: Unknown LUA Type '%i' in SpellProcess::ProcessSpell for Spell '%s'", (int)data->at(i)->type, spell->spell->GetName());
return false;
if(all_targets)
{
for(int t=0;t<spell->targets.size();t++)
{
Spawn* altSpawn = spell->caster->GetZone()->GetSpawnByID(spell->targets[t]);
if(altSpawn)
{
std::string functionCall = ApplyLuaFunction(spell, first_cast, function, timer, altSpawn);
if(functionCall.length() < 1)
ret = false;
else
ret = lua_interface->CallSpellProcess(spell, 2 + spell->spell->GetLUAData()->size(), functionCall);
}
}
return true;
}
ret = lua_interface->CallSpellProcess(spell, 2 + data->size(), functionCall);
std::string functionCall = ApplyLuaFunction(spell, first_cast, function, timer);
if(functionCall.length() < 1)
ret = false;
else
ret = lua_interface->CallSpellProcess(spell, 2 + spell->spell->GetLUAData()->size(), functionCall);
}
return ret;
}
std::string SpellProcess::ApplyLuaFunction(LuaSpell* spell, bool first_cast, const char* function, SpellScriptTimer* timer, Spawn* altTarget)
{
std::string functionCall = lua_interface->AddSpawnPointers(spell, first_cast, false, function, timer, false, altTarget);
vector<LUAData*>* data = spell->spell->GetLUAData();
for(int32 i=0;i<data->size();i++){
switch(data->at(i)->type){
case 0:{
lua_interface->SetSInt32Value(spell->state, data->at(i)->int_value);
break;
}
case 1:{
lua_interface->SetFloatValue(spell->state, data->at(i)->float_value);
break;
}
case 2:{
lua_interface->SetBooleanValue(spell->state, data->at(i)->bool_value);
break;
}
case 3:{
lua_interface->SetStringValue(spell->state, data->at(i)->string_value.c_str());
break;
}
default:{
LogWrite(SPELL__ERROR, 0, "Spell", "Error: Unknown LUA Type '%i' in SpellProcess::ProcessSpell for Spell '%s'", (int)data->at(i)->type, spell->spell->GetName());
return string("");
}
}
}
return functionCall;
}
bool SpellProcess::CastPassives(Spell* spell, Entity* caster, bool remove) {
CastInstant(spell, caster, caster, remove, true);
return true;
@ -1050,14 +1075,12 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster,
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;
}
}
@ -1102,7 +1125,7 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster,
return;
}
if (target_type != SPELL_TARGET_SELF && target_type != SPELL_TARGET_GROUP_AE && target_type != SPELL_TARGET_NONE && spell->GetSpellData()->max_aoe_targets == 0)
if (target_type != SPELL_TARGET_SELF && target_type != SPELL_TARGET_GROUP_AE && target_type != SPELL_TARGET_ALLGROUPTARGETS && target_type != SPELL_TARGET_NONE && spell->GetSpellData()->max_aoe_targets == 0)
{
LogWrite(SPELL__DEBUG, 1, "Spell", "%s: Not Self, Not Group AE, Not None, Max Targets = 0", spell->GetName());
@ -1562,8 +1585,10 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
}
}
}*/
bool allTargets = (spell->spell->GetSpellData()->target_type == SPELL_TARGET_ALLGROUPTARGETS);
if (!processedSpell)
processedSpell = ProcessSpell(spell);
processedSpell = ProcessSpell(spell, true, 0, 0, allTargets);
// Quick hack to prevent a crash on spells that zones the caster (Gate)
if (!spell->caster)
@ -2000,26 +2025,48 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
}
}
}
else if (target_type == SPELL_TARGET_GROUP_AE || target_type == SPELL_TARGET_RAID_AE) {
else if (target_type == SPELL_TARGET_GROUP_AE || target_type == SPELL_TARGET_ALLGROUPTARGETS || target_type == SPELL_TARGET_RAID_AE) {
// player handling
if (target)
{
if (data->icon_backdrop == 316) // using TARGET backdrop icon
if (data->icon_backdrop == 316 || data->icon_backdrop == 312) // using TARGET backdrop icon
{
// PLAYER LOGIC:
if ((target->IsPlayer() && luaspell->caster->IsPlayer() && target != luaspell->caster && ((Player*)target)->GetGroupMemberInfo() != NULL && ((Player*)luaspell->caster)->GetGroupMemberInfo() != NULL
if ((data->friendly_spell && (target->IsPlayer() && luaspell->caster->IsPlayer() && target != luaspell->caster && ((Player*)target)->GetGroupMemberInfo() != NULL && ((Player*)luaspell->caster)->GetGroupMemberInfo() != NULL
&& ((Player*)target)->GetGroupMemberInfo()->group_id == ((Player*)luaspell->caster)->GetGroupMemberInfo()->group_id))
|| (!data->friendly_spell && (target->IsPlayer() && luaspell->caster->IsPlayer() && target != luaspell->caster && ((Player*)target)->GetGroupMemberInfo() != NULL)))
{
GetPlayerGroupTargets((Player*)target, caster, luaspell, true, false);
}//TODO: NEED RAID SUPPORT
}
//TODO: NEED RAID SUPPORT
// NPC LOGIC:
else if (target->group_id > 0 && target->group_id == luaspell->caster->group_id)
else if (target->IsNPC())
{
// Check to see if the npc is a spawn group by getting the group and checikng if valid
vector<Spawn*>* group = ((NPC*)target)->GetSpawnGroup();
if (group)
{
vector<Spawn*>::iterator itr;
// iterate through spawn group members
for (itr = group->begin(); itr != group->end(); itr++)
{
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 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
}
} // end is spawngroup
else
luaspell->targets.push_back(target->GetID()); // return single target NPC for non-friendly spell
}
else
else if(data->friendly_spell)
{
// add self
target = NULL;
@ -2060,7 +2107,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
luaspell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
// Group AE type NOTE: Add support for RAID AE to affect raid members once raids have been completed
if (target_type == SPELL_TARGET_GROUP_AE || target_type == SPELL_TARGET_RAID_AE)
if (target_type == SPELL_TARGET_GROUP_AE || target_type == SPELL_TARGET_ALLGROUPTARGETS || target_type == SPELL_TARGET_RAID_AE)
{
if (data->icon_backdrop == 316) // single target in a group/raid
{

View file

@ -385,7 +385,8 @@ public:
void SpellCannotStack(ZoneServer* zone, Client* client, Entity* caster, LuaSpell* lua_spell, LuaSpell* conflictSpell);
bool ProcessSpell(LuaSpell* spell, bool first_cast = true, const char* function = 0, SpellScriptTimer* timer = 0);
bool ProcessSpell(LuaSpell* spell, bool first_cast = true, const char* function = 0, SpellScriptTimer* timer = 0, bool all_targets = false);
std::string ApplyLuaFunction(LuaSpell* spell, bool first_cast, const char* function, SpellScriptTimer* timer, Spawn* altTarget = 0);
void AddActiveSpell(LuaSpell* spell);
static void AddSelfAndPet(LuaSpell* spell, Spawn* caster, bool onlyPet=false);

View file

@ -40,6 +40,7 @@
#define SPELL_TARGET_NONE 7
#define SPELL_TARGET_RAID_AE 8
#define SPELL_TARGET_OTHER_GROUP_AE 9
#define SPELL_TARGET_ALLGROUPTARGETS 10 // use this with cast/tick only containing DIRECT target/spawn.
#define SPELL_BOOK_TYPE_SPELL 0

View file

@ -7405,7 +7405,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
if(custom_spell)
{
if((lua_spell = lua_interface->GetSpell(lua_file.c_str())) == nullptr)
{
{
LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: GetSpell(%u, %u, '%s'), custom lua script not loaded, when attempting to load.", spell_id, tier, lua_file.c_str());
lua_interface->LoadLuaSpell(lua_file);
}
@ -7458,6 +7458,9 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
else if(db_spell_type == DB_TYPE_MAINTAINEDEFFECTS)
{
safe_delete(lua_spell);
if(!target_char_id)
continue;
lua_spell = lua_interface->GetSpell(spell->GetSpellData()->lua_script.c_str());
if(lua_spell)
lua_spell->spell = spell;

View file

@ -3241,7 +3241,7 @@ void ClientList::RemoveConnection(EQStream* eqs) {
for (client_iter = client_list.begin(); client_iter != client_list.end(); client_iter++) {
client = *client_iter;
if (client->getConnection() == eqs)
client->Disconnect(false);
client->Disconnect(true);
}
MClients.releasereadlock(__FUNCTION__, __LINE__);
}

View file

@ -568,6 +568,21 @@ int32 ParseIntValue(string input){
return ret;
}
int64 ParseLongLongValue(string input){
int64 ret = 0xFFFFFFFFFFFFFFFF;
try{
if(input.length() > 0){
#ifdef WIN32
ret = _strtoui64(input.c_str(), NULL, 10);
#else
ret = strtoull(input.c_str(), 0, 10);
#endif
}
}
catch(...){}
return ret;
}
map<string, string> TranslateBrokerRequest(string request){
map<string, string> ret;
string key;

View file

@ -67,6 +67,7 @@ void Decode(uchar* dst, uchar* src, int16 len);
string ToUpper(string input);
string ToLower(string input);
int32 ParseIntValue(string input);
int64 ParseLongLongValue(string input);
map<string, string> TranslateBrokerRequest(string request);
void MovementDecode(uchar* dst, uchar* newval, uchar* orig, int16 len);
vector<string>* SplitString(string str, char delim);