From 56e86ff05fa96824edaea3f04bdbbbaa0d164129 Mon Sep 17 00:00:00 2001 From: NoFantasy Date: Tue, 26 May 2009 18:08:34 +0400 Subject: [PATCH 1/8] [7896] Rename creature_template class/race fields to trainer_class/trainer_race for clarify use. Signed-off-by: VladimirMangos --- sql/mangos.sql | 6 +++--- sql/updates/7896_01_mangos_creature_template.sql | 4 ++++ sql/updates/Makefile.am | 2 ++ src/game/Creature.cpp | 12 ++++++------ src/game/Creature.h | 4 ++-- src/game/ObjectMgr.cpp | 8 ++++---- src/shared/revision_nr.h | 2 +- 7 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 sql/updates/7896_01_mangos_creature_template.sql diff --git a/sql/mangos.sql b/sql/mangos.sql index 697d93713..2cff642fe 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, - `required_7893_01_mangos_command` bit(1) default NULL + `required_7896_01_mangos_creature_template` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -820,8 +820,8 @@ CREATE TABLE `creature_template` ( `family` tinyint(4) NOT NULL default '0', `trainer_type` tinyint(4) NOT NULL default '0', `trainer_spell` mediumint(8) unsigned NOT NULL default '0', - `class` tinyint(3) unsigned NOT NULL default '0', - `race` tinyint(3) unsigned NOT NULL default '0', + `trainer_class` tinyint(3) unsigned NOT NULL default '0', + `trainer_race` tinyint(3) unsigned NOT NULL default '0', `minrangedmg` float NOT NULL default '0', `maxrangedmg` float NOT NULL default '0', `rangedattackpower` smallint(5) unsigned NOT NULL default '0', diff --git a/sql/updates/7896_01_mangos_creature_template.sql b/sql/updates/7896_01_mangos_creature_template.sql new file mode 100644 index 000000000..511460958 --- /dev/null +++ b/sql/updates/7896_01_mangos_creature_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_7893_01_mangos_command required_7896_01_mangos_creature_template bit; + +ALTER TABLE creature_template CHANGE COLUMN class trainer_class tinyint(3) unsigned NOT NULL default '0'; +ALTER TABLE creature_template CHANGE COLUMN race trainer_race tinyint(3) unsigned NOT NULL default '0'; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 3470dcb72..4930f8ffa 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -200,6 +200,7 @@ pkgdata_DATA = \ 7886_01_mangos_petcreateinfo_spell.sql \ 7887_01_characters_character_pet.sql \ 7893_01_mangos_command.sql \ + 7896_01_mangos_creature_template.sql \ README ## Additional files to include when running 'make dist' @@ -380,4 +381,5 @@ EXTRA_DIST = \ 7886_01_mangos_petcreateinfo_spell.sql \ 7887_01_characters_character_pet.sql \ 7893_01_mangos_command.sql \ + 7896_01_mangos_creature_template.sql \ README diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index ab3eec386..7c6cbdb6c 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -605,12 +605,12 @@ bool Creature::isCanTrainingOf(Player* pPlayer, bool msg) const switch(GetCreatureInfo()->trainer_type) { case TRAINER_TYPE_CLASS: - if(pPlayer->getClass()!=GetCreatureInfo()->classNum) + if(pPlayer->getClass()!=GetCreatureInfo()->trainer_class) { if(msg) { pPlayer->PlayerTalkClass->ClearMenus(); - switch(GetCreatureInfo()->classNum) + switch(GetCreatureInfo()->trainer_class) { case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu( 4913,GetGUID()); break; case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090,GetGUID()); break; @@ -635,12 +635,12 @@ bool Creature::isCanTrainingOf(Player* pPlayer, bool msg) const } break; case TRAINER_TYPE_MOUNTS: - if(GetCreatureInfo()->race && pPlayer->getRace() != GetCreatureInfo()->race) + if(GetCreatureInfo()->trainer_race && pPlayer->getRace() != GetCreatureInfo()->trainer_race) { if(msg) { pPlayer->PlayerTalkClass->ClearMenus(); - switch(GetCreatureInfo()->classNum) + switch(GetCreatureInfo()->trainer_class) { case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865,GetGUID()); break; case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881,GetGUID()); break; @@ -710,7 +710,7 @@ bool Creature::isCanTrainingAndResetTalentsOf(Player* pPlayer) const { return pPlayer->getLevel() >= 10 && GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS - && pPlayer->getClass() == GetCreatureInfo()->classNum; + && pPlayer->getClass() == GetCreatureInfo()->trainer_class; } void Creature::prepareGossipMenu( Player *pPlayer,uint32 gossipid ) @@ -771,7 +771,7 @@ void Creature::prepareGossipMenu( Player *pPlayer,uint32 gossipid ) cantalking=false; break; case GOSSIP_OPTION_UNLEARNPETSKILLS: - if(!pPlayer->GetPet() || pPlayer->GetPet()->getPetType() != HUNTER_PET || pPlayer->GetPet()->m_spells.size() <= 1 || GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || GetCreatureInfo()->classNum != CLASS_HUNTER) + if(!pPlayer->GetPet() || pPlayer->GetPet()->getPetType() != HUNTER_PET || pPlayer->GetPet()->m_spells.size() <= 1 || GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || GetCreatureInfo()->trainer_class != CLASS_HUNTER) cantalking=false; break; case GOSSIP_OPTION_TAXIVENDOR: diff --git a/src/game/Creature.h b/src/game/Creature.h index 5f0c54a95..70b1d771c 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -188,8 +188,8 @@ struct CreatureInfo uint32 family; // enum CreatureFamily values (optional) uint32 trainer_type; uint32 trainer_spell; - uint32 classNum; - uint32 race; + uint32 trainer_class; + uint32 trainer_race; float minrangedmg; float maxrangedmg; uint32 rangedattackpower; diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 2f76bd391..2c0662fe6 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -496,15 +496,15 @@ void ObjectMgr::LoadCreatureTemplates() continue; } - if(cInfo->classNum != heroicInfo->classNum) + if(cInfo->trainer_class != heroicInfo->trainer_class) { - sLog.outErrorDb("Creature (Entry: %u) has different `classNum` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); continue; } - if(cInfo->race != heroicInfo->race) + if(cInfo->trainer_race != heroicInfo->trainer_race) { - sLog.outErrorDb("Creature (Entry: %u) has different `race` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); continue; } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 72f6803f3..05a8b3ec0 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7895" + #define REVISION_NR "7896" #endif // __REVISION_NR_H__ From 83b2eb2bba4b0277b56d39d3e2e5ad0bde4a4fb4 Mon Sep 17 00:00:00 2001 From: Ambal Date: Tue, 26 May 2009 21:58:56 +0400 Subject: [PATCH 2/8] [7897] Include function name in assertion fail output. Signed-off-by: VladimirMangos --- src/shared/Errors.h | 8 ++++---- src/shared/revision_nr.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shared/Errors.h b/src/shared/Errors.h index 546da27b1..06bcc8823 100644 --- a/src/shared/Errors.h +++ b/src/shared/Errors.h @@ -19,11 +19,11 @@ #ifndef MANGOSSERVER_ERRORS_H #define MANGOSSERVER_ERRORS_H -#define WPAssert( assertion ) { if( !(assertion) ) { fprintf( stderr, "\n%s:%i ASSERTION FAILED:\n %s\n", __FILE__, __LINE__, #assertion ); assert( #assertion &&0 ); } } -#define WPError( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%s:%i ERROR:\n %s\n", __FILE__, __LINE__, (char *)errmsg ); assert( false ); } -#define WPWarning( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%s:%i WARNING:\n %s\n", __FILE__, __LINE__, (char *)errmsg ); } +#define WPAssert( assertion ) { if( !(assertion) ) { fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n", __FILE__, __LINE__,__FUNCTION__, #assertion ); assert( #assertion &&0 ); } } +#define WPError( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%\n%s:%i in %s ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); assert( false ); } +#define WPWarning( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "\n%s:%i in %s WARNING:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); } -#define WPFatal( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%s:%i FATAL ERROR:\n %s\n", __FILE__, __LINE__, (char *)errmsg ); assert( #assertion &&0 ); abort(); } +#define WPFatal( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "\n%s:%i in %s FATAL ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); assert( #assertion &&0 ); abort(); } #define ASSERT WPAssert #endif diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 05a8b3ec0..d9d4874a2 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7896" + #define REVISION_NR "7897" #endif // __REVISION_NR_H__ From d2e25491a2d940ed2bbe7135a057ba15539d2681 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Wed, 27 May 2009 01:12:44 +0400 Subject: [PATCH 3/8] [7898] Improve client error output at different mail send errors, cleanup code. --- src/game/Item.cpp | 10 ++++----- src/game/Item.h | 7 +++++-- src/game/ItemPrototype.h | 4 ++-- src/game/Mail.cpp | 44 ++++++++++++++++++++++++---------------- src/game/Mail.h | 24 ---------------------- src/game/Player.cpp | 6 +++--- src/game/Player.h | 2 +- src/game/SharedDefines.h | 28 +++++++++++++++++++++++++ src/shared/revision_nr.h | 2 +- 9 files changed, 72 insertions(+), 55 deletions(-) diff --git a/src/game/Item.cpp b/src/game/Item.cpp index 2d25b7f0f..283036785 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -698,16 +698,16 @@ bool Item::IsEquipped() const bool Item::CanBeTraded() const { - if(IsSoulBound()) + if (IsSoulBound()) return false; - if(IsBag() && (Player::IsBagPos(GetPos()) || !((Bag const*)this)->IsEmpty()) ) + if (IsBag() && (Player::IsBagPos(GetPos()) || !((Bag const*)this)->IsEmpty()) ) return false; - if(Player* owner = GetOwner()) + if (Player* owner = GetOwner()) { - if(owner->CanUnequipItem(GetPos(),false) != EQUIP_ERR_OK ) + if (owner->CanUnequipItem(GetPos(),false) != EQUIP_ERR_OK ) return false; - if(owner->GetLootGUID()==GetGUID()) + if (owner->GetLootGUID()==GetGUID()) return false; } diff --git a/src/game/Item.h b/src/game/Item.h index 2f7376aae..3d3d3bb48 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -116,8 +116,11 @@ enum InventoryChangeFailure EQUIP_ERR_TOO_MUCH_GOLD = 77, EQUIP_ERR_NOT_DURING_ARENA_MATCH = 78, EQUIP_ERR_CANNOT_TRADE_THAT = 79, - EQUIP_ERR_PERSONAL_ARENA_RATING_TOO_LOW = 80 - // probably exist more + EQUIP_ERR_PERSONAL_ARENA_RATING_TOO_LOW = 80, + // no output = 81, + EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS = 82, + // no output = 83, + // crash client = 84, }; enum BuyFailure diff --git a/src/game/ItemPrototype.h b/src/game/ItemPrototype.h index ba578c7d7..70f33021e 100644 --- a/src/game/ItemPrototype.h +++ b/src/game/ItemPrototype.h @@ -101,7 +101,7 @@ enum ItemBondingType // masks for ITEM_FIELD_FLAGS field enum ITEM_FLAGS { - ITEM_FLAGS_BINDED = 0x00000001, + ITEM_FLAGS_BINDED = 0x00000001, // set in game at binding, not set in template ITEM_FLAGS_CONJURED = 0x00000002, ITEM_FLAGS_OPENABLE = 0x00000004, ITEM_FLAGS_WRAPPED = 0x00000008, @@ -114,7 +114,7 @@ enum ITEM_FLAGS ITEM_FLAGS_USEABLE_IN_ARENA = 0x00200000, ITEM_FLAGS_THROWABLE = 0x00400000, // not used in game for check trow possibility, only for item in game tooltip ITEM_FLAGS_SPECIALUSE = 0x00800000, // last used flag in 2.3.0 - ITEM_FLAGS_BOA = 0x08000000, // bind on account + ITEM_FLAGS_BOA = 0x08000000, // bind on account (set in template for items that can binded in like way) ITEM_FLAGS_MILLABLE = 0x20000000 }; diff --git a/src/game/Mail.cpp b/src/game/Mail.cpp index d671aeb69..e39c85222 100644 --- a/src/game/Mail.cpp +++ b/src/game/Mail.cpp @@ -77,7 +77,10 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) recv_data >> items_count; // attached items count if(items_count > 12) // client limit + { + GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); return; + } // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+(subject.size()+1)+(body.size()+1)+4+4+1+items_count*(1+8)+4+4+8+1); @@ -113,7 +116,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) { sLog.outDetail("Player %u is sending mail to %s (GUID: not existed!) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); - pl->SendMailResult(0, 0, MAIL_ERR_RECIPIENT_NOT_FOUND); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } @@ -121,7 +124,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) if(pl->GetGUID() == rc) { - pl->SendMailResult(0, 0, MAIL_ERR_CANNOT_SEND_TO_SELF); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } @@ -131,7 +134,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) if (pl->GetMoney() < reqmoney) { - pl->SendMailResult(0, 0, MAIL_ERR_NOT_ENOUGH_MONEY); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } @@ -159,13 +162,13 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) //do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mails_count > 100) { - pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // test the receiver's Faction... if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && GetSecurity() == SEC_PLAYER) { - pl->SendMailResult(0, 0, MAIL_ERR_NOT_YOUR_TEAM); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } @@ -177,31 +180,38 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) if(!mailItem.item_guidlow) { - pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } mailItem.item = pl->GetItemByGuid(MAKE_NEW_GUID(mailItem.item_guidlow, 0, HIGHGUID_ITEM)); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) - if(!mailItem.item || !mailItem.item->CanBeTraded()) + if(!mailItem.item) { - pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } + + if(!mailItem.item->CanBeTraded()) + { + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); + return; + } + if (mailItem.item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || mailItem.item->GetUInt32Value(ITEM_FIELD_DURATION)) { - pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if(COD && mailItem.item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) { - pl->SendMailResult(0, 0, MAIL_ERR_CANT_SEND_WRAPPED_COD); + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } } } - pl->SendMailResult(0, 0, MAIL_OK); + pl->SendMailResult(0, MAIL_SEND, MAIL_OK); uint32 itemTextId = 0; if (!body.empty()) @@ -313,7 +323,7 @@ void WorldSession::HandleMailDelete(WorldPacket & recv_data ) Mail *m = pl->GetMail(mailId); if(m) m->state = MAIL_STATE_DELETED; - pl->SendMailResult(mailId, MAIL_DELETED, 0); + pl->SendMailResult(mailId, MAIL_DELETED, MAIL_OK); } void WorldSession::HandleReturnToSender(WorldPacket & recv_data ) @@ -365,7 +375,7 @@ void WorldSession::HandleReturnToSender(WorldPacket & recv_data ) SendReturnToSender(MAIL_NORMAL, GetAccountId(), m->receiver, m->sender, m->subject, m->itemTextId, &mi, m->money, m->mailTemplateId); delete m; //we can deallocate old mail - pl->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, 0); + pl->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK); } void WorldSession::SendReturnToSender(uint8 messageType, uint32 sender_acc, uint32 sender_guid, uint32 receiver_guid, const std::string& subject, uint32 itemTextId, MailItemsInfo *mi, uint32 money, uint16 mailTemplateId ) @@ -508,7 +518,7 @@ void WorldSession::HandleTakeItem(WorldPacket & recv_data ) pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count); } else - pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_BAG_FULL, msg); + pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); } void WorldSession::HandleTakeMoney(WorldPacket & recv_data ) @@ -532,7 +542,7 @@ void WorldSession::HandleTakeMoney(WorldPacket & recv_data ) return; } - pl->SendMailResult(mailId, MAIL_MONEY_TAKEN, 0); + pl->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); pl->ModifyMoney(m->money); m->money = 0; @@ -725,11 +735,11 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket & recv_data ) pl->StoreItem(dest, bodyItem, true); //bodyItem->SetState(ITEM_NEW, pl); is set automatically - pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, 0); + pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK); } else { - pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_BAG_FULL, msg); + pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg); delete bodyItem; } } diff --git a/src/game/Mail.h b/src/game/Mail.h index ba223a890..7f7398da8 100644 --- a/src/game/Mail.h +++ b/src/game/Mail.h @@ -26,30 +26,6 @@ class Item; #define MAIL_BODY_ITEM_TEMPLATE 8383 // - plain letter, A Dusty Unsent Letter: 889 #define MAX_MAIL_ITEMS 12 -enum MAIL_RESPONSE -{ - MAIL_OK = 0, - MAIL_MONEY_TAKEN = 1, - MAIL_ITEM_TAKEN = 2, - MAIL_RETURNED_TO_SENDER = 3, - MAIL_DELETED = 4, - MAIL_MADE_PERMANENT = 5 -}; - -enum MAIL_ERRORS -{ - MAIL_ERR_BAG_FULL = 1, - MAIL_ERR_CANNOT_SEND_TO_SELF = 2, - MAIL_ERR_NOT_ENOUGH_MONEY = 3, - MAIL_ERR_RECIPIENT_NOT_FOUND = 4, - MAIL_ERR_NOT_YOUR_TEAM = 5, - MAIL_ERR_INTERNAL_ERROR = 6, - MAIL_ERR_DISABLED_FOR_TRIAL_ACC = 14, - MAIL_ERR_RECIPIENT_CAP_REACHED = 15, - MAIL_ERR_CANT_SEND_WRAPPED_COD = 16, - MAIL_ERR_MAIL_AND_CHAT_SUSPENDED = 17 -}; - enum MailCheckMask { MAIL_CHECK_MASK_NONE = 0, diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 49ac6de9a..81cd7ee3e 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2598,13 +2598,13 @@ void Player::RemoveMail(uint32 id) } } -void Player::SendMailResult(uint32 mailId, uint32 mailAction, uint32 mailError, uint32 equipError, uint32 item_guid, uint32 item_count) +void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError, uint32 item_guid, uint32 item_count) { - WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(mailError == MAIL_ERR_BAG_FULL?4:(mailAction == MAIL_ITEM_TAKEN?4+4:0)))); + WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(mailError == MAIL_ERR_EQUIP_ERROR?4:(mailAction == MAIL_ITEM_TAKEN?4+4:0)))); data << (uint32) mailId; data << (uint32) mailAction; data << (uint32) mailError; - if ( mailError == MAIL_ERR_BAG_FULL ) + if ( mailError == MAIL_ERR_EQUIP_ERROR ) data << (uint32) equipError; else if( mailAction == MAIL_ITEM_TAKEN ) { diff --git a/src/game/Player.h b/src/game/Player.h index 2478616a2..5c4dd2dc5 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1297,7 +1297,7 @@ class MANGOS_DLL_SPEC Player : public Unit void ClearComboPoints(); void SendComboPoints(); - void SendMailResult(uint32 mailId, uint32 mailAction, uint32 mailError, uint32 equipError = 0, uint32 item_guid = 0, uint32 item_count = 0); + void SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError = 0, uint32 item_guid = 0, uint32 item_count = 0); void SendNewMail(); void UpdateNextMailTimeAndUnreads(); void AddNewMailDeliverTime(time_t deliver_time); diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 54ff80ae5..f8a92c386 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -2512,4 +2512,32 @@ enum BattleGroundTypeId }; #define MAX_BATTLEGROUND_TYPE_ID 12 +enum MailResponseType +{ + MAIL_SEND = 0, + MAIL_MONEY_TAKEN = 1, + MAIL_ITEM_TAKEN = 2, + MAIL_RETURNED_TO_SENDER = 3, + MAIL_DELETED = 4, + MAIL_MADE_PERMANENT = 5 +}; + +enum MailResponseResult +{ + MAIL_OK = 0, + MAIL_ERR_EQUIP_ERROR = 1, + MAIL_ERR_CANNOT_SEND_TO_SELF = 2, + MAIL_ERR_NOT_ENOUGH_MONEY = 3, + MAIL_ERR_RECIPIENT_NOT_FOUND = 4, + MAIL_ERR_NOT_YOUR_TEAM = 5, + MAIL_ERR_INTERNAL_ERROR = 6, + MAIL_ERR_DISABLED_FOR_TRIAL_ACC = 14, + MAIL_ERR_RECIPIENT_CAP_REACHED = 15, + MAIL_ERR_CANT_SEND_WRAPPED_COD = 16, + MAIL_ERR_MAIL_AND_CHAT_SUSPENDED = 17, + MAIL_ERR_TOO_MANY_ATTACHMENTS = 18, + MAIL_ERR_MAIL_ATTACHMENT_INVALID = 19, + MAIL_ERR_ITEM_HAS_EXPIRED = 21, +}; + #endif diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index d9d4874a2..22028cd51 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7897" + #define REVISION_NR "7898" #endif // __REVISION_NR_H__ From ba1d0684dafe8cc3b4be0ed416e6df3bf4c2ac01 Mon Sep 17 00:00:00 2001 From: GriffonHeart Date: Wed, 27 May 2009 01:44:40 +0400 Subject: [PATCH 4/8] [7899] Implement binding for account items support. Signed-off-by: VladimirMangos --- src/game/Item.cpp | 5 +++-- src/game/Item.h | 4 ++-- src/game/Mail.cpp | 20 +++++++++++++------- src/shared/revision_nr.h | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/game/Item.cpp b/src/game/Item.cpp index 283036785..d508b6dbd 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -696,10 +696,11 @@ bool Item::IsEquipped() const return !IsInBag() && m_slot < EQUIPMENT_SLOT_END; } -bool Item::CanBeTraded() const +bool Item::CanBeTraded(bool mail) const { - if (IsSoulBound()) + if ((!mail || !IsBoundAccountWide()) && IsSoulBound()) return false; + if (IsBag() && (Player::IsBagPos(GetPos()) || !((Bag const*)this)->IsEmpty()) ) return false; diff --git a/src/game/Item.h b/src/game/Item.h index 3d3d3bb48..03209ec51 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -215,7 +215,7 @@ class MANGOS_DLL_SPEC Item : public Object void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS,ITEM_FLAGS_BINDED,val); } bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BINDED); } - bool IsAccountBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BOA); } + bool IsBoundAccountWide() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BOA); } bool IsBindedNotWith(uint64 guid) const { return IsSoulBound() && GetOwnerGUID()!= guid; } bool IsBoundByEnchant() const; virtual void SaveToDB(); @@ -225,7 +225,7 @@ class MANGOS_DLL_SPEC Item : public Object bool IsBag() const { return GetProto()->InventoryType == INVTYPE_BAG; } bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; } - bool CanBeTraded() const; + bool CanBeTraded(bool mail = false) const; void SetInTrade(bool b = true) { mb_in_trade = b; } bool IsInTrade() const { return mb_in_trade; } diff --git a/src/game/Mail.cpp b/src/game/Mail.cpp index e39c85222..34134ebaf 100644 --- a/src/game/Mail.cpp +++ b/src/game/Mail.cpp @@ -172,6 +172,12 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) return; } + uint32 rc_account = 0; + if(receive) + rc_account = receive->GetSession()->GetAccountId(); + else + rc_account = objmgr.GetPlayerAccountIdByGUID(rc); + if (items_count) { for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter) @@ -192,12 +198,18 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) return; } - if(!mailItem.item->CanBeTraded()) + if(!mailItem.item->CanBeTraded(true)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } + if(mailItem.item->IsBoundAccountWide() && mailItem.item->IsSoulBound() && pl->GetSession()->GetAccountId() != rc_account) + { + pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); + return; + } + if (mailItem.item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || mailItem.item->GetUInt32Value(ITEM_FIELD_DURATION)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); @@ -226,12 +238,6 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) if(items_count > 0 || money > 0) { - uint32 rc_account = 0; - if(receive) - rc_account = receive->GetSession()->GetAccountId(); - else - rc_account = objmgr.GetPlayerAccountIdByGUID(rc); - if (items_count > 0) { for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 22028cd51..87fee4bd4 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7898" + #define REVISION_NR "7899" #endif // __REVISION_NR_H__ From 1abe4c0d79df6da3e8f7a4cee8022939e776a14f Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Wed, 27 May 2009 10:53:02 +0400 Subject: [PATCH 5/8] [7900] Now really allow recieve account bounded items by mail reciver. --- src/game/Item.cpp | 26 ++++++++++++++++++++++++++ src/game/Item.h | 2 +- src/game/Player.cpp | 10 +++++----- src/shared/revision_nr.h | 2 +- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/game/Item.cpp b/src/game/Item.cpp index d508b6dbd..5d595e323 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -942,3 +942,29 @@ Item* Item::CloneItem( uint32 count, Player const* player ) const newItem->SetItemRandomProperties(GetItemRandomPropertyId()); return newItem; } + +bool Item::IsBindedNotWith( Player const* player ) const +{ + // not binded item + if(!IsSoulBound()) + return false; + + // own item + if(GetOwnerGUID()== player->GetGUID()) + return false; + + // not BOA item case + if(!IsBoundAccountWide()) + return true; + + // online + if(Player* owner = objmgr.GetPlayer(GetOwnerGUID())) + { + return owner->GetSession()->GetAccountId() != player->GetSession()->GetAccountId(); + } + // offline slow case + else + { + return objmgr.GetPlayerAccountIdByGUID(GetOwnerGUID()) != player->GetSession()->GetAccountId(); + } +} \ No newline at end of file diff --git a/src/game/Item.h b/src/game/Item.h index 03209ec51..b13fcf568 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -216,7 +216,7 @@ class MANGOS_DLL_SPEC Item : public Object void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS,ITEM_FLAGS_BINDED,val); } bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BINDED); } bool IsBoundAccountWide() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BOA); } - bool IsBindedNotWith(uint64 guid) const { return IsSoulBound() && GetOwnerGUID()!= guid; } + bool IsBindedNotWith(Player const* player) const; bool IsBoundByEnchant() const; virtual void SaveToDB(); virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result = NULL); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 81cd7ee3e..88725e0be 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -8892,7 +8892,7 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND; } - if(pItem && pItem->IsBindedNotWith(GetGUID())) + if(pItem && pItem->IsBindedNotWith(this)) { if(no_space_count) *no_space_count = count; @@ -9375,7 +9375,7 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const return EQUIP_ERR_ITEM_NOT_FOUND; // item it 'bind' - if(pItem->IsBindedNotWith(GetGUID())) + if(pItem->IsBindedNotWith(this)) return EQUIP_ERR_DONT_OWN_THAT_ITEM; Bag *pBag; @@ -9577,7 +9577,7 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo ItemPrototype const *pProto = pItem->GetProto(); if( pProto ) { - if(pItem->IsBindedNotWith(GetGUID())) + if(pItem->IsBindedNotWith(this)) return EQUIP_ERR_DONT_OWN_THAT_ITEM; // check count of items (skip for auto move for same player from bank) @@ -9750,7 +9750,7 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p if (!pProto) return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; - if (pItem->IsBindedNotWith(GetGUID())) + if (pItem->IsBindedNotWith(this)) return EQUIP_ERR_DONT_OWN_THAT_ITEM; // check count of items (skip for auto move for same player from bank) @@ -9930,7 +9930,7 @@ uint8 Player::CanUseItem( Item *pItem, bool not_loading ) const ItemPrototype const *pProto = pItem->GetProto(); if (pProto) { - if (pItem->IsBindedNotWith(GetGUID())) + if (pItem->IsBindedNotWith(this)) return EQUIP_ERR_DONT_OWN_THAT_ITEM; if ((pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 87fee4bd4..b38946ae9 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7899" + #define REVISION_NR "7900" #endif // __REVISION_NR_H__ From 4d8adefe70bb89bef0b91516794685dfce4981ba Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Wed, 27 May 2009 19:24:12 +0400 Subject: [PATCH 6/8] [7901] Refactoting pet action bar related code. Fixed some related bugs. * Correctly update action bar at loading and other cases when listed unlearned/not existed spells * Avoid send data by PetSpellInitialize() many times while pet loading --- src/game/Pet.cpp | 79 ++++++++++++------------ src/game/Pet.h | 7 ++- src/game/PetHandler.cpp | 15 +++-- src/game/Player.cpp | 15 +---- src/game/Unit.cpp | 127 +++++++++++++++++++++++++++------------ src/game/Unit.h | 52 +++++++++------- src/shared/revision_nr.h | 2 +- 7 files changed, 175 insertions(+), 122 deletions(-) diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index c68bb21a5..9244736c2 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -240,23 +240,11 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool if (!is_temporary_summoned) { - // permanent controlled pets store state in DB - Tokens tokens = StrSplit(fields[14].GetString(), " "); - - if (tokens.size() != 20) + if(!m_charmInfo->LoadActionBar(fields[14].GetCppString())) { delete result; return false; } - - int index; - Tokens::iterator iter; - for(iter = tokens.begin(), index = 0; index < 10; ++iter, ++index ) - { - m_charmInfo->GetActionBarEntry(index)->Type = atol((*iter).c_str()); - ++iter; - m_charmInfo->GetActionBarEntry(index)->SpellOrAction = atol((*iter).c_str()); - } } // since last save (in seconds) @@ -299,6 +287,10 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool // Spells should be loaded after pet is added to map, because in CheckCast is check on it _LoadSpells(); + InitLevelupSpellsForLevel(); + + CleanupActionBar(); // remove unknown spells from action bar after load + _LoadSpellCooldowns(); owner->SetPet(this); // in DB stored only full controlled creature @@ -329,8 +321,6 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool } } - InitLevelupSpellsForLevel(); - m_loading = false; SynchronizeLevelWithOwner(); @@ -421,8 +411,12 @@ void Pet::SavePetToDB(PetSaveMode mode) << curmana << ", " << GetPower(POWER_HAPPINESS) << ", '"; - for(uint32 i = 0; i < 10; ++i) - ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; + for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " + << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; + }; + ss << "', " << time(NULL) << ", " << uint32(m_resetTalentsCost) << ", " @@ -1337,7 +1331,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel // skip unknown ranks if(!HasSpell(rankSpellId)) continue; - removeSpell(rankSpellId,false); + removeSpell(rankSpellId,false,false); } } } @@ -1358,7 +1352,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel ToggleAutocast(itr2->first, false); oldspell_id = itr2->first; - unlearnSpell(itr2->first,false); + unlearnSpell(itr2->first,false,false); break; } // ignore new lesser rank @@ -1373,7 +1367,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel if (IsPassiveSpell(spell_id)) CastSpell(this, spell_id, true); else - m_charmInfo->AddSpellToAB(oldspell_id, spell_id); + m_charmInfo->AddSpellToActionBar(spell_id); if(newspell.active == ACT_ENABLED) ToggleAutocast(spell_id, true); @@ -1396,16 +1390,17 @@ bool Pet::learnSpell(uint32 spell_id) if (!addSpell(spell_id)) return false; - Unit* owner = GetOwner(); - if(owner && owner->GetTypeId() == TYPEID_PLAYER) + if(!m_loading) { - if(!m_loading) + Unit* owner = GetOwner(); + if(owner && owner->GetTypeId() == TYPEID_PLAYER) { WorldPacket data(SMSG_PET_LEARNED_SPELL, 2); data << uint16(spell_id); ((Player*)owner)->GetSession()->SendPacket(&data); + + ((Player*)owner)->PetSpellInitialize(); } - ((Player*)owner)->PetSpellInitialize(); } return true; } @@ -1441,7 +1436,7 @@ void Pet::InitLevelupSpellsForLevel() // will called first if level down if(spellEntry->spellLevel > level) - unlearnSpell(spellEntry->Id,false); + unlearnSpell(spellEntry->Id,true); // will called if level up else learnSpell(spellEntry->Id); @@ -1449,9 +1444,9 @@ void Pet::InitLevelupSpellsForLevel() } } -bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev) +bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab) { - if(removeSpell(spell_id,learn_prev)) + if(removeSpell(spell_id,learn_prev,clear_ab)) { if(GetOwner()->GetTypeId() == TYPEID_PLAYER) { @@ -1467,7 +1462,7 @@ bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev) return false; } -bool Pet::removeSpell(uint32 spell_id, bool learn_prev) +bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab) { PetSpellMap::iterator itr = m_spells.find(spell_id); if (itr == m_spells.end()) @@ -1498,29 +1493,35 @@ bool Pet::removeSpell(uint32 spell_id, bool learn_prev) if (learn_prev) { if (uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id)) - { - // replace to next spell - if(!talentCost && !IsPassiveSpell(prev_id)) - m_charmInfo->AddSpellToAB(spell_id, prev_id); - learnSpell(prev_id); - } else learn_prev = false; } // if remove last rank or non-ranked then update action bar at server and client if need - if(!learn_prev && m_charmInfo->AddSpellToAB(spell_id, 0)) + if (clear_ab && !learn_prev && m_charmInfo->RemoveSpellFromActionBar(spell_id)) { - // need update action bar for last removed rank - if (Unit* owner = GetOwner()) - if (owner->GetTypeId() == TYPEID_PLAYER) - ((Player*)owner)->PetSpellInitialize(); + if(!m_loading) + { + // need update action bar for last removed rank + if (Unit* owner = GetOwner()) + if (owner->GetTypeId() == TYPEID_PLAYER) + ((Player*)owner)->PetSpellInitialize(); + } } return true; } + +void Pet::CleanupActionBar() +{ + for(int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + if(UnitActionBarEntry const* ab = m_charmInfo->GetActionBarEntry(i)) + if(ab->SpellOrAction && ab->IsActionBarForSpell() && !HasSpell(ab->SpellOrAction)) + m_charmInfo->SetActionBar(i,0,ACT_DISABLED); +} + void Pet::InitPetCreateSpells() { m_charmInfo->InitPetActionBar(); diff --git a/src/game/Pet.h b/src/game/Pet.h index f8de3ed5e..510738731 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -198,8 +198,9 @@ class Pet : public Creature bool learnSpell(uint32 spell_id); void learnSpellHighRank(uint32 spellid); void InitLevelupSpellsForLevel(); - bool unlearnSpell(uint32 spell_id, bool learn_prev); - bool removeSpell(uint32 spell_id, bool learn_prev); + bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); + bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); + void CleanupActionBar(); PetSpellMap m_spells; AutoSpellList m_autospells; @@ -248,4 +249,4 @@ class Pet : public Creature assert(false); } }; -#endif +#endif \ No newline at end of file diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index eecc938ed..82930fee7 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -357,7 +357,11 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state); - //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add + //ignore invalid position + if(position >= MAX_UNIT_ACTION_BAR_INDEX) + return; + + //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) { //sign for autocast @@ -377,8 +381,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) ((Pet*)pet)->ToggleAutocast(spell_id, false); } - charmInfo->GetActionBarEntry(position)->Type = act_state; - charmInfo->GetActionBarEntry(position)->SpellOrAction = spell_id; + charmInfo->SetActionBar(position,spell_id,ActiveStates(act_state)); } } } @@ -560,11 +563,7 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket ) else ((Pet*)pet)->ToggleAutocast(spellid, state); - for(uint8 i = 0; i < 10; ++i) - { - if((charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED) && spellid == charmInfo->GetActionBarEntry(i)->SpellOrAction) - charmInfo->GetActionBarEntry(i)->Type = state ? ACT_ENABLED : ACT_DISABLED; - } + charmInfo->SetSpellAutocast(spellid,state); } void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 88725e0be..b5c0ebc8a 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -16410,10 +16410,7 @@ void Player::PetSpellInitialize() data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); // action bar loop - for(uint32 i = 0; i < 10; ++i) - { - data << uint32(charmInfo->GetActionBarEntry(i)->Raw); - } + charmInfo->BuildActionBar(&data); size_t spellsCountPos = data.wpos(); @@ -16489,10 +16486,7 @@ void Player::PossessSpellInitialize() data << uint32(0); data << uint32(0); - for(uint32 i = 0; i < 10; ++i) //40 - { - data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); - } + charmInfo->BuildActionBar(&data); //40 data << uint8(addlist); //1 @@ -16543,10 +16537,7 @@ void Player::CharmSpellInitialize() data << uint8(0) << uint8(0); data << uint16(0); - for(uint32 i = 0; i < 10; ++i) //40 - { - data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); - } + charmInfo->BuildActionBar(&data); //40 data << uint8(addlist); //1 diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index a5a79170d..b7e116e39 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -10328,28 +10328,18 @@ void CharmInfo::InitPetActionBar() // the first 3 SpellOrActions are attack, follow and stay for(uint32 i = 0; i < 3; ++i) { - PetActionBar[i].Type = ACT_COMMAND; - PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i; - - PetActionBar[i + 7].Type = ACT_REACTION; - PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i; - } - for(uint32 i=0; i < 4; ++i) - { - PetActionBar[i + 3].Type = ACT_DISABLED; - PetActionBar[i + 3].SpellOrAction = 0; + SetActionBar(i,COMMAND_ATTACK - i,ACT_COMMAND); + SetActionBar(i + 7,COMMAND_ATTACK - i,ACT_REACTION); } + for(uint32 i = 0; i < 4; ++i) + SetActionBar(i,0,ACT_DISABLED); } void CharmInfo::InitEmptyActionBar() { - for(uint32 x = 1; x < 10; ++x) - { - PetActionBar[x].Type = ACT_PASSIVE; - PetActionBar[x].SpellOrAction = 0; - } - PetActionBar[0].Type = ACT_COMMAND; - PetActionBar[0].SpellOrAction = COMMAND_ATTACK; + SetActionBar(0,COMMAND_ATTACK,ACT_COMMAND); + for(uint32 x = 1; x < MAX_UNIT_ACTION_BAR_INDEX; ++x) + SetActionBar(x,0,ACT_PASSIVE); } void CharmInfo::InitPossessCreateSpells() @@ -10364,7 +10354,7 @@ void CharmInfo::InitPossessCreateSpells() if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); else - AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_PASSIVE); + AddSpellToActionBar(((Creature*)m_unit)->m_spells[x], ACT_PASSIVE); } } @@ -10409,39 +10399,56 @@ void CharmInfo::InitCharmCreateSpells() else newstate = ACT_PASSIVE; - AddSpellToAB(0, spellId, newstate); + AddSpellToActionBar(spellId, newstate); } } } -bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate) +bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate) { - // new spell already listed for example in case prepered switch to lesser rank in Pet::removeSpell - for(uint8 i = 0; i < 10; ++i) - if (PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE) - if (newid && PetActionBar[i].SpellOrAction == newid) - return true; + uint32 first_id = spellmgr.GetFirstSpellInChain(spell_id); - // old spell can be leasted for example in case learn high rank - for(uint8 i = 0; i < 10; ++i) + // new spell rank can be already listed + for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) { - if (PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE) + if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) { - if (PetActionBar[i].SpellOrAction == oldid) + if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id) { - PetActionBar[i].SpellOrAction = newid; - if (!oldid) - { - if (newstate == ACT_DECIDE) - PetActionBar[i].Type = ACT_DISABLED; - else - PetActionBar[i].Type = newstate; - } - + PetActionBar[i].SpellOrAction = spell_id; return true; } } } + + // or use empty slot in other case + for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if (!PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + { + SetActionBar(i,spell_id,newstate == ACT_DECIDE ? ACT_DISABLED : newstate); + return true; + } + } + return false; +} + +bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id) +{ + uint32 first_id = spellmgr.GetFirstSpellInChain(spell_id); + + for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + { + if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id) + { + SetActionBar(i,0,ACT_DISABLED); + return true; + } + } + } + return false; } @@ -10468,6 +10475,50 @@ void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow) m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0); } +bool CharmInfo::LoadActionBar( std::string data ) +{ + Tokens tokens = StrSplit(data, " "); + + if (tokens.size() != MAX_UNIT_ACTION_BAR_INDEX*2) + return false; + + int index; + Tokens::iterator iter; + for(iter = tokens.begin(), index = 0; index < MAX_UNIT_ACTION_BAR_INDEX; ++iter, ++index ) + { + // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion + PetActionBar[index].Type = atol((*iter).c_str()); + ++iter; + PetActionBar[index].SpellOrAction = atol((*iter).c_str()); + + // check correctness + if(PetActionBar[index].IsActionBarForSpell() && !sSpellStore.LookupEntry(PetActionBar[index].SpellOrAction)) + SetActionBar(index,0,ACT_DISABLED); + } + return true; +} + +void CharmInfo::BuildActionBar( WorldPacket* data ) +{ + for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + *data << uint16(PetActionBar[i].SpellOrAction); + *data << uint16(PetActionBar[i].Type); + } +} + +void CharmInfo::SetSpellAutocast( uint32 spell_id, bool state ) +{ + for(int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if(spell_id == PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + { + PetActionBar[i].Type = state ? ACT_ENABLED : ACT_DISABLED; + break; + } + } +} + bool Unit::isFrozen() const { return HasAuraState(AURA_STATE_FROZEN); diff --git a/src/game/Unit.h b/src/game/Unit.h index e79b88493..ccefb8c86 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -678,24 +678,6 @@ struct SpellNonMeleeDamage{ uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition); -struct UnitActionBarEntry -{ - UnitActionBarEntry() : Raw(0) {} - - union - { - struct - { - uint16 SpellOrAction; - uint16 Type; - }; - struct - { - uint32 Raw; - }; - }; -}; - #define MAX_DECLINED_NAME_CASES 5 struct DeclinedName @@ -738,12 +720,28 @@ enum CommandStates COMMAND_ABANDON = 3 }; +struct UnitActionBarEntry +{ + UnitActionBarEntry() : SpellOrAction(0), Type(ACT_DISABLED) {} + + uint16 SpellOrAction; + uint16 Type; + + // helper + bool IsActionBarForSpell() const + { + return Type == ACT_DISABLED || Type == ACT_ENABLED || Type == ACT_PASSIVE; + } +}; + struct CharmSpellEntry { uint16 spellId; uint16 active; }; +#define MAX_UNIT_ACTION_BAR_INDEX 10 + struct CharmInfo { public: @@ -762,15 +760,27 @@ struct CharmInfo void InitCharmCreateSpells(); void InitPetActionBar(); void InitEmptyActionBar(); + //return true if successful - bool AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate = ACT_DECIDE); + bool AddSpellToActionBar(uint32 spellid, ActiveStates newstate = ACT_DECIDE); + bool RemoveSpellFromActionBar(uint32 spell_id); + bool LoadActionBar(std::string data); + void BuildActionBar(WorldPacket* data); + void SetSpellAutocast(uint32 spell_id, bool state); + void SetActionBar(uint8 index, uint32 spellOrAction,ActiveStates type) + { + PetActionBar[index].Type = type; + PetActionBar[index].SpellOrAction = spellOrAction; + } + UnitActionBarEntry const* GetActionBarEntry(uint8 index) const { return &(PetActionBar[index]); } + void ToggleCreatureAutocast(uint32 spellid, bool apply); - UnitActionBarEntry* GetActionBarEntry(uint8 index) { return &(PetActionBar[index]); } CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); } private: + Unit* m_unit; - UnitActionBarEntry PetActionBar[10]; + UnitActionBarEntry PetActionBar[MAX_UNIT_ACTION_BAR_INDEX]; CharmSpellEntry m_charmspells[4]; CommandStates m_CommandState; ReactStates m_reactState; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b38946ae9..6c8925ca3 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7900" + #define REVISION_NR "7901" #endif // __REVISION_NR_H__ From c87e51dae5ccd3d535b1c4c8e246bc227725ef2e Mon Sep 17 00:00:00 2001 From: AlexDereka Date: Thu, 28 May 2009 00:00:10 +0400 Subject: [PATCH 7/8] [7902] Speed up Creature and GO loads. --- sql/mangos.sql | 8 +++++--- sql/updates/7902_01_mangos_pool_creature.sql | 4 ++++ sql/updates/7902_02_mangos_pool_gameobject.sql | 4 ++++ sql/updates/Makefile.am | 4 ++++ src/shared/revision_nr.h | 2 +- 5 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 sql/updates/7902_01_mangos_pool_creature.sql create mode 100644 sql/updates/7902_02_mangos_pool_gameobject.sql diff --git a/sql/mangos.sql b/sql/mangos.sql index 2cff642fe..e5b43254d 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, - `required_7896_01_mangos_creature_template` bit(1) default NULL + `required_7902_02_mangos_pool_gameobject` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -12938,7 +12938,8 @@ CREATE TABLE `pool_creature` ( `pool_entry` mediumint(8) unsigned NOT NULL default '0', `chance` float unsigned NOT NULL default '0', `description` varchar(255) NOT NULL, - PRIMARY KEY (`pool_entry`,`guid`) + PRIMARY KEY (`pool_entry`,`guid`), + INDEX `idx_guid`(`guid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; @@ -12961,7 +12962,8 @@ CREATE TABLE `pool_gameobject` ( `pool_entry` mediumint(8) unsigned NOT NULL default '0', `chance` float unsigned NOT NULL default '0', `description` varchar(255) NOT NULL, - PRIMARY KEY (`guid`,`pool_entry`) + PRIMARY KEY (`guid`,`pool_entry`), + INDEX `idx_guid`(`guid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- diff --git a/sql/updates/7902_01_mangos_pool_creature.sql b/sql/updates/7902_01_mangos_pool_creature.sql new file mode 100644 index 000000000..309ca5e38 --- /dev/null +++ b/sql/updates/7902_01_mangos_pool_creature.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_7896_01_mangos_creature_template required_7902_01_mangos_pool_creature bit; + +ALTER TABLE `pool_creature` + ADD INDEX `idx_guid`(`guid`); \ No newline at end of file diff --git a/sql/updates/7902_02_mangos_pool_gameobject.sql b/sql/updates/7902_02_mangos_pool_gameobject.sql new file mode 100644 index 000000000..46524337a --- /dev/null +++ b/sql/updates/7902_02_mangos_pool_gameobject.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_7902_01_mangos_pool_creature required_7902_02_mangos_pool_gameobject bit; + +ALTER TABLE `pool_gameobject` + ADD INDEX `idx_guid`(`guid`); \ No newline at end of file diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 4930f8ffa..d090aa5af 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -201,6 +201,8 @@ pkgdata_DATA = \ 7887_01_characters_character_pet.sql \ 7893_01_mangos_command.sql \ 7896_01_mangos_creature_template.sql \ + 7902_01_mangos_pool_creature.sql \ + 7902_02_mangos_pool_gameobject.sql \ README ## Additional files to include when running 'make dist' @@ -382,4 +384,6 @@ EXTRA_DIST = \ 7887_01_characters_character_pet.sql \ 7893_01_mangos_command.sql \ 7896_01_mangos_creature_template.sql \ + 7902_01_mangos_pool_creature.sql \ + 7902_02_mangos_pool_gameobject.sql \ README diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 6c8925ca3..2728cb06c 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7901" + #define REVISION_NR "7902" #endif // __REVISION_NR_H__ From 0614a9eb7528fd6beac9d7510ce474fca5275c37 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Thu, 28 May 2009 01:57:52 +0400 Subject: [PATCH 8/8] [7903] Load and save for pets only talents. Not store unused (in fact) free talent point amount. * Other pet spell types auto-learned at level setup/load. * Code will cleanup pet_spell table from non-talents spell if detect any at load. * Free talents points recalculated at loading and levelup so store its in DB useless. Note: bug with not highlighting learned pet talents (except first line) until learn one more talent not fixed. --- sql/characters.sql | 3 +- .../7903_01_characters_character_pet.sql | 4 ++ sql/updates/Makefile.am | 2 + src/game/Pet.cpp | 65 +++++++++++-------- src/game/Pet.h | 1 + src/shared/revision_nr.h | 2 +- 6 files changed, 48 insertions(+), 29 deletions(-) create mode 100644 sql/updates/7903_01_characters_character_pet.sql diff --git a/sql/characters.sql b/sql/characters.sql index c20530a05..fc717c1ef 100644 --- a/sql/characters.sql +++ b/sql/characters.sql @@ -21,7 +21,7 @@ DROP TABLE IF EXISTS `character_db_version`; CREATE TABLE `character_db_version` ( - `required_7887_01_characters_character_pet` bit(1) default NULL + `required_7903_01_characters_character_pet` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; -- @@ -472,7 +472,6 @@ CREATE TABLE `character_pet` ( `level` int(11) unsigned NOT NULL default '1', `exp` int(11) unsigned NOT NULL default '0', `Reactstate` tinyint(1) unsigned NOT NULL default '0', - `talentpoints` int(11) unsigned NOT NULL default '0', `name` varchar(100) default 'Pet', `renamed` tinyint(1) unsigned NOT NULL default '0', `slot` int(11) unsigned NOT NULL default '0', diff --git a/sql/updates/7903_01_characters_character_pet.sql b/sql/updates/7903_01_characters_character_pet.sql new file mode 100644 index 000000000..834aac200 --- /dev/null +++ b/sql/updates/7903_01_characters_character_pet.sql @@ -0,0 +1,4 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_7887_01_characters_character_pet required_7903_01_characters_character_pet bit; + +ALTER TABLE `character_pet` + DROP `talentpoints`; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index d090aa5af..6e18e6493 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -203,6 +203,7 @@ pkgdata_DATA = \ 7896_01_mangos_creature_template.sql \ 7902_01_mangos_pool_creature.sql \ 7902_02_mangos_pool_gameobject.sql \ + 7903_01_characters_character_pet.sql \ README ## Additional files to include when running 'make dist' @@ -386,4 +387,5 @@ EXTRA_DIST = \ 7896_01_mangos_creature_template.sql \ 7902_01_mangos_pool_creature.sql \ 7902_02_mangos_pool_gameobject.sql \ + 7903_01_characters_character_pet.sql \ README diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 9244736c2..60b7c06b4 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -87,25 +87,25 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool QueryResult *result; if (petnumber) - // known petnumber entry 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " + // known petnumber entry 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND id = '%u'", ownerid, petnumber); else if (current) - // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " + // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND slot = '%u'", ownerid, PET_SAVE_AS_CURRENT ); else if (petentry) // known petentry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets) - // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " + // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '%u' OR slot > '%u') ", ownerid, petentry,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); else // any current or other non-stabled pet (for hunter "call pet") - // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " + // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u') ", ownerid,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); @@ -122,7 +122,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool return false; } - uint32 summon_spell_id = fields[18].GetUInt32(); + uint32 summon_spell_id = fields[17].GetUInt32(); SpellEntry const* spellInfo = sSpellStore.LookupEntry(summon_spell_id); bool is_temporary_summoned = spellInfo && GetSpellDuration(spellInfo) > 0; @@ -164,7 +164,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool return false; } - setPetType(PetType(fields[19].GetUInt8())); + setPetType(PetType(fields[18].GetUInt8())); SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, owner->getFaction()); SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id); @@ -184,7 +184,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool SetNativeDisplayId(fields[3].GetUInt32()); uint32 petlevel = fields[4].GetUInt32(); SetUInt32Value(UNIT_NPC_FLAGS, 0); - SetName(fields[9].GetString()); + SetName(fields[8].GetString()); switch (getPetType()) { @@ -197,14 +197,13 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool break; case HUNTER_PET: SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); - SetByteValue(UNIT_FIELD_BYTES_1, 1, fields[7].GetUInt32()); SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE); - SetByteValue(UNIT_FIELD_BYTES_2, 2, fields[10].GetBool() ? UNIT_RENAME_NOT_ALLOWED : UNIT_RENAME_ALLOWED); + SetByteValue(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_RENAME_NOT_ALLOWED : UNIT_RENAME_ALLOWED); SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet abandon, cancel) SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); - SetPower(POWER_HAPPINESS, fields[13].GetUInt32()); + SetPower(POWER_HAPPINESS, fields[12].GetUInt32()); setPowerType(POWER_FOCUS); break; default: @@ -215,20 +214,22 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool SetPvP(true); InitStatsForLevel(petlevel); + InitTalentForLevel(); // set original talents points before spell loading + SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL)); SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32()); SetCreatorGUID(owner->GetGUID()); m_charmInfo->SetReactState(ReactStates(fields[6].GetUInt8())); - uint32 savedhealth = fields[11].GetUInt32(); - uint32 savedmana = fields[12].GetUInt32(); + uint32 savedhealth = fields[10].GetUInt32(); + uint32 savedmana = fields[11].GetUInt32(); // set current pet as current // 0=current // 1..MAX_PET_STABLES in stable slot // PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning)) - if (fields[8].GetUInt32() != 0) + if (fields[7].GetUInt32() != 0) { CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND slot = '%u' AND id <> '%u'", @@ -240,7 +241,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool if (!is_temporary_summoned) { - if(!m_charmInfo->LoadActionBar(fields[14].GetCppString())) + if(!m_charmInfo->LoadActionBar(fields[13].GetCppString())) { delete result; return false; @@ -248,10 +249,10 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool } // since last save (in seconds) - uint32 timediff = (time(NULL) - fields[15].GetUInt32()); + uint32 timediff = (time(NULL) - fields[14].GetUInt32()); - m_resetTalentsCost = fields[16].GetUInt32(); - m_resetTalentsTime = fields[17].GetUInt64(); + m_resetTalentsCost = fields[15].GetUInt32(); + m_resetTalentsTime = fields[16].GetUInt64(); delete result; @@ -394,7 +395,7 @@ void Pet::SavePetToDB(PetSaveMode mode) owner,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); // save pet std::ostringstream ss; - ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) " + ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) " << "VALUES (" << m_charmInfo->GetPetNumber() << ", " << GetEntry() << ", " @@ -403,7 +404,6 @@ void Pet::SavePetToDB(PetSaveMode mode) << getLevel() << ", " << GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ", " << uint32(m_charmInfo->GetReactState()) << ", " - << uint32(GetFreeTalentPoints()) << ", " << uint32(mode) << ", '" << name.c_str() << "', " << uint32((GetByteValue(UNIT_FIELD_BYTES_2, 2) == UNIT_RENAME_ALLOWED)?0:1) << ", " @@ -1093,7 +1093,17 @@ void Pet::_LoadSpells() { Field *fields = result->Fetch(); - addSpell(fields[0].GetUInt32(), ActiveStates(fields[1].GetUInt16()), PETSPELL_UNCHANGED); + uint32 spell_id = fields[0].GetUInt32(); + + // load only pet talents, other spell types auto-learned + if(GetTalentSpellCost(spell_id)==0) + { + CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE spell = '%u'",spell_id); + sLog.outError("Table `pet_spell` have non-talent spell %u , spell removed from table for all pets.",spell_id); + continue; + } + + addSpell(spell_id, ActiveStates(fields[1].GetUInt16()), PETSPELL_UNCHANGED,PETSPELL_TALENT); } while( result->NextRow() ); @@ -1107,8 +1117,8 @@ void Pet::_SaveSpells() { ++next; - // prevent saving family passives to DB - if (itr->second.type == PETSPELL_FAMILY) + // save only talent spells for pets, other spells auto-applied + if (itr->second.type != PETSPELL_TALENT) continue; switch(itr->second.state) @@ -1319,6 +1329,9 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel // talent: unlearn all other talent ranks (high and low) if(TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id)) { + // propertly mark spell for allow save + newspell.type = PETSPELL_TALENT; + if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id )) { for(int i=0; i < MAX_TALENT_RANK; ++i) diff --git a/src/game/Pet.h b/src/game/Pet.h index 510738731..223675a88 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -65,6 +65,7 @@ enum PetSpellType { PETSPELL_NORMAL = 0, PETSPELL_FAMILY = 1, + PETSPELL_TALENT = 2, }; struct PetSpell diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 2728cb06c..de1b34343 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7902" + #define REVISION_NR "7903" #endif // __REVISION_NR_H__