Merge fix

This commit is contained in:
KimLS 2017-04-11 21:48:01 -07:00
commit 1d1ee1ccbf
40 changed files with 331 additions and 186 deletions

View File

@ -1,6 +1,7 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 4/1/2017 ==
Akkadius: Cleaned up some of the NPC to NPC aggro code, only do aggro checks to other NPC's when the NPC is flagged for it
Akkadius: [Performance] Reworked how all log calls are made in the source
- Before we used Log.Out, we will now use a macro Log(
- Before: Log.Out(Logs::General, Logs::Status, "Importing Spells...");

View File

@ -49,7 +49,7 @@ namespace EQEmu
};
enum DeityTypeBit : uint32 {
bit_DeityAll = 0x00000000,
bit_DeityNone = 0x00000000,
bit_DeityAgnostic = 0x00000001,
bit_DeityBertoxxulous = 0x00000002,
bit_DeityBrellSirilis = 0x00000004,
@ -66,7 +66,8 @@ namespace EQEmu
bit_DeitySolusekRo = 0x00002000,
bit_DeityTheTribunal = 0x00004000,
bit_DeityTunare = 0x00008000,
bit_DeityVeeshan = 0x00010000
bit_DeityVeeshan = 0x00010000,
bit_DeityAll = 0xFFFFFFFF
};
extern DeityTypeBit ConvertDeityTypeToDeityTypeBit(DeityType deity_type);

View File

@ -105,6 +105,15 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::Login_Server].log_to_console = Logs::General;
log_settings[Logs::Headless_Client].log_to_console = Logs::General;
/* Set Category enabled status on defaults */
log_settings[Logs::World_Server].is_category_enabled = 1;
log_settings[Logs::Zone_Server].is_category_enabled = 1;
log_settings[Logs::QS_Server].is_category_enabled = 1;
log_settings[Logs::UCS_Server].is_category_enabled = 1;
log_settings[Logs::Crash].is_category_enabled = 1;
log_settings[Logs::MySQLError].is_category_enabled = 1;
log_settings[Logs::Login_Server].is_category_enabled = 1;
/* Declare process file names for log writing
If there is no process_file_name declared, no log file will be written, simply
*/

View File

@ -111,9 +111,6 @@ Zone extensions and features
//path to where sql logs should be placed
#define SQL_LOG_PATH "sql_logs/"
//New aggro system to reduce overhead.
#define REVERSE_AGGRO
//The highest you can #setskill / #setallskill
#define HIGHEST_CAN_SET_SKILL 400

View File

@ -241,48 +241,70 @@ EQEmu::ItemInstance* EQEmu::InventoryProfile::GetCursorItem()
}
// Swap items in inventory
bool EQEmu::InventoryProfile::SwapItem(int16 slot_a, int16 slot_b, uint16 race_id, uint8 class_id, uint16 deity_id, uint8 level)
bool EQEmu::InventoryProfile::SwapItem(int16 slot_a, int16 slot_b, SwapItemFailState& fail_state, uint16 race_id, uint8 class_id, uint16 deity_id, uint8 level)
{
fail_state = swapInvalid;
// Temp holding areas for a and b
ItemInstance* inst_a = GetItem(slot_a);
ItemInstance* inst_b = GetItem(slot_b);
if (inst_a) {
if (!inst_a->IsSlotAllowed(slot_b))
if (!inst_a->IsSlotAllowed(slot_b)) {
fail_state = swapNotAllowed;
return false;
}
if ((slot_b >= legacy::EQUIPMENT_BEGIN && slot_b <= legacy::EQUIPMENT_END) || slot_b == inventory::slotPowerSource) {
auto item_a = inst_a->GetItem();
if (!item_a)
if (!item_a) {
fail_state = swapNullData;
return false;
if (race_id && class_id && !item_a->IsEquipable(race_id, class_id))
}
if (race_id && class_id && !item_a->IsEquipable(race_id, class_id)) {
fail_state = swapRaceClass;
return false;
if (deity_id && item_a->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & item_a->Deity))
}
if (deity_id && item_a->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & item_a->Deity)) {
fail_state = swapDeity;
return false;
if (level && item_a->ReqLevel && level < item_a->ReqLevel)
}
if (level && item_a->ReqLevel && level < item_a->ReqLevel) {
fail_state = swapLevel;
return false;
}
}
}
if (inst_b) {
if (!inst_b->IsSlotAllowed(slot_a))
if (!inst_b->IsSlotAllowed(slot_a)) {
fail_state = swapNotAllowed;
return false;
}
if ((slot_a >= legacy::EQUIPMENT_BEGIN && slot_a <= legacy::EQUIPMENT_END) || slot_a == inventory::slotPowerSource) {
auto item_b = inst_b->GetItem();
if (!item_b)
if (!item_b) {
fail_state = swapNullData;
return false;
if (race_id && class_id && !item_b->IsEquipable(race_id, class_id))
}
if (race_id && class_id && !item_b->IsEquipable(race_id, class_id)) {
fail_state = swapRaceClass;
return false;
if (deity_id && item_b->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & item_b->Deity))
}
if (deity_id && item_b->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & item_b->Deity)) {
fail_state = swapDeity;
return false;
if (level && item_b->ReqLevel && level < item_b->ReqLevel)
}
if (level && item_b->ReqLevel && level < item_b->ReqLevel) {
fail_state = swapLevel;
return false;
}
}
}
_PutItem(slot_a, inst_b); // Copy b->a
_PutItem(slot_b, inst_a); // Copy a->b
_PutItem(slot_a, inst_b); // Assign b->a
_PutItem(slot_b, inst_a); // Assign a->b
fail_state = swapPass;
return true;
}

View File

@ -85,15 +85,22 @@ namespace EQEmu
// Public Methods
///////////////////////////////
InventoryProfile() { m_mob_version = versions::MobVersion::Unknown; m_mob_version_set = false; }
InventoryProfile() {
m_mob_version = versions::MobVersion::Unknown;
m_mob_version_set = false;
m_lookup = inventory::Lookup(versions::MobVersion::Unknown);
}
~InventoryProfile();
bool SetInventoryVersion(versions::MobVersion inventory_version) {
if (!m_mob_version_set) {
m_mob_version = versions::ValidateMobVersion(inventory_version);
return (m_mob_version_set = true);
m_lookup = inventory::Lookup(m_mob_version);
m_mob_version_set = true;
return true;
}
else {
m_lookup = inventory::Lookup(versions::MobVersion::Unknown);
return false;
}
}
@ -127,7 +134,8 @@ namespace EQEmu
ItemInstance* GetCursorItem();
// Swap items in inventory
bool SwapItem(int16 slot_a, int16 slot_b, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
bool SwapItem(int16 slot_a, int16 slot_b, SwapItemFailState& fail_state, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
// Remove item from inventory
bool DeleteItem(int16 slot_id, uint8 quantity = 0);
@ -224,6 +232,7 @@ namespace EQEmu
// Active mob version
versions::MobVersion m_mob_version;
bool m_mob_version_set;
const inventory::LookupEntry* m_lookup;
};
}

View File

@ -22,7 +22,8 @@
#include <map>
#include <vector>
enum { //values for pTimerType
enum : int { //values for pTimerType
pTimerNegativeItemReuse = -1, // these grow down basically, we will have item ID * -1 for the timer ID
pTimerStartAdventureTimer = 1,
pTimerSurnameChange = 2,
pTimerFeignDeath = 3,

View File

@ -30,7 +30,7 @@
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9107
#define CURRENT_BINARY_DATABASE_VERSION 9110
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017
#else

View File

@ -44,6 +44,7 @@ int main()
LogSys.LoadLogSettingsDefaults();
LogSys.log_settings[Logs::Error].log_to_console = Logs::General;
LogSys.log_settings[Logs::Error].is_category_enabled = 1;
Log(Logs::General, Logs::Login_Server, "Logging System Init.");

View File

@ -361,6 +361,9 @@
9105|2017_02_15_bot_spells_entries.sql|SELECT `id` FROM `npc_spells_entries` WHERE `npc_spells_id` >= 701 AND `npc_spells_id` <= 712|not_empty|
9106|2017_02_26_npc_spells_update_for_bots.sql|SELECT * FROM `npc_spells` WHERE `id` = '701' AND `name` = 'Cleric Bot'|not_empty|
9107|2017_03_09_inventory_version.sql|SHOW TABLES LIKE 'inventory_version'|empty|
9108|2017_04_07_ignore_despawn.sql|SHOW COLUMNS FROM `npc_types` LIKE 'ignore_despawn'|empty|
9109|2017_04_08_doors_disable_timer.sql|SHOW COLUMNS FROM `doors` LIKE 'disable_timer'|empty|
9110|2017_04_10_graveyard.sql|show index from graveyard WHERE key_name = 'zone_id_nonunique'|empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1 @@
alter table npc_types add column `ignore_despawn` tinyint(2) not null default 0;

View File

@ -0,0 +1 @@
ALTER TABLE `doors` ADD COLUMN `disable_timer` TINYINT(2) NOT NULL DEFAULT '0' AFTER `triggertype`;

View File

@ -0,0 +1,2 @@
alter table graveyard drop index zone_id;
create index zone_id_nonunique on graveyard(zone_id);

View File

@ -162,6 +162,7 @@ SET(zone_headers
lua_bit.h
lua_client.h
lua_corpse.h
lua_door.h
lua_encounter.h
lua_entity.h
lua_entity_list.h

View File

@ -408,25 +408,19 @@ bool Mob::CheckWillAggro(Mob *mob) {
return(false);
}
Mob* EntityList::AICheckCloseAggro(Mob* sender, float iAggroRange, float iAssistRange) {
Mob* EntityList::AICheckNPCtoNPCAggro(Mob* sender, float iAggroRange, float iAssistRange) {
if (!sender || !sender->IsNPC())
return(nullptr);
#ifdef REVERSE_AGGRO
//with reverse aggro, npc->client is checked elsewhere, no need to check again
auto it = npc_list.begin();
while (it != npc_list.end()) {
#else
auto it = mob_list.begin();
while (it != mob_list.end()) {
#endif
Mob *mob = it->second;
if (sender->CheckWillAggro(mob))
return mob;
++it;
}
//LogFile->write(EQEMuLog::Debug, "Check aggro for %s no target.", sender->GetName());
return nullptr;
}

View File

@ -3974,16 +3974,9 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
Log(Logs::Detail, Logs::Combat,
"Spell proc %d procing spell %d (%.2f percent chance)",
i, SpellProcs[i].spellID, chance);
auto outapp = new EQApplicationPacket(OP_BeginCast, sizeof(BeginCast_Struct));
BeginCast_Struct* begincast = (BeginCast_Struct*)outapp->pBuffer;
begincast->caster_id = GetID();
begincast->spell_id = SpellProcs[i].spellID;
begincast->cast_time = 0;
outapp->priority = 3;
entity_list.QueueCloseClients(this, outapp, false, RuleI(Range, SpellMessages), 0, true);
safe_delete(outapp);
"Spell proc %d procing spell %d (%.2f percent chance)",
i, SpellProcs[i].spellID, chance);
SendBeginCast(SpellProcs[i].spellID, 0);
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
SpellProcs[i].base_spellID);

View File

@ -134,9 +134,7 @@ Client::Client(EQStreamInterface* ieqs)
endupkeep_timer(1000),
forget_timer(0),
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
#ifdef REVERSE_AGGRO
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000),
#endif
tribute_timer(Tribute_duration),
proximity_timer(ClientProximity_interval),
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),

View File

@ -1460,9 +1460,7 @@ private:
Timer endupkeep_timer;
Timer forget_timer; // our 2 min everybody forgets you timer
Timer autosave_timer;
#ifdef REVERSE_AGGRO
Timer client_scan_npc_aggro_timer;
#endif
Timer tribute_timer;
Timer proximity_timer;

View File

@ -614,7 +614,6 @@ bool Client::Process() {
}
}
#ifdef REVERSE_AGGRO
//At this point, we are still connected, everything important has taken
//place, now check to see if anybody wants to aggro us.
// only if client is not feigned
@ -630,7 +629,6 @@ bool Client::Process() {
}
Log(Logs::General, Logs::Aggro, "Checking Reverse Aggro (client->npc) scanned_npcs (%i)", npc_scan_count);
}
#endif
if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
{

View File

@ -70,6 +70,8 @@ m_Destination(door->dest_x, door->dest_y, door->dest_z, door->dest_heading)
is_ldon_door = door->is_ldon_door;
client_version_mask = door->client_version_mask;
disable_timer = (door->disable_timer == 1 ? true : false);
}
Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uint16 dsize) :
@ -102,6 +104,8 @@ m_Destination(glm::vec4())
is_ldon_door = 0;
client_version_mask = 4294967295u;
disable_timer = 0;
}
@ -135,7 +139,7 @@ void Doors::HandleClick(Client* sender, uint8 trigger)
//door debugging info dump
Log(Logs::Detail, Logs::Doors, "%s clicked door %s (dbid %d, eqid %d) at %s", sender->GetName(), door_name, db_id, door_id, to_string(m_Position).c_str());
Log(Logs::Detail, Logs::Doors, " incline %d, opentype %d, lockpick %d, key %d, nokeyring %d, trigger %d type %d, param %d", incline, opentype, lockpick, keyitem, nokeyring, trigger_door, trigger_type, door_param);
Log(Logs::Detail, Logs::Doors, " size %d, invert %d, dest: %s %s", size, invert_state, dest_zone, to_string(m_Destination).c_str());
Log(Logs::Detail, Logs::Doors, " disable_timer '%s',size %d, invert %d, dest: %s %s", (disable_timer?"true":"false"), size, invert_state, dest_zone, to_string(m_Destination).c_str());
auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct));
MoveDoor_Struct* md = (MoveDoor_Struct*)outapp->pBuffer;
@ -354,13 +358,15 @@ void Doors::HandleClick(Client* sender, uint8 trigger)
entity_list.QueueClients(sender, outapp, false);
if(!IsDoorOpen() || (opentype == 58))
{
close_timer.Start();
if (!disable_timer)
close_timer.Start();
SetOpenState(true);
}
else
{
close_timer.Disable();
SetOpenState(false);
if (!disable_timer)
SetOpenState(false);
}
//everything past this point assumes we opened the door
@ -443,31 +449,34 @@ void Doors::HandleClick(Client* sender, uint8 trigger)
void Doors::NPCOpen(NPC* sender, bool alt_mode)
{
if(sender) {
if(GetTriggerType() == 255 || GetTriggerDoorID() > 0 || GetLockpick() != 0 || GetKeyItem() != 0 || opentype == 59 || opentype == 58 || !sender->IsNPC()) { // this object isnt triggered or door is locked - NPCs should not open locked doors!
if (sender) {
if (GetTriggerType() == 255 || GetTriggerDoorID() > 0 || GetLockpick() != 0 || GetKeyItem() != 0 || opentype == 59 || opentype == 58 || !sender->IsNPC()) { // this object isnt triggered or door is locked - NPCs should not open locked doors!
return;
}
auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct));
MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer;
MoveDoor_Struct* md = (MoveDoor_Struct*)outapp->pBuffer;
md->doorid = door_id;
md->action = invert_state == 0 ? OPEN_DOOR : OPEN_INVDOOR;
entity_list.QueueCloseClients(sender,outapp,false,200);
entity_list.QueueCloseClients(sender, outapp, false, 200);
safe_delete(outapp);
if(!alt_mode) { // original function
if(!isopen) {
close_timer.Start();
isopen=true;
if (!alt_mode) { // original function
if (!is_open) {
if (!disable_timer)
close_timer.Start();
is_open = true;
}
else {
close_timer.Disable();
isopen=false;
if (!disable_timer)
is_open = false;
}
}
else { // alternative function
close_timer.Start();
isopen=true;
if (!disable_timer)
close_timer.Start();
is_open = true;
}
}
}
@ -475,49 +484,53 @@ void Doors::NPCOpen(NPC* sender, bool alt_mode)
void Doors::ForceOpen(Mob *sender, bool alt_mode)
{
auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct));
MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer;
MoveDoor_Struct* md = (MoveDoor_Struct*)outapp->pBuffer;
md->doorid = door_id;
md->action = invert_state == 0 ? OPEN_DOOR : OPEN_INVDOOR;
entity_list.QueueClients(sender,outapp,false);
entity_list.QueueClients(sender, outapp, false);
safe_delete(outapp);
if(!alt_mode) { // original function
if(!isopen) {
close_timer.Start();
isopen=true;
if (!alt_mode) { // original function
if (!is_open) {
if (!disable_timer)
close_timer.Start();
is_open = true;
}
else {
close_timer.Disable();
isopen=false;
if (!disable_timer)
is_open = false;
}
}
else { // alternative function
close_timer.Start();
isopen=true;
if (!disable_timer)
close_timer.Start();
is_open = true;
}
}
void Doors::ForceClose(Mob *sender, bool alt_mode)
{
auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct));
MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer;
MoveDoor_Struct* md = (MoveDoor_Struct*)outapp->pBuffer;
md->doorid = door_id;
md->action = invert_state == 0 ? CLOSE_DOOR : CLOSE_INVDOOR; // change from original (open to close)
entity_list.QueueClients(sender,outapp,false);
entity_list.QueueClients(sender, outapp, false);
safe_delete(outapp);
if(!alt_mode) { // original function
if(!isopen) {
close_timer.Start();
isopen=true;
if (!alt_mode) { // original function
if (!is_open) {
if (!disable_timer)
close_timer.Start();
is_open = true;
}
else {
close_timer.Disable();
isopen=false;
is_open = false;
}
}
else { // alternative function
if(isopen)
if (is_open)
close_timer.Trigger();
}
}
@ -532,14 +545,14 @@ void Doors::ToggleState(Mob *sender)
MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer;
md->doorid = door_id;
if(!isopen) {
if(!is_open) {
md->action = invert_state == 0 ? OPEN_DOOR : OPEN_INVDOOR;
isopen=true;
is_open=true;
}
else
{
md->action = invert_state == 0 ? CLOSE_DOOR : CLOSE_INVDOOR;
isopen=false;
is_open=false;
}
entity_list.QueueClients(sender,outapp,false);
@ -552,7 +565,7 @@ void Doors::DumpDoor(){
db_id, door_id, zone_name, door_name, to_string(m_Position).c_str());
Log(Logs::General, Logs::None,
"opentype:%i guild_id:%i lockpick:%i keyitem:%i nokeyring:%i trigger_door:%i trigger_type:%i door_param:%i open:%s",
opentype, guild_id, lockpick, keyitem, nokeyring, trigger_door, trigger_type, door_param, (isopen) ? "open":"closed");
opentype, guild_id, lockpick, keyitem, nokeyring, trigger_door, trigger_type, door_param, (is_open) ? "open":"closed");
Log(Logs::General, Logs::None,
"dest_zone:%s destination:%s ",
dest_zone, to_string(m_Destination).c_str());
@ -632,34 +645,32 @@ bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name
Log(Logs::General, Logs::Status, "Loading Doors from database...");
// Door tmpDoor;
std::string query = StringFormat("SELECT id, doorid, zone, name, pos_x, pos_y, pos_z, heading, "
"opentype, guild, lockpick, keyitem, nokeyring, triggerdoor, triggertype, "
"dest_zone, dest_instance, dest_x, dest_y, dest_z, dest_heading, "
"door_param, invert_state, incline, size, is_ldon_door, client_version_mask "
"FROM doors WHERE zone = '%s' AND (version = %u OR version = -1) "
"ORDER BY doorid asc", zone_name, version);
// Door tmpDoor;
std::string query = StringFormat("SELECT id, doorid, zone, name, pos_x, pos_y, pos_z, heading, "
"opentype, guild, lockpick, keyitem, nokeyring, triggerdoor, triggertype, "
"dest_zone, dest_instance, dest_x, dest_y, dest_z, dest_heading, "
"door_param, invert_state, incline, size, is_ldon_door, client_version_mask, disable_timer "
"FROM doors WHERE zone = '%s' AND (version = %u OR version = -1) "
"ORDER BY doorid asc", zone_name, version);
auto results = QueryDatabase(query);
if (!results.Success()){
if (!results.Success()) {
return false;
}
int32 rowIndex = 0;
for(auto row = results.begin(); row != results.end(); ++row, ++rowIndex) {
if(rowIndex >= iDoorCount) {
std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl;
break;
}
int32 rowIndex = 0;
for (auto row = results.begin(); row != results.end(); ++row, ++rowIndex) {
if (rowIndex >= iDoorCount) {
std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl;
break;
}
memset(&into[rowIndex], 0, sizeof(Door));
memset(&into[rowIndex], 0, sizeof(Door));
into[rowIndex].db_id = atoi(row[0]);
into[rowIndex].door_id = atoi(row[1]);
Log(Logs::Detail, Logs::Doors, "Door Load: db id: %u, door_id %u", into[rowIndex].db_id, into[rowIndex].door_id);
strn0cpy(into[rowIndex].zone_name,row[2],32);
strn0cpy(into[rowIndex].door_name,row[3],32);
strn0cpy(into[rowIndex].zone_name, row[2], 32);
strn0cpy(into[rowIndex].door_name, row[3], 32);
into[rowIndex].pos_x = (float)atof(row[4]);
into[rowIndex].pos_y = (float)atof(row[5]);
@ -676,17 +687,24 @@ bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name
strn0cpy(into[rowIndex].dest_zone, row[15], 32);
into[rowIndex].dest_instance_id = atoi(row[16]);
into[rowIndex].dest_x = (float) atof(row[17]);
into[rowIndex].dest_y = (float) atof(row[18]);
into[rowIndex].dest_z = (float) atof(row[19]);
into[rowIndex].dest_heading = (float) atof(row[20]);
into[rowIndex].door_param=atoi(row[21]);
into[rowIndex].invert_state=atoi(row[22]);
into[rowIndex].incline=atoi(row[23]);
into[rowIndex].size=atoi(row[24]);
into[rowIndex].is_ldon_door=atoi(row[25]);
into[rowIndex].dest_x = (float)atof(row[17]);
into[rowIndex].dest_y = (float)atof(row[18]);
into[rowIndex].dest_z = (float)atof(row[19]);
into[rowIndex].dest_heading = (float)atof(row[20]);
into[rowIndex].door_param = atoi(row[21]);
into[rowIndex].invert_state = atoi(row[22]);
into[rowIndex].incline = atoi(row[23]);
into[rowIndex].size = atoi(row[24]);
into[rowIndex].is_ldon_door = atoi(row[25]);
into[rowIndex].client_version_mask = (uint32)strtoul(row[26], nullptr, 10);
}
into[rowIndex].disable_timer = atoi(row[27]);
Log(Logs::Detail, Logs::Doors, "Door Load: db id: %u, door_id %u disable_timer: %i",
into[rowIndex].db_id,
into[rowIndex].door_id,
into[rowIndex].disable_timer
);
}
return true;
}
@ -730,6 +748,10 @@ void Doors::SetSize(uint16 in) {
entity_list.RespawnAllDoors();
}
void Doors::SetDisableTimer(bool flag) {
disable_timer = flag;
}
void Doors::CreateDatabaseEntry()
{
if(database.GetDoorsDBCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion()) - 1 >= 255)

View File

@ -32,8 +32,8 @@ public:
const glm::vec4& GetPosition() const{ return m_Position; }
int GetIncline() { return incline; }
bool triggered;
void SetOpenState(bool st) { isopen = st; }
bool IsDoorOpen() { return isopen; }
void SetOpenState(bool st) { is_open = st; }
bool IsDoorOpen() { return is_open; }
uint8 GetTriggerDoorID() { return trigger_door; }
uint8 GetTriggerType() { return trigger_type; }
@ -67,6 +67,10 @@ public:
void SetDoorName(const char* name);
void SetOpenType(uint8 in);
void SetSize(uint16 size);
void SetDisableTimer(bool flag);
bool GetDisableTimer() { return disable_timer; }
void CreateDatabaseEntry();
private:
@ -88,7 +92,8 @@ private:
uint16 size;
int invert_state;
uint32 entity_id;
bool isopen;
bool disable_timer;
bool is_open;
Timer close_timer;
//Timer trigger_timer;

View File

@ -877,12 +877,12 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client)
auto it = door_list.begin();
while (it != door_list.end()) {
if ((it->second->GetClientVersionMask() & mask_test) &&
strlen(it->second->GetDoorName()) > 3)
strlen(it->second->GetDoorName()) > 3)
count++;
++it;
}
if(count == 0 || count > 500)
if (count == 0 || count > 500)
return false;
uint32 length = count * sizeof(Door_Struct);
@ -890,31 +890,43 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client)
memset(packet_buffer, 0, length);
uchar *ptr = packet_buffer;
Doors *door;
Door_Struct nd;
Door_Struct new_door;
it = door_list.begin();
while (it != door_list.end()) {
door = it->second;
if (door && (door->GetClientVersionMask() & mask_test) &&
strlen(door->GetDoorName()) > 3) {
memset(&nd, 0, sizeof(nd));
memcpy(nd.name, door->GetDoorName(), 32);
strlen(door->GetDoorName()) > 3) {
memset(&new_door, 0, sizeof(new_door));
memcpy(new_door.name, door->GetDoorName(), 32);
auto position = door->GetPosition();
nd.xPos = position.x;
nd.yPos = position.y;
nd.zPos = position.z;
nd.heading = position.w;
nd.incline = door->GetIncline();
nd.size = door->GetSize();
nd.doorId = door->GetDoorID();
nd.opentype = door->GetOpenType();
nd.state_at_spawn = door->GetInvertState() ? !door->IsDoorOpen() : door->IsDoorOpen();
nd.invert_state = door->GetInvertState();
nd.door_param = door->GetDoorParam();
memcpy(ptr, &nd, sizeof(nd));
ptr+=sizeof(nd);
*(ptr-1)=0x01;
*(ptr-3)=0x01;
new_door.xPos = position.x;
new_door.yPos = position.y;
new_door.zPos = position.z;
new_door.heading = position.w;
new_door.incline = door->GetIncline();
new_door.size = door->GetSize();
new_door.doorId = door->GetDoorID();
new_door.opentype = door->GetOpenType();
Log(Logs::General, Logs::Doors, "Door timer_disable: %s door_id: %u is_open: %s invert_state: %i",
(door->GetDisableTimer() ? "true" : "false"),
door->GetDoorID(),
(door->IsDoorOpen() ? "true" : "false"),
door->GetInvertState()
);
new_door.state_at_spawn = (door->GetInvertState() ? !door->IsDoorOpen() : door->IsDoorOpen());
new_door.invert_state = door->GetInvertState();
new_door.door_param = door->GetDoorParam();
memcpy(ptr, &new_door, sizeof(new_door));
ptr += sizeof(new_door);
*(ptr - 1) = 0x01;
*(ptr - 3) = 0x01;
}
++it;
}

View File

@ -412,7 +412,7 @@ public:
bool LimitCheckName(const char* npc_name);
void CheckClientAggro(Client *around);
Mob* AICheckCloseAggro(Mob* sender, float iAggroRange, float iAssistRange);
Mob* AICheckNPCtoNPCAggro(Mob* sender, float iAggroRange, float iAssistRange);
int GetHatedCount(Mob *attacker, Mob *exclude);
void AIYellForHelp(Mob* sender, Mob* attacker);
bool AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint32 iSpellTypes);

View File

@ -1792,7 +1792,8 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// Nothing in destination slot: split stack into two
if ((int16)move_in->number_in_stack >= src_inst->GetCharges()) {
// Move entire stack
if(!m_inv.SwapItem(src_slot_id, dst_slot_id)) { return false; }
EQEmu::InventoryProfile::SwapItemFailState fail_state = EQEmu::InventoryProfile::swapInvalid;
if (!m_inv.SwapItem(src_slot_id, dst_slot_id, fail_state)) { return false; }
Log(Logs::Detail, Logs::Inventory, "Move entire stack from %d to %d with stack size %d. Dest empty.", src_slot_id, dst_slot_id, move_in->number_in_stack);
}
else {
@ -1822,7 +1823,21 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
SetMaterial(dst_slot_id,src_inst->GetItem()->ID);
}
if(!m_inv.SwapItem(src_slot_id, dst_slot_id, GetRace(), GetClass(), GetDeity(), GetLevel())) { return false; }
EQEmu::InventoryProfile::SwapItemFailState fail_state = EQEmu::InventoryProfile::swapInvalid;
if (!m_inv.SwapItem(src_slot_id, dst_slot_id, fail_state, GetBaseRace(), GetBaseClass(), GetDeity(), GetLevel())) {
const char* fail_message = "The selected slot was invalid.";
if (fail_state == EQEmu::InventoryProfile::swapRaceClass || fail_state == EQEmu::InventoryProfile::swapDeity)
fail_message = "Your class, deity and/or race may not equip that item.";
else if (fail_state == EQEmu::InventoryProfile::swapLevel)
fail_message = "You are not sufficient level to use this item.";
if (fail_message)
Message(CC_Red, "%s", fail_message);
return false;
}
Log(Logs::Detail, Logs::Inventory, "Moving entire item from slot %d to slot %d", src_slot_id, dst_slot_id);
if (src_slot_id <= EQEmu::legacy::EQUIPMENT_END || src_slot_id == EQEmu::inventory::slotPowerSource) {

View File

@ -111,6 +111,16 @@ uint32 Lua_Door::GetOpenType() {
return self->GetOpenType();
}
void Lua_Door::SetDisableTimer(bool flag) {
Lua_Safe_Call_Void();
self->SetDisableTimer(flag);
}
bool Lua_Door::GetDisableTimer() {
Lua_Safe_Call_Bool();
return self->GetDisableTimer();
}
void Lua_Door::SetLockPick(uint32 pick) {
Lua_Safe_Call_Void();
self->SetLockpick(pick);
@ -190,6 +200,8 @@ luabind::scope lua_register_door() {
.def("GetIncline", (uint32(Lua_Door::*)(void))&Lua_Door::GetIncline)
.def("SetOpenType", (void(Lua_Door::*)(uint32))&Lua_Door::SetOpenType)
.def("GetOpenType", (uint32(Lua_Door::*)(void))&Lua_Door::GetOpenType)
.def("SetDisableTimer", (void(Lua_Door::*)(bool))&Lua_Door::SetDisableTimer)
.def("GetDisableTimer", (bool(Lua_Door::*)(void))&Lua_Door::GetDisableTimer)
.def("SetLockPick", (void(Lua_Door::*)(uint32))&Lua_Door::SetLockPick)
.def("GetLockPick", (uint32(Lua_Door::*)(void))&Lua_Door::GetLockPick)
.def("SetKeyItem", (void(Lua_Door::*)(uint32))&Lua_Door::SetKeyItem)

View File

@ -49,6 +49,8 @@ public:
uint32 GetIncline();
void SetOpenType(uint32 type);
uint32 GetOpenType();
void SetDisableTimer(bool flag);
bool GetDisableTimer();
void SetLockPick(uint32 pick);
uint32 GetLockPick();
void SetKeyItem(uint32 key);

View File

@ -1680,7 +1680,7 @@ luabind::scope lua_register_events() {
luabind::value("loot", static_cast<int>(EVENT_LOOT)),
luabind::value("zone", static_cast<int>(EVENT_ZONE)),
luabind::value("level_up", static_cast<int>(EVENT_LEVEL_UP)),
luabind::value("killed_merit ", static_cast<int>(EVENT_KILLED_MERIT )),
luabind::value("killed_merit", static_cast<int>(EVENT_KILLED_MERIT)),
luabind::value("cast_on", static_cast<int>(EVENT_CAST_ON)),
luabind::value("task_accepted", static_cast<int>(EVENT_TASK_ACCEPTED)),
luabind::value("task_stage_complete", static_cast<int>(EVENT_TASK_STAGE_COMPLETE)),

View File

@ -40,7 +40,8 @@ int Lua_Inventory::PushCursor(Lua_ItemInst item) {
bool Lua_Inventory::SwapItem(int slot_a, int slot_b) {
Lua_Safe_Call_Bool();
return self->SwapItem(slot_a, slot_b);
EQEmu::InventoryProfile::SwapItemFailState fail_state = EQEmu::InventoryProfile::swapInvalid;
return self->SwapItem(slot_a, slot_b, fail_state);
}
bool Lua_Inventory::DeleteItem(int slot_id) {

View File

@ -18,6 +18,11 @@ namespace luabind {
luabind::scope lua_register_inventory();
// This class should be deprecated due to the nature of inventory actions.
// Direct manipulation of the inventory system bypasses the client management
// of database calls and can lead to lost items, duplicated items and/or
// desync'd inventories, if not handled correctly.
class Lua_Inventory : public Lua_Ptr<EQEmu::InventoryProfile>
{
typedef EQEmu::InventoryProfile NativeType;

View File

@ -823,6 +823,11 @@ bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_use
return self->SpellFinished(spell_id, target, static_cast<EQEmu::CastingSlot>(slot), mana_used, inventory_slot, resist_adjust, proc);
}
void Lua_Mob::SendBeginCast(int spell_id, int cast_time) {
Lua_Safe_Call_Void();
self->SendBeginCast(spell_id, cast_time);
}
void Lua_Mob::SpellEffect(Lua_Mob caster, int spell_id, double partial) {
Lua_Safe_Call_Void();
self->SpellEffect(caster, spell_id, static_cast<float>(partial));
@ -2128,6 +2133,7 @@ luabind::scope lua_register_mob() {
.def("SpellFinished", (bool(Lua_Mob::*)(int,Lua_Mob,int,int,uint32))&Lua_Mob::SpellFinished)
.def("SpellFinished", (bool(Lua_Mob::*)(int,Lua_Mob,int,int,uint32,int))&Lua_Mob::SpellFinished)
.def("SpellFinished", (bool(Lua_Mob::*)(int,Lua_Mob,int,int,uint32,int,bool))&Lua_Mob::SpellFinished)
.def("SendBeginCast", &Lua_Mob::SendBeginCast)
.def("SpellEffect", &Lua_Mob::SpellEffect)
.def("GetPet", &Lua_Mob::GetPet)
.def("GetOwner", &Lua_Mob::GetOwner)

View File

@ -181,6 +181,7 @@ public:
bool SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot);
bool SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust);
bool SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust, bool proc);
void SendBeginCast(int spell_id, int cast_time);
void SpellEffect(Lua_Mob caster, int spell_id, double partial);
Lua_Mob GetPet();
Lua_Mob GetOwner();

View File

@ -279,6 +279,7 @@ public:
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
bool SpellFinished(uint16 spell_id, Mob *target, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, uint16 mana_used = 0,
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
void SendBeginCast(uint16 spell_id, uint32 casttime);
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false,
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1);

View File

@ -457,18 +457,18 @@ void Mob::AI_Start(uint32 iMoveDelay) {
AI_movement_timer = std::unique_ptr<Timer>(new Timer(AImovement_duration));
AI_target_check_timer = std::unique_ptr<Timer>(new Timer(AItarget_check_duration));
AI_feign_remember_timer = std::unique_ptr<Timer>(new Timer(AIfeignremember_delay));
AI_scan_area_timer = std::unique_ptr<Timer>(new Timer(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax))));
if(CastToNPC()->WillAggroNPCs())
AI_scan_area_timer = std::unique_ptr<Timer>(new Timer(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax))));
AI_check_signal_timer = std::unique_ptr<Timer>(new Timer(AI_check_signal_timer_delay));
#ifdef REVERSE_AGGRO
if(IsNPC() && !CastToNPC()->WillAggroNPCs())
AI_scan_area_timer->Disable();
#endif
if (GetAggroRange() == 0)
pAggroRange = 70;
if (GetAssistRange() == 0)
pAssistRange = 70;
hate_list.WipeHateList();
m_Delta = glm::vec4();
@ -1304,7 +1304,7 @@ void Mob::AI_Process() {
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive))
SendRemovePlayerState(PlayerState::Aggressive);
if(!zone->CanDoCombat() && AI_feign_remember_timer->Check()) {
if(zone->CanDoCombat() && AI_feign_remember_timer->Check()) {
// 6/14/06
// Improved Feign Death Memory
// check to see if any of our previous feigned targets have gotten up.
@ -1329,18 +1329,13 @@ void Mob::AI_Process() {
{
//we processed a spell action, so do nothing else.
}
else if (!zone->CanDoCombat() && AI_scan_area_timer->Check())
else if (zone->CanDoCombat() && CastToNPC()->WillAggroNPCs() && AI_scan_area_timer->Check())
{
/*
* This is where NPCs look around to see if they want to attack anybody.
*
* if REVERSE_AGGRO is enabled, then this timer is disabled unless they
* have the npc_aggro flag on them, and aggro against clients is checked
* by the clients.
*
* NPC to NPC aggro checking, npc needs npc_aggro flag
*/
Mob* temp_target = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange());
Mob* temp_target = entity_list.AICheckNPCtoNPCAggro(this, GetAggroRange(), GetAssistRange());
if (temp_target){
AddToHateList(temp_target);
}
@ -1415,6 +1410,7 @@ void Mob::AI_Process() {
}
}
}
/* Entity has been assigned another entity to follow */
else if (GetFollowID())
{
Mob* follow = entity_list.GetMob(GetFollowID());
@ -1458,6 +1454,7 @@ void Mob::AI_Process() {
minLastFightingDelayMoving = 0;
maxLastFightingDelayMoving = 0;
}
/* All normal NPC pathing */
CastToNPC()->AI_DoMovement();
}
}

View File

@ -374,6 +374,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
InitializeBuffSlots();
CalcBonuses();
raid_target = d->raid_target;
ignore_despawn = d->ignore_despawn;
}
NPC::~NPC()

View File

@ -417,6 +417,8 @@ public:
bool IsRaidTarget() const { return raid_target; };
void ResetHPUpdateTimer() { sendhpupdate_timer.Start(); }
bool IgnoreDespawn() { return ignore_despawn; }
protected:
const NPCType* NPCTypedata;
@ -532,6 +534,7 @@ protected:
bool raid_target;
uint8 probability;
bool ignore_despawn; //NPCs with this set to 1 will ignore the despawn value in spawngroup
private:
uint32 loottable_id;

View File

@ -208,11 +208,26 @@ bool Spawn2::Process() {
}
}
if(sg->despawn != 0 && condition_id == 0)
zone->Despawn(spawn2_id);
if(IsDespawned)
bool ignore_despawn = false;
if (npcthis)
{
ignore_despawn = npcthis->IgnoreDespawn();
}
if (ignore_despawn)
{
return true;
}
if (sg->despawn != 0 && condition_id == 0 && !ignore_despawn)
{
zone->Despawn(spawn2_id);
}
if (IsDespawned)
{
return true;
}
currentnpcid = npcid;
NPC* npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3);
@ -295,6 +310,9 @@ void Spawn2::ForceDespawn()
if(npcthis != nullptr)
{
if (npcthis->IgnoreDespawn())
return;
if(!npcthis->IsEngaged())
{
if(sg->despawn == 3 || sg->despawn == 4)

View File

@ -478,23 +478,8 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
// now tell the people in the area -- we ALWAYS want to send this, even instant cast spells.
// The only time this is skipped is for NPC innate procs and weapon procs. Procs from buffs
// oddly still send this. Since those cases don't reach here, we don't need to check them
if (slot != CastingSlot::Discipline) {
auto outapp = new EQApplicationPacket(OP_BeginCast,sizeof(BeginCast_Struct));
BeginCast_Struct* begincast = (BeginCast_Struct*)outapp->pBuffer;
begincast->caster_id = GetID();
begincast->spell_id = spell_id;
begincast->cast_time = orgcasttime; // client calculates reduced time by itself
outapp->priority = 3;
entity_list.QueueCloseClients(
this, /* Sender */
outapp, /* Packet */
false, /* Ignore Sender */
RuleI(Range, BeginCast),
0, /* Skip this Mob */
true /* Packet ACK */
); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS);
safe_delete(outapp);
}
if (slot != CastingSlot::Discipline)
SendBeginCast(spell_id, orgcasttime);
// cast time is 0, just finish it right now and be done with it
if(cast_time == 0) {
@ -537,6 +522,29 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
return(true);
}
void Mob::SendBeginCast(uint16 spell_id, uint32 casttime)
{
auto outapp = new EQApplicationPacket(OP_BeginCast, sizeof(BeginCast_Struct));
auto begincast = (BeginCast_Struct *)outapp->pBuffer;
begincast->caster_id = GetID();
begincast->spell_id = spell_id;
begincast->cast_time = casttime; // client calculates reduced time by itself
outapp->priority = 3;
entity_list.QueueCloseClients(
this, /* Sender */
outapp, /* Packet */
false, /* Ignore Sender */
RuleI(Range, BeginCast),
0, /* Skip this Mob */
true /* Packet ACK */
); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS);
safe_delete(outapp);
}
/*
* Some failures should be caught before the spell finishes casting
* This is especially helpful to clients when they cast really long things
@ -3782,11 +3790,13 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
default:
break;
}
if(reflect_chance) {
Message_StringID(MT_Spells, SPELL_REFLECT, GetCleanName(), spelltar->GetCleanName());
if (reflect_chance) {
entity_list.MessageClose_StringID(this, false, RuleI(Range, SpellMessages), MT_Spells,
SPELL_REFLECT, GetCleanName(), spelltar->GetCleanName());
CheckNumHitsRemaining(NumHit::ReflectSpell);
// caster actually appears to change
// ex. During OMM fight you click your reflect mask and you get the recourse from the reflected spell
// ex. During OMM fight you click your reflect mask and you get the recourse from the reflected
// spell
spelltar->SpellOnTarget(spell_id, this, true, use_resist_adjust, resist_adjust);
safe_delete(action_packet);
return false;

View File

@ -1966,7 +1966,8 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
"npc_types.bracertexture, "
"npc_types.handtexture, "
"npc_types.legtexture, "
"npc_types.feettexture "
"npc_types.feettexture, "
"npc_types.ignore_despawn "
"FROM npc_types %s",
where_condition.c_str()
);
@ -2141,6 +2142,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
temp_npctype_data->handtexture = atoi(row[94]);
temp_npctype_data->legtexture = atoi(row[95]);
temp_npctype_data->feettexture = atoi(row[96]);
temp_npctype_data->ignore_despawn = atoi(row[97]) == 1 ? true : false;
// If NPC with duplicate NPC id already in table,
// free item we attempted to add.
@ -2987,16 +2989,16 @@ void ZoneDatabase::QGlobalPurge()
database.QueryDatabase(query);
}
void ZoneDatabase::InsertDoor(uint32 ddoordbid, uint16 ddoorid, const char* ddoor_name, const glm::vec4& position, uint8 dopentype, uint16 dguildid, uint32 dlockpick, uint32 dkeyitem, uint8 ddoor_param, uint8 dinvert, int dincline, uint16 dsize){
void ZoneDatabase::InsertDoor(uint32 ddoordbid, uint16 ddoorid, const char* ddoor_name, const glm::vec4& position, uint8 dopentype, uint16 dguildid, uint32 dlockpick, uint32 dkeyitem, uint8 ddoor_param, uint8 dinvert, int dincline, uint16 dsize, bool ddisabletimer){
std::string query = StringFormat("REPLACE INTO doors (id, doorid, zone, version, name, "
"pos_x, pos_y, pos_z, heading, opentype, guild, lockpick, "
"keyitem, door_param, invert_state, incline, size) "
"keyitem, disable_timer, door_param, invert_state, incline, size) "
"VALUES('%i', '%i', '%s', '%i', '%s', '%f', '%f', "
"'%f', '%f', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i')",
"'%f', '%f', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i')",
ddoordbid, ddoorid, zone->GetShortName(), zone->GetInstanceVersion(),
ddoor_name, position.x, position.y, position.z, position.w,
dopentype, dguildid, dlockpick, dkeyitem, ddoor_param, dinvert, dincline, dsize);
dopentype, dguildid, dlockpick, dkeyitem, (ddisabletimer ? 1 : 0), ddoor_param, dinvert, dincline, dsize);
QueryDatabase(query);
}

View File

@ -454,7 +454,7 @@ public:
int32 GetDoorsCount(uint32* oMaxID, const char *zone_name, int16 version);
int32 GetDoorsCountPlusOne(const char *zone_name, int16 version);
int32 GetDoorsDBCountPlusOne(const char *zone_name, int16 version);
void InsertDoor(uint32 did, uint16 ddoorid, const char* ddoor_name, const glm::vec4& position, uint8 dopentype, uint16 dguildid, uint32 dlockpick, uint32 dkeyitem, uint8 ddoor_param, uint8 dinvert, int dincline, uint16 dsize);
void InsertDoor(uint32 did, uint16 ddoorid, const char* ddoor_name, const glm::vec4& position, uint8 dopentype, uint16 dguildid, uint32 dlockpick, uint32 dkeyitem, uint8 ddoor_param, uint8 dinvert, int dincline, uint16 dsize, bool ddisabletimer = false);
/* Blocked Spells */
int32 GetBlockedSpellsCount(uint32 zoneid);

View File

@ -132,6 +132,7 @@ struct NPCType
uint8 handtexture;
uint8 legtexture;
uint8 feettexture;
bool ignore_despawn;
};
namespace player_lootitem {
@ -201,6 +202,7 @@ struct Door {
uint8 nokeyring;
uint8 trigger_door;
uint8 trigger_type;
uint8 disable_timer;
uint32 door_param;
int invert_state;
uint16 size;