diff --git a/sql/mangos.sql b/sql/mangos.sql index c320c9169..8e3e149a3 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -358,13 +358,14 @@ INSERT INTO `command` VALUES ('reload all_spell',3,'Syntax: .reload all_spell\r\n\r\nReload all `spell_*` tables with reload support added and that can be _safe_ reloaded.'), ('reload all_locales',3,'Syntax: .reload all_locales\r\n\r\nReload all `locales_*` tables with reload support added and that can be _safe_ reloaded.'), ('reload config',3,'Syntax: .reload config\r\n\r\nReload config settings (by default stored in mangosd.conf). Not all settings can be change at reload: some new setting values will be ignored until restart, some values will applied with delay or only to new objects/maps, some values will explicitly rejected to change at reload.'), +('repairitems',2,'Syntax: .repairitems\r\n\r\nRepair all selected player''s items.'), ('reset all',3,'Syntax: .reset all spells\r\n\r\nSyntax: .reset all talents\r\n\r\nRequest reset spells or talents at next login each existed character.'), ('reset honor',3,'Syntax:\r\n.reset honor [Playername]\r\n Reset all honor data for targeted character.'), ('reset level',3,'Syntax:\r\n.reset level [Playername]\r\n Reset level to 1 including reset stats and talents. Equipped items with greater level requirement can be lost.'), ('reset spells',3,'Syntax:\r\n.reset spells [Playername]\r\n Removes all non-original spells from spellbook.\r\n. Playername can be name of offline character.'), ('reset stats',3,'Syntax:\r\n.reset stats [Playername]\r\n Resets(recalculate) all stats of the targeted player to their original VALUESat current level.'), ('reset talents',3,'Syntax:\r\n.reset talents [Playername]\r\n Removes all talents of the targeted player. Playername can be name of offline character.'), -('respawn',3,'Syntax: .respawn\r\n\r\nRespawn all nearest creatures and GO without waiting respawn time expiration.'), +('respawn',3,'Syntax: .respawn\r\n\r\nRespawn selected creature or respawn all nearest creatures (if none selected) and GO without waiting respawn time expiration.'), ('revive',3,'Syntax: .revive\r\n\r\nRevive the selected player. If no player is selected, it will revive you.'), ('save',0,'Syntax: .save\r\n\r\nSaves your character.'), ('saveall',1,'Syntax: .saveall\r\n\r\nSave all characters in game.'), @@ -1803,6 +1804,42 @@ LOCK TABLES `locales_item` WRITE; /*!40000 ALTER TABLE `locales_item` ENABLE KEYS */; UNLOCK TABLES; + +-- +-- Table structure for table `locales_npc_option` +-- + +DROP TABLE IF EXISTS `locales_npc_option`; +CREATE TABLE `locales_npc_option` ( + `entry` mediumint(8) unsigned NOT NULL default '0', + `option_text_loc1` text, + `option_text_loc2` text, + `option_text_loc3` text, + `option_text_loc4` text, + `option_text_loc5` text, + `option_text_loc6` text, + `option_text_loc7` text, + `option_text_loc8` text, + `box_text_loc1` text, + `box_text_loc2` text, + `box_text_loc3` text, + `box_text_loc4` text, + `box_text_loc5` text, + `box_text_loc6` text, + `box_text_loc7` text, + `box_text_loc8` text, + PRIMARY KEY (`entry`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `locales_npc_option` +-- + +LOCK TABLES `locales_npc_option` WRITE; +/*!40000 ALTER TABLE `locales_npc_option` DISABLE KEYS */; +/*!40000 ALTER TABLE `locales_npc_option` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `locales_npc_text` -- @@ -2230,7 +2267,7 @@ INSERT INTO `mangos_string` VALUES (168,'Locations found are:\n %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (169,'Mail sent to %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (170,'You try to hear sound %u but it doesn\'t exist.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(171,'You are being teleported by server console command.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(172,'server console command',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (200,'No selection.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (201,'Object GUID is: lowpart %u highpart %X',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (202,'The name was too long by %i characters.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), @@ -2367,6 +2404,8 @@ INSERT INTO `mangos_string` VALUES (333,'GM mode is OFF',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (334,'GM Chat Badge is ON',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (335,'GM Chat Badge is OFF',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(336,'You repair all %s''s items.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(337,'All your items repaired by %s.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (400,'|cffff0000[System Message]:|rScripts reloaded',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (401,'You change security level of account %s to %i.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (402,'%s changed your security level to %i.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), @@ -2707,12 +2746,15 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `npc_option`; CREATE TABLE `npc_option` ( - `id` tinyint(3) unsigned NOT NULL default '0', - `gossip_id` tinyint(3) unsigned NOT NULL default '0', + `id` mediumint(8) unsigned NOT NULL default '0', + `gossip_id` mediumint(8) unsigned NOT NULL default '0', `npcflag` int(10) unsigned NOT NULL default '0', `icon` tinyint(3) unsigned NOT NULL default '0', - `action` tinyint(3) unsigned NOT NULL default '0', + `action` mediumint(8) unsigned NOT NULL default '0', + `box_money` int(10) unsigned NOT NULL default '0', + `coded` tinyint(3) unsigned NOT NULL default '0', `option_text` text, + `box_text` text, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/sql/updates/2008_10_27_01_npc_option.sql b/sql/updates/2008_10_27_01_npc_option.sql new file mode 100644 index 000000000..983a6c9e6 --- /dev/null +++ b/sql/updates/2008_10_27_01_npc_option.sql @@ -0,0 +1,7 @@ +ALTER TABLE `npc_option` + CHANGE COLUMN `id` `id` mediumint(8) unsigned NOT NULL default '0', + CHANGE COLUMN `gossip_id` `gossip_id` mediumint(8) unsigned NOT NULL default '0', + CHANGE COLUMN `action` `action` mediumint(8) unsigned NOT NULL default '0', + ADD COLUMN `box_money` int(10) unsigned NOT NULL default '0' AFTER `action`, + ADD COLUMN `coded` tinyint(3) unsigned NOT NULL default '0' AFTER `box_money`, + ADD COLUMN `box_text` text AFTER `option_text`; diff --git a/sql/updates/2008_10_27_02_locales_npc_option.sql b/sql/updates/2008_10_27_02_locales_npc_option.sql new file mode 100644 index 000000000..172e35a24 --- /dev/null +++ b/sql/updates/2008_10_27_02_locales_npc_option.sql @@ -0,0 +1,22 @@ +CREATE TABLE `locales_npc_option` ( + `entry` mediumint(8) unsigned NOT NULL default '0', + `option_text_loc1` text, + `option_text_loc2` text, + `option_text_loc3` text, + `option_text_loc4` text, + `option_text_loc5` text, + `option_text_loc6` text, + `option_text_loc7` text, + `option_text_loc8` text, + `box_text_loc1` text, + `box_text_loc2` text, + `box_text_loc3` text, + `box_text_loc4` text, + `box_text_loc5` text, + `box_text_loc6` text, + `box_text_loc7` text, + `box_text_loc8` text, + PRIMARY KEY (`entry`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + + diff --git a/sql/updates/2008_10_28_01_mangos_mangos_string.sql b/sql/updates/2008_10_28_01_mangos_mangos_string.sql new file mode 100644 index 000000000..fa325bb94 --- /dev/null +++ b/sql/updates/2008_10_28_01_mangos_mangos_string.sql @@ -0,0 +1,5 @@ +DELETE FROM mangos_string WHERE entry IN (171,172); + +INSERT INTO mangos_string VALUES +(172,'server console command',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); + diff --git a/sql/updates/2008_10_28_02_mangos_mangos_string.sql b/sql/updates/2008_10_28_02_mangos_mangos_string.sql new file mode 100644 index 000000000..16f340532 --- /dev/null +++ b/sql/updates/2008_10_28_02_mangos_mangos_string.sql @@ -0,0 +1,5 @@ +DELETE FROM mangos_string WHERE entry IN (336,337); + +INSERT INTO mangos_string VALUES +(336,'You repair all %s''s items.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(337,'All your items repaired by %s.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); diff --git a/sql/updates/2008_10_28_03_mangos_command.sql b/sql/updates/2008_10_28_03_mangos_command.sql new file mode 100644 index 000000000..438f6e746 --- /dev/null +++ b/sql/updates/2008_10_28_03_mangos_command.sql @@ -0,0 +1,4 @@ +DELETE FROM command WHERE name IN ('repairitems'); + +INSERT INTO command VALUES +('repairitems',2,'Syntax: .repairitems\r\n\r\nRepair all selected player''s items.'); diff --git a/sql/updates/2008_10_28_04_mangos_command.sql b/sql/updates/2008_10_28_04_mangos_command.sql new file mode 100644 index 000000000..c1758fc58 --- /dev/null +++ b/sql/updates/2008_10_28_04_mangos_command.sql @@ -0,0 +1,4 @@ +DELETE FROM command WHERE name IN ('respawn'); + +INSERT INTO command VALUES +('respawn',3,'Syntax: .respawn\r\n\r\nRespawn selected creature or respawn all nearest creatures (if none selected) and GO without waiting respawn time expiration.'); diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index da45d285a..1829616e2 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -107,6 +107,12 @@ pkgdata_DATA = \ 2008_10_23_04_mangos_command.sql \ 2008_10_23_05_mangos_command.sql \ 2008_10_26_01_mangos_mangos_string.sql \ + 2008_10_27_01_npc_option.sql \ + 2008_10_27_02_locales_npc_option.sql \ + 2008_10_28_01_mangos_mangos_string.sql \ + 2008_10_28_02_mangos_mangos_string.sql \ + 2008_10_28_03_mangos_command.sql \ + 2008_10_28_04_mangos_command.sql \ README ## Additional files to include when running 'make dist' @@ -195,4 +201,10 @@ EXTRA_DIST = \ 2008_10_23_04_mangos_command.sql \ 2008_10_23_05_mangos_command.sql \ 2008_10_26_01_mangos_mangos_string.sql \ + 2008_10_27_01_npc_option.sql \ + 2008_10_27_02_locales_npc_option.sql \ + 2008_10_28_01_mangos_mangos_string.sql \ + 2008_10_28_02_mangos_mangos_string.sql \ + 2008_10_28_03_mangos_command.sql \ + 2008_10_28_04_mangos_command.sql \ README diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 86e96d5bf..ad7b396af 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -228,6 +228,7 @@ ChatCommand * ChatHandler::getCommandTable() { "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, { "mangos_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadMangosStringCommand, "", NULL }, { "npc_gossip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcGossipCommand, "", NULL }, + { "npc_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcOptionCommand, "", NULL }, { "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL }, { "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL }, { "page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPageTextsCommand, "", NULL }, @@ -526,6 +527,7 @@ ChatCommand * ChatHandler::getCommandTable() { "combatstop", SEC_GAMEMASTER, false, &ChatHandler::HandleCombatStopCommand, "", NULL }, { "chardelete", SEC_CONSOLE, true, &ChatHandler::HandleCombatStopCommand, "", NULL }, { "sendmessage", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMessageCommand, "", NULL }, + { "repairitems", SEC_GAMEMASTER, false, &ChatHandler::HandleRepairitemsCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; @@ -786,7 +788,13 @@ bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, ch if( *subcmd && !hasStringAbbr(table[i].Name, subcmd)) continue; - (list += "\n ") += table[i].Name; + if(m_session) + list += "\n "; + else + list += "\n\r "; + + list += table[i].Name; + if(table[i].ChildCommands) list += " ..."; } @@ -1187,6 +1195,17 @@ GameTele const* ChatHandler::extractGameTeleFromLink(char* text) return objmgr.GetGameTele(cId); } +const char *ChatHandler::GetName() const +{ + return m_session->GetPlayer()->GetName(); +} + +bool ChatHandler::needReportToTarget(Player* chr) const +{ + Player* pl = m_session->GetPlayer(); + return pl != chr && pl->IsVisibleGloballyFor(chr); +} + const char *CliHandler::GetMangosString(int32 entry) const { return objmgr.GetMangosStringForDBCLocale(entry); @@ -1203,3 +1222,14 @@ void CliHandler::SendSysMessage(const char *str) m_print(str); m_print("\r\n"); } + +const char *CliHandler::GetName() const +{ + return GetMangosString(LANG_CONSOLE_COMMAND); +} + +bool CliHandler::needReportToTarget(Player* /*chr*/) const +{ + return true; +} + diff --git a/src/game/Chat.h b/src/game/Chat.h index c91f0b673..402284399 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -69,12 +69,14 @@ class ChatHandler int ParseCommands(const char* text); + virtual char const* GetName() const; protected: explicit ChatHandler() : m_session(NULL) {} // for CLI subclass bool hasStringAbbr(const char* name, const char* part); virtual bool isAvailable(ChatCommand const& cmd) const; + virtual bool needReportToTarget(Player* chr) const; void SendGlobalSysMessage(const char *str); @@ -183,6 +185,7 @@ class ChatHandler bool HandleReloadLootTemplatesSkinningCommand(const char* args); bool HandleReloadMangosStringCommand(const char* args); bool HandleReloadNpcGossipCommand(const char* args); + bool HandleReloadNpcOptionCommand(const char* args); bool HandleReloadNpcTrainerCommand(const char* args); bool HandleReloadNpcVendorCommand(const char* args); bool HandleReloadQuestAreaTriggersCommand(const char* args); @@ -403,6 +406,7 @@ class ChatHandler bool HandleComeToMeCommand(const char *args); bool HandleCombatStopCommand(const char *args); bool HandleSendMessageCommand(const char * args); + bool HandleRepairitemsCommand(const char* args); //! Development Commands bool HandleSetValue(const char* args); @@ -454,6 +458,8 @@ class CliHandler : public ChatHandler const char *GetMangosString(int32 entry) const; bool isAvailable(ChatCommand const& cmd) const; void SendSysMessage(const char *str); + char const* GetName() const; + bool needReportToTarget(Player* chr) const; private: Print* m_print; diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index e39c319de..15652ea95 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -671,12 +671,9 @@ void Creature::prepareGossipMenu( Player *pPlayer,uint32 gossipid ) // lazy loading single time at use LoadGossipOptions(); - GossipOption* gso; - GossipOption* ingso; - for( GossipOptionList::iterator i = m_goptions.begin( ); i != m_goptions.end( ); i++ ) { - gso=&*i; + GossipOption* gso=&*i; if(gso->GossipId == gossipid) { bool cantalking=true; @@ -744,15 +741,29 @@ void Creature::prepareGossipMenu( Player *pPlayer,uint32 gossipid ) case GOSSIP_OPTION_AUCTIONEER: break; // no checks default: - sLog.outErrorDb("Creature %u (entry: %u) have unknown gossip option %u",GetGUIDLow(),GetEntry(),gso->Action); + sLog.outErrorDb("Creature %u (entry: %u) have unknown gossip option %u",GetDBTableGUIDLow(),GetEntry(),gso->Action); break; } } - if(!gso->Option.empty() && cantalking ) - { //note for future dev: should have database fields for BoxMessage & BoxMoney - pm->GetGossipMenu().AddMenuItem((uint8)gso->Icon,gso->Option, gossipid,gso->Action,"",0,false); - ingso=gso; + //note for future dev: should have database fields for BoxMessage & BoxMoney + if(!gso->OptionText.empty() && cantalking) + { + std::string OptionText = gso->OptionText; + std::string BoxText = gso->BoxText; + int loc_idx = pPlayer->GetSession()->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + NpcOptionLocale const *no = objmgr.GetNpcOptionLocale(gso->Id); + if (no) + { + if (no->OptionText.size() > loc_idx && !no->OptionText[loc_idx].empty()) + OptionText=no->OptionText[loc_idx]; + if (no->BoxText.size() > loc_idx && !no->BoxText[loc_idx].empty()) + BoxText=no->BoxText[loc_idx]; + } + } + pm->GetGossipMenu().AddMenuItem((uint8)gso->Icon,OptionText, gossipid,gso->Action,BoxText,gso->BoxMoney,gso->Coded); } } } @@ -800,8 +811,8 @@ void Creature::OnGossipSelect(Player* player, uint32 option) uint32 action=gossipmenu.GetItem(option).m_gAction; uint32 zoneid=GetZoneId(); uint64 guid=GetGUID(); + GossipOption const *gossip=GetGossipOption( action ); - uint32 textid; if(!gossip) { zoneid=0; @@ -809,7 +820,8 @@ void Creature::OnGossipSelect(Player* player, uint32 option) if(!gossip) return; } - textid=GetGossipTextId( action, zoneid); + + uint32 textid=GetGossipTextId( action, zoneid); if(textid==0) textid=GetNpcTextId(); @@ -898,7 +910,7 @@ void Creature::OnPoiSelect(Player* player, GossipOption const *gossip) Map const* map=MapManager::Instance().GetBaseMap( mapid ); uint16 areaflag=map->GetAreaFlag(GetPositionX(),GetPositionY()); uint32 zoneid=Map::GetZoneId(areaflag,mapid); - std::string areaname= gossip->Option; + std::string areaname= gossip->OptionText; /* uint16 pflag; @@ -992,24 +1004,10 @@ void Creature::LoadGossipOptions() uint32 npcflags=GetUInt32Value(UNIT_NPC_FLAGS); - QueryResult *result = WorldDatabase.PQuery( "SELECT id,gossip_id,npcflag,icon,action,option_text FROM npc_option WHERE (npcflag & %u)<>0", npcflags ); - - if(!result) - return; - - GossipOption go; - do - { - Field *fields = result->Fetch(); - go.Id= fields[0].GetUInt32(); - go.GossipId = fields[1].GetUInt32(); - go.NpcFlag=fields[2].GetUInt32(); - go.Icon=fields[3].GetUInt32(); - go.Action=fields[4].GetUInt32(); - go.Option=fields[5].GetCppString(); - addGossipOption(go); - }while( result->NextRow() ); - delete result; + CacheNpcOptionList const& noList = objmgr.GetNpcOptions (); + for (CacheNpcOptionList::const_iterator i = noList.begin (); i != noList.end (); ++i) + if(i->NpcFlag & npcflags) + addGossipOption(*i); m_gossipOptionLoaded = true; } diff --git a/src/game/Creature.h b/src/game/Creature.h index 05a65be6b..4f2a48b2b 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -109,7 +109,10 @@ struct GossipOption uint32 NpcFlag; uint32 Icon; uint32 Action; - std::string Option; + uint32 BoxMoney; + bool Coded; + std::string OptionText; + std::string BoxText; }; enum CreatureFlagsExtra @@ -207,6 +210,12 @@ struct CreatureLocale std::vector SubName; }; +struct NpcOptionLocale +{ + std::vector OptionText; + std::vector BoxText; +}; + struct EquipmentInfo { uint32 entry; @@ -465,8 +474,8 @@ class MANGOS_DLL_SPEC Creature : public Unit CreatureDataAddon const* GetCreatureAddon() const; char const* GetScriptName() const; - void prepareGossipMenu( Player *pPlayer,uint32 gossipid ); - void sendPreparedGossip( Player* player); + void prepareGossipMenu( Player *pPlayer, uint32 gossipid = 0 ); + void sendPreparedGossip( Player* player ); void OnGossipSelect(Player* player, uint32 option); void OnPoiSelect(Player* player, GossipOption const *gossip); diff --git a/src/game/Group.cpp b/src/game/Group.cpp index eade6412d..d850fcfee 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -42,6 +42,7 @@ Group::Group() m_lootMethod = (LootMethod)0; m_looterGuid = 0; m_lootThreshold = ITEM_QUALITY_UNCOMMON; + m_subGroupsCounts = NULL; for(int i=0; isecond.save->RemoveGroup(this); + + // Sub group counters clean up + if (m_subGroupsCounts) + delete[] m_subGroupsCounts; } bool Group::Create(const uint64 &guid, const char * name) @@ -79,6 +84,10 @@ bool Group::Create(const uint64 &guid, const char * name) m_leaderName = name; m_groupType = isBGGroup() ? GROUPTYPE_RAID : GROUPTYPE_NORMAL; + + if (m_groupType == GROUPTYPE_RAID) + _initRaidSubGroupsCounter(); + m_lootMethod = GROUP_LOOT; m_lootThreshold = ITEM_QUALITY_UNCOMMON; m_looterGuid = guid; @@ -134,6 +143,10 @@ bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool } m_groupType = (*result)[13].GetBool() ? GROUPTYPE_RAID : GROUPTYPE_NORMAL; + + if (m_groupType == GROUPTYPE_RAID) + _initRaidSubGroupsCounter(); + m_difficulty = (*result)[14].GetUInt8(); m_mainTank = (*result)[0].GetUInt64(); m_mainAssistant = (*result)[1].GetUInt64(); @@ -176,6 +189,9 @@ bool Group::LoadMemberFromDB(uint32 guidLow, uint8 subgroup, bool assistant) member.group = subgroup; member.assistant = assistant; m_memberSlots.push_back(member); + + SubGroupCounterIncrease(subgroup); + return true; } @@ -384,7 +400,7 @@ void Group::SendLootStartRoll(uint32 CountDown, const Roll &r) } } -void Group::SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r) +void Group::SendLootRoll(const uint64& SourceGuid, const uint64& TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r) { WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1)); data << uint64(SourceGuid); // guid of the item rolled @@ -408,7 +424,7 @@ void Group::SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, } } -void Group::SendLootRollWon(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r) +void Group::SendLootRollWon(const uint64& SourceGuid, const uint64& TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r) { WorldPacket data(SMSG_LOOT_ROLL_WON, (8+4+4+4+4+8+1+1)); data << uint64(SourceGuid); // guid of the item rolled @@ -451,7 +467,7 @@ void Group::SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r) } } -void Group::GroupLoot(uint64 playerGUID, Loot *loot, Creature *creature) +void Group::GroupLoot(const uint64& playerGUID, Loot *loot, Creature *creature) { std::vector::iterator i; ItemPrototype const *item; @@ -507,7 +523,7 @@ void Group::GroupLoot(uint64 playerGUID, Loot *loot, Creature *creature) } } -void Group::NeedBeforeGreed(uint64 playerGUID, Loot *loot, Creature *creature) +void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *creature) { ItemPrototype const *item; Player *player = objmgr.GetPlayer(playerGUID); @@ -561,7 +577,7 @@ void Group::NeedBeforeGreed(uint64 playerGUID, Loot *loot, Creature *creature) } } -void Group::MasterLoot(uint64 playerGUID, Loot* /*loot*/, Creature *creature) +void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creature) { Player *player = objmgr.GetPlayer(playerGUID); if(!player) @@ -597,7 +613,7 @@ void Group::MasterLoot(uint64 playerGUID, Loot* /*loot*/, Creature *creature) } } -void Group::CountRollVote(uint64 playerGUID, uint64 Guid, uint32 NumberOfPlayers, uint8 Choise) +void Group::CountRollVote(const uint64& playerGUID, const uint64& Guid, uint32 NumberOfPlayers, uint8 Choise) { Rolls::iterator rollI = GetRoll(Guid); if (rollI == RollId.end()) @@ -929,13 +945,20 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant) { // get first not-full group uint8 groupid = 0; - std::vector temp(MAXRAIDSIZE/MAXGROUPSIZE); - for(member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + if (m_subGroupsCounts) { - if (itr->group >= temp.size()) continue; - ++temp[itr->group]; - if(temp[groupid] >= MAXGROUPSIZE) - ++groupid; + bool groupFound = false; + for (; groupid < MAXRAIDSIZE/MAXGROUPSIZE; ++groupid) + { + if (m_subGroupsCounts[groupid] < MAXGROUPSIZE) + { + groupFound = true; + break; + } + } + // We are raid group and no one slot is free + if (!groupFound) + return false; } return _addMember(guid, name, isAssistant, groupid); @@ -958,6 +981,8 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u member.assistant = isAssistant; m_memberSlots.push_back(member); + SubGroupCounterIncrease(group); + if(player) { player->SetGroupInvite(NULL); @@ -995,7 +1020,11 @@ bool Group::_removeMember(const uint64 &guid) member_witerator slot = _getMemberWSlot(guid); if (slot != m_memberSlots.end()) + { + SubGroupCounterDecrease(slot->group); + m_memberSlots.erase(slot); + } if(!isBGGroup()) CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid='%u'", GUID_LOPART(guid)); @@ -1088,13 +1117,6 @@ void Group::_removeRolls(const uint64 &guid) } } -void Group::_convertToRaid() -{ - m_groupType = GROUPTYPE_RAID; - - if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); -} - bool Group::_setMembersGroup(const uint64 &guid, const uint8 &group) { member_witerator slot = _getMemberWSlot(guid); @@ -1102,7 +1124,11 @@ bool Group::_setMembersGroup(const uint64 &guid, const uint8 &group) return false; slot->group = group; + + SubGroupCounterIncrease(group); + if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE group_member SET subgroup='%u' WHERE memberGuid='%u'", group, GUID_LOPART(guid)); + return true; } @@ -1156,12 +1182,20 @@ void Group::ChangeMembersGroup(const uint64 &guid, const uint8 &group) if(!isRaidGroup()) return; Player *player = objmgr.GetPlayer(guid); + if (!player) { + uint8 prevSubGroup; + prevSubGroup = GetMemberGroup(guid); + + SubGroupCounterDecrease(prevSubGroup); + if(_setMembersGroup(guid, group)) SendUpdate(); } - else ChangeMembersGroup(player, group); + else + // This methods handles itself groupcounter decrease + ChangeMembersGroup(player, group); } // only for online members @@ -1171,6 +1205,11 @@ void Group::ChangeMembersGroup(Player *player, const uint8 &group) return; if(_setMembersGroup(player->GetGUID(), group)) { + uint8 prevSubGroup; + prevSubGroup = player->GetSubGroup(); + + SubGroupCounterDecrease(prevSubGroup); + player->GetGroupRef().setSubGroup(group); SendUpdate(); } diff --git a/src/game/Group.h b/src/game/Group.h index 971167aa5..fbe0c9f22 100644 --- a/src/game/Group.h +++ b/src/game/Group.h @@ -182,8 +182,8 @@ class MANGOS_DLL_SPEC Group ItemQualities GetLootThreshold() const { return m_lootThreshold; } // member manipulation methods - bool IsMember(uint64 guid) const { return _getMemberCSlot(guid) != m_memberSlots.end(); } - bool IsLeader(uint64 guid) const { return (GetLeaderGUID() == guid); } + bool IsMember(const uint64& guid) const { return _getMemberCSlot(guid) != m_memberSlots.end(); } + bool IsLeader(const uint64& guid) const { return (GetLeaderGUID() == guid); } bool IsAssistant(uint64 guid) const { member_citerator mslot = _getMemberCSlot(guid); @@ -193,7 +193,7 @@ class MANGOS_DLL_SPEC Group return mslot->assistant; } - bool SameSubGroup(uint64 guid1, uint64 guid2) const + bool SameSubGroup(uint64 guid1,const uint64& guid2) const { member_citerator mslot2 = _getMemberCSlot(guid2); if(mslot2==m_memberSlots.end()) @@ -211,6 +211,11 @@ class MANGOS_DLL_SPEC Group return (mslot1->group==slot2->group); } + bool HasFreeSlotSubGroup(uint8 subgroup) const + { + return (m_subGroupsCounts && m_subGroupsCounts[subgroup] < MAXGROUPSIZE); + } + bool SameSubGroup(Player const* member1, Player const* member2) const; MemberSlotList const& GetMemberSlots() const { return m_memberSlots; } @@ -229,7 +234,11 @@ class MANGOS_DLL_SPEC Group // some additional raid methods void ConvertToRaid() { - _convertToRaid(); + m_groupType = GROUPTYPE_RAID; + + _initRaidSubGroupsCounter(); + + if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); SendUpdate(); } void SetBattlegroundGroup(BattleGround *bg) { m_bgGroup = bg; } @@ -237,14 +246,14 @@ class MANGOS_DLL_SPEC Group void ChangeMembersGroup(const uint64 &guid, const uint8 &group); void ChangeMembersGroup(Player *player, const uint8 &group); - void SetAssistant(const uint64 &guid, const bool &state) + void SetAssistant(uint64 guid, const bool &state) { if(!isRaidGroup()) return; if(_setAssistantFlag(guid, state)) SendUpdate(); } - void SetMainTank(const uint64 &guid) + void SetMainTank(uint64 guid) { if(!isRaidGroup()) return; @@ -252,7 +261,7 @@ class MANGOS_DLL_SPEC Group if(_setMainTank(guid)) SendUpdate(); } - void SetMainAssistant(const uint64 &guid) + void SetMainAssistant(uint64 guid) { if(!isRaidGroup()) return; @@ -283,12 +292,12 @@ class MANGOS_DLL_SPEC Group /*********************************************************/ void SendLootStartRoll(uint32 CountDown, const Roll &r); - void SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r); - void SendLootRollWon(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r); + void SendLootRoll(const uint64& SourceGuid, const uint64& TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r); + void SendLootRollWon(const uint64& SourceGuid, const uint64& TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r); void SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r); - void GroupLoot(uint64 playerGUID, Loot *loot, Creature *creature); - void NeedBeforeGreed(uint64 playerGUID, Loot *loot, Creature *creature); - void MasterLoot(uint64 playerGUID, Loot *loot, Creature *creature); + void GroupLoot(const uint64& playerGUID, Loot *loot, Creature *creature); + void NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *creature); + void MasterLoot(const uint64& playerGUID, Loot *loot, Creature *creature); Rolls::iterator GetRoll(uint64 Guid) { Rolls::iterator iter; @@ -302,7 +311,7 @@ class MANGOS_DLL_SPEC Group return RollId.end(); } void CountTheRoll(Rolls::iterator roll, uint32 NumberOfPlayers); - void CountRollVote(uint64 playerGUID, uint64 Guid, uint32 NumberOfPlayers, uint8 Choise); + void CountRollVote(const uint64& playerGUID, const uint64& Guid, uint32 NumberOfPlayers, uint8 Choise); void EndRoll(); void LinkMember(GroupReference *pRef) { m_memberMgr.insertFirst(pRef); } @@ -329,6 +338,18 @@ class MANGOS_DLL_SPEC Group void _homebindIfInstance(Player *player); + void _initRaidSubGroupsCounter() + { + // Sub group counters initialization + if (!m_subGroupsCounts) + m_subGroupsCounts = new uint8[MAXRAIDSIZE / MAXGROUPSIZE]; + + memset((void*)m_subGroupsCounts, 0, (MAXRAIDSIZE / MAXGROUPSIZE)*sizeof(uint8)); + + for (member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + ++m_subGroupsCounts[itr->group]; + } + member_citerator _getMemberCSlot(uint64 Guid) const { for(member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) @@ -349,6 +370,18 @@ class MANGOS_DLL_SPEC Group return m_memberSlots.end(); } + void SubGroupCounterIncrease(uint8 subgroup) + { + if (m_subGroupsCounts) + ++m_subGroupsCounts[subgroup]; + } + + void SubGroupCounterDecrease(uint8 subgroup) + { + if (m_subGroupsCounts) + --m_subGroupsCounts[subgroup]; + } + MemberSlotList m_memberSlots; GroupRefManager m_memberMgr; InvitesList m_invitees; @@ -365,5 +398,6 @@ class MANGOS_DLL_SPEC Group uint64 m_looterGuid; Rolls RollId; BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES]; + uint8* m_subGroupsCounts; }; #endif diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index 545257b4e..5b112c095 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -543,6 +543,9 @@ void WorldSession::HandleGroupChangeSubGroupOpcode( WorldPacket & recv_data ) /** error handling **/ if(!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) return; + + if (!group->HasFreeSlotSubGroup(groupNr)) + return; /********************/ // everything's fine, do it diff --git a/src/game/Language.h b/src/game/Language.h index e512d297b..21a93cc15 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -166,8 +166,9 @@ enum MangosStrings LANG_MAIL_SENT = 169, LANG_SOUND_NOT_EXIST = 170, - LANG_TELEPORTED_TO_BY_CONSOLE = 171, - // Room for more level 1 172-199 not used + // 171, // not used + LANG_CONSOLE_COMMAND = 172, + // Room for more level 1 173-199 not used // level 2 chat LANG_NO_SELECTION = 200, @@ -316,7 +317,9 @@ enum MangosStrings LANG_GM_OFF = 333, LANG_GM_CHAT_ON = 334, LANG_GM_CHAT_OFF = 335, - // Room for more level 2 336-399 not used + LANG_YOU_REPAIR_ITEMS = 336, + LANG_YOUR_ITEMS_REPAIRED = 337, + // Room for more level 2 338-399 not used // level 3 chat LANG_SCRIPTS_RELOADED = 400, diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 243e39340..56e805f5b 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -309,9 +309,10 @@ bool ChatHandler::HandleGPSCommand(const char* args) zone_x, zone_y, ground_z, floor_z, have_map, have_vmap ); sLog.outDebug("Player %s GPS call for %s '%s' (%s: %u):", - m_session->GetPlayer()->GetName(), + GetName(), (obj->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), obj->GetName(), (obj->GetTypeId() == TYPEID_PLAYER ? "GUID" : "Entry"), (obj->GetTypeId() == TYPEID_PLAYER ? obj->GetGUIDLow(): obj->GetEntry()) ); + sLog.outDebug(GetMangosString(LANG_MAP_POSITION), obj->GetMapId(), (mapEntry ? mapEntry->name[sWorld.GetDefaultDbcLocale()] : "" ), zone_id, (zoneEntry ? zoneEntry->area_name[sWorld.GetDefaultDbcLocale()] : "" ), @@ -374,9 +375,8 @@ bool ChatHandler::HandleNamegoCommand(const char* args) } PSendSysMessage(LANG_SUMMONING, chr->GetName(),""); - - if (m_session->GetPlayer()->IsVisibleGloballyFor(chr)) - ChatHandler(chr).PSendSysMessage(LANG_SUMMONED_BY, m_session->GetPlayer()->GetName()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_SUMMONED_BY, GetName()); // stop flight if need if(chr->isInFlight()) @@ -655,7 +655,8 @@ bool ChatHandler::HandleModifyHPCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_HP, chr->GetName(), hp, hpm); - ChatHandler(chr).PSendSysMessage(LANG_YOURS_HP_CHANGED, m_session->GetPlayer()->GetName(), hp, hpm); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_HP_CHANGED, GetName(), hp, hpm); chr->SetMaxHealth( hpm ); chr->SetHealth( hp ); @@ -698,7 +699,8 @@ bool ChatHandler::HandleModifyManaCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_MANA, chr->GetName(), mana, manam); - ChatHandler(chr).PSendSysMessage(LANG_YOURS_MANA_CHANGED, m_session->GetPlayer()->GetName(), mana, manam); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_MANA_CHANGED, GetName(), mana, manam); chr->SetMaxPower(POWER_MANA,manam ); chr->SetPower(POWER_MANA, mana ); @@ -742,7 +744,8 @@ bool ChatHandler::HandleModifyEnergyCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_ENERGY, chr->GetName(), energy/10, energym/10); - ChatHandler(chr).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, m_session->GetPlayer()->GetName(), energy/10, energym/10); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, GetName(), energy/10, energym/10); chr->SetMaxPower(POWER_ENERGY,energym ); chr->SetPower(POWER_ENERGY, energy ); @@ -788,8 +791,8 @@ bool ChatHandler::HandleModifyRageCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_RAGE, chr->GetName(), rage/10, ragem/10); - // Special case: I use GetMangosString here to get local of destination char ;) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_RAGE_CHANGED), m_session->GetPlayer()->GetName(), rage/10, ragem/10); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_RAGE_CHANGED, GetName(), rage/10, ragem/10); chr->SetMaxPower(POWER_RAGE,ragem ); chr->SetPower(POWER_RAGE, rage ); @@ -867,11 +870,6 @@ bool ChatHandler::HandleModifyFactionCommand(const char* args) PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); - //sprintf((char*)buf,"%s changed your Faction to %i.", m_session->GetPlayer()->GetName(), factionid); - //FillSystemMessageData(&data, m_session, buf); - - //chr->GetSession()->SendPacket(&data); - chr->setFaction(factionid); chr->SetUInt32Value(UNIT_FIELD_FLAGS,flag); chr->SetUInt32Value(UNIT_NPC_FLAGS,npcflag); @@ -917,8 +915,8 @@ bool ChatHandler::HandleModifySpellCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_SPELLFLATID, spellflatid, val, mark, chr->GetName()); - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPELLFLATID_CHANGED, m_session->GetPlayer()->GetName(), spellflatid, val, mark); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPELLFLATID_CHANGED, GetName(), spellflatid, val, mark); WorldPacket data(SMSG_SET_FLAT_SPELL_MODIFIER, (1+1+2+2)); data << uint8(spellflatid); @@ -974,10 +972,8 @@ bool ChatHandler::HandleTaxiCheatCommand(const char* args) { chr->SetTaxiCheater(true); PSendSysMessage(LANG_YOU_GIVE_TAXIS, chr->GetName()); - - if(chr != m_session->GetPlayer()) - // to send localized data to target - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_TAXIS_ADDED), m_session->GetPlayer()->GetName()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_ADDED, GetName()); return true; } @@ -985,9 +981,8 @@ bool ChatHandler::HandleTaxiCheatCommand(const char* args) { chr->SetTaxiCheater(false); PSendSysMessage(LANG_YOU_REMOVE_TAXIS, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_TAXIS_REMOVED), m_session->GetPlayer()->GetName()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_REMOVED, GetName()); return true; } @@ -1028,9 +1023,8 @@ bool ChatHandler::HandleModifyASpeedCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_ASPEED_CHANGED), m_session->GetPlayer()->GetName(), ASpeed); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_ASPEED_CHANGED, GetName(), ASpeed); chr->SetSpeed(MOVE_WALK, ASpeed,true); chr->SetSpeed(MOVE_RUN, ASpeed,true); @@ -1071,9 +1065,8 @@ bool ChatHandler::HandleModifySpeedCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SPEED_CHANGED), m_session->GetPlayer()->GetName(), Speed); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPEED_CHANGED, GetName(), Speed); chr->SetSpeed(MOVE_RUN,Speed,true); @@ -1111,9 +1104,8 @@ bool ChatHandler::HandleModifySwimCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SWIM_SPEED_CHANGED), m_session->GetPlayer()->GetName(), Swim); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SWIM_SPEED_CHANGED, GetName(), Swim); chr->SetSpeed(MOVE_SWIM,Swim,true); @@ -1151,9 +1143,8 @@ bool ChatHandler::HandleModifyBWalkCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_BACK_SPEED_CHANGED), m_session->GetPlayer()->GetName(), BSpeed); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_BACK_SPEED_CHANGED, GetName(), BSpeed); chr->SetSpeed(MOVE_WALKBACK,BSpeed,true); @@ -1184,9 +1175,8 @@ bool ChatHandler::HandleModifyFlyCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_FLY_SPEED_CHANGED), m_session->GetPlayer()->GetName(), FSpeed); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_FLY_SPEED_CHANGED, GetName(), FSpeed); chr->SetSpeed(MOVE_FLY,FSpeed,true); @@ -1216,9 +1206,8 @@ bool ChatHandler::HandleModifyScaleCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SIZE_CHANGED), m_session->GetPlayer()->GetName(), Scale); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SIZE_CHANGED, GetName(), Scale); chr->SetFloatValue(OBJECT_FIELD_SCALE_X, Scale); @@ -1460,9 +1449,8 @@ bool ChatHandler::HandleModifyMountCommand(const char* args) } PSendSysMessage(LANG_YOU_GIVE_MOUNT, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_MOUNT_GIVED), m_session->GetPlayer()->GetName()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_MOUNT_GIVED, GetName()); chr->SetUInt32Value( UNIT_FIELD_FLAGS , 0x001000 ); chr->Mount(mId); @@ -1509,25 +1497,24 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args) if(newmoney <= 0 ) { PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_ALL_MONEY_GONE), m_session->GetPlayer()->GetName()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_ALL_MONEY_GONE, GetName()); chr->SetMoney(0); } else { PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), chr->GetName()); - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_MONEY_TAKEN), m_session->GetPlayer()->GetName(), abs(addmoney)); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, GetName(), abs(addmoney)); chr->SetMoney( newmoney ); } } else { PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, chr->GetName()); - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_MONEY_GIVEN), m_session->GetPlayer()->GetName(), addmoney); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, GetName(), addmoney); chr->ModifyMoney( addmoney ); } @@ -2020,14 +2007,8 @@ bool ChatHandler::HandleNameTeleCommand(const char * args) } PSendSysMessage(LANG_TELEPORTING_TO, chr->GetName(),"", tele->name.c_str()); - - if (m_session) - { - if(m_session->GetPlayer()->IsVisibleGloballyFor(chr)) - ChatHandler(chr).PSendSysMessage(LANG_TELEPORTED_TO_BY, m_session->GetPlayer()->GetName()); - } - else - ChatHandler(chr).SendSysMessage(LANG_TELEPORTED_TO_BY_CONSOLE); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_TELEPORTED_TO_BY, GetName()); // stop flight if need if(chr->isInFlight()) @@ -2097,9 +2078,8 @@ bool ChatHandler::HandleGroupTeleCommand(const char * args) } PSendSysMessage(LANG_TELEPORTING_TO, pl->GetName(),"", tele->name.c_str()); - - if (m_session->GetPlayer() != pl && m_session->GetPlayer()->IsVisibleGloballyFor(pl)) - ChatHandler(pl).PSendSysMessage(LANG_TELEPORTED_TO_BY, m_session->GetPlayer()->GetName()); + if (needReportToTarget(pl)) + ChatHandler(pl).PSendSysMessage(LANG_TELEPORTED_TO_BY, GetName()); // stop flight if need if(pl->isInFlight()) @@ -2191,9 +2171,8 @@ bool ChatHandler::HandleGroupgoCommand(const char* args) } PSendSysMessage(LANG_SUMMONING, pl->GetName(),""); - - if (m_session->GetPlayer()->IsVisibleGloballyFor(pl)) - ChatHandler(pl).PSendSysMessage(LANG_SUMMONED_BY, m_session->GetPlayer()->GetName()); + if (needReportToTarget(pl)) + ChatHandler(pl).PSendSysMessage(LANG_SUMMONED_BY, GetName()); // stop flight if need if(pl->isInFlight()) diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 647d7ebbb..5494cbc89 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -4047,3 +4047,23 @@ bool ChatHandler::HandleServerCorpsesCommand(const char* /*args*/) CorpsesErase(); return true; } + +bool ChatHandler::HandleRepairitemsCommand(const char* args) +{ + Player *target = getSelectedPlayer(); + + if(!target) + { + PSendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // Repair items + target->DurabilityRepairAll(false, 0, false); + + PSendSysMessage(LANG_YOU_REPAIR_ITEMS, target->GetName()); + if(needReportToTarget(target)) + ChatHandler(target).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, GetName()); + return true; +} diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 91a50b0d5..db4e2d8b6 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -100,6 +100,7 @@ bool ChatHandler::HandleReloadAllLootCommand(const char*) bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/) { HandleReloadNpcGossipCommand("a"); + HandleReloadNpcOptionCommand("a"); HandleReloadNpcTrainerCommand("a"); HandleReloadNpcVendorCommand("a"); return true; @@ -345,6 +346,14 @@ bool ChatHandler::HandleReloadMangosStringCommand(const char*) return true; } +bool ChatHandler::HandleReloadNpcOptionCommand(const char*) +{ + sLog.outString( "Re-Loading `npc_option` Table!" ); + objmgr.LoadNpcOptions(); + SendGlobalSysMessage("DB table `npc_option` reloaded."); + return true; +} + bool ChatHandler::HandleReloadNpcGossipCommand(const char*) { sLog.outString( "Re-Loading `npc_gossip` Table!" ); @@ -732,7 +741,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args) if(targetPlayer) { - ChatHandler(targetPlayer).PSendSysMessage(LANG_YOURS_SECURITY_CHANGED,m_session->GetPlayer()->GetName(), gm); + ChatHandler(targetPlayer).PSendSysMessage(LANG_YOURS_SECURITY_CHANGED,GetName(), gm); targetPlayer->GetSession()->SetSecurity(gm); } @@ -3671,14 +3680,14 @@ bool ChatHandler::HandleExploreCheatCommand(const char* args) if (flag != 0) { PSendSysMessage(LANG_YOU_SET_EXPLORE_ALL, chr->GetName()); - if(chr!=m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_ALL,m_session->GetPlayer()->GetName()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_ALL,GetName()); } else { PSendSysMessage(LANG_YOU_SET_EXPLORE_NOTHING, chr->GetName()); - if(chr!=m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_NOTHING,m_session->GetPlayer()->GetName()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_NOTHING,GetName()); } for (uint8 i=0; i<128; i++) @@ -5308,6 +5317,22 @@ bool ChatHandler::HandleBanListIPCommand(const char* args) bool ChatHandler::HandleRespawnCommand(const char* /*args*/) { + Unit* target = getSelectedUnit(); + + if(target) + { + if(target->GetTypeId()!=TYPEID_UNIT) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if(target->isDead()) + ((Creature*)target)->Respawn(); + return true; + } + Player* pl = m_session->GetPlayer(); CellPair p(MaNGOS::ComputeCellPair(pl->GetPositionX(), pl->GetPositionY())); diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index cc2fb033c..bebf2770e 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -295,8 +295,8 @@ void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data ) if(!Script->GossipHello( _player, unit )) { _player->TalkedToCreature(unit->GetEntry(),unit->GetGUID()); - unit->prepareGossipMenu(_player,0); - unit->sendPreparedGossip( _player ); + unit->prepareGossipMenu(_player); + unit->sendPreparedGossip(_player); } } @@ -335,14 +335,14 @@ void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data ) if(!code.empty()) { - - if(!Script->GossipSelectWithCode( _player, unit, _player->PlayerTalkClass->GossipOptionSender( option ), _player->PlayerTalkClass->GossipOptionAction( option ), code.c_str()) ) - unit->OnGossipSelect( _player, option ); + if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction( option ), code.c_str())) + unit->OnGossipSelect (_player, option); } else - - if(!Script->GossipSelect( _player, unit, _player->PlayerTalkClass->GossipOptionSender( option ), _player->PlayerTalkClass->GossipOptionAction( option )) ) - unit->OnGossipSelect( _player, option ); + { + if (!Script->GossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option))) + unit->OnGossipSelect (_player, option); + } } void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data ) diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 28562fbc5..c2efab314 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -563,6 +563,74 @@ void ObjectMgr::LoadCreatureLocales() sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() ); } +void ObjectMgr::LoadNpcOptionLocales() +{ + mNpcOptionLocaleMap.clear(); // need for reload case + + QueryResult *result = WorldDatabase.Query("SELECT entry," + "option_text_loc1,box_text_loc1,option_text_loc2,box_text_loc2," + "option_text_loc3,box_text_loc3,option_text_loc4,box_text_loc4," + "option_text_loc5,box_text_loc5,option_text_loc6,box_text_loc6," + "option_text_loc7,box_text_loc7,option_text_loc8,box_text_loc8 " + "FROM locales_npc_option"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outString(">> Loaded 0 npc_option locale strings. DB table `locales_npc_option` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + NpcOptionLocale& data = mNpcOptionLocaleMap[entry]; + + for(int i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[1+2*(i-1)].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.OptionText.size() <= idx) + data.OptionText.resize(idx+1); + + data.OptionText[idx] = str; + } + } + str = fields[1+2*(i-1)+1].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.BoxText.size() <= idx) + data.BoxText.resize(idx+1); + + data.BoxText[idx] = str; + } + } + } + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u npc_option locale strings", mNpcOptionLocaleMap.size() ); +} + void ObjectMgr::LoadCreatureTemplates() { sCreatureStorage.Load(); @@ -6899,6 +6967,58 @@ void ObjectMgr::LoadNpcTextId() sLog.outString( ">> Loaded %d NpcTextId ", count ); } +void ObjectMgr::LoadNpcOptions() +{ + m_mCacheNpcOptionList.clear(); // For reload case + + QueryResult *result = WorldDatabase.Query( + // 0 1 2 3 4 5 6 7 8 + "SELECT id,gossip_id,npcflag,icon,action,box_money,coded,option_text,box_text " + "FROM npc_option"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `npc_option`, table is empty!"); + return; + } + + barGoLink bar( result->GetRowCount() ); + + uint32 count = 0; + + do + { + bar.step(); + + Field* fields = result->Fetch(); + + GossipOption go; + go.Id = fields[0].GetUInt32(); + go.GossipId = fields[1].GetUInt32(); + go.NpcFlag = fields[2].GetUInt32(); + go.Icon = fields[3].GetUInt32(); + go.Action = fields[4].GetUInt32(); + go.BoxMoney = fields[5].GetUInt32(); + go.Coded = fields[6].GetUInt8()!=0; + go.OptionText = fields[7].GetCppString(); + go.BoxText = fields[8].GetCppString(); + + m_mCacheNpcOptionList.push_back(go); + + ++count; + + } while (result->NextRow()); + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %d npc_option entries", count ); +} + void ObjectMgr::AddVendorItem( uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 extendedcost ) { VendorItemData& vList = m_mCacheVendorItemMap[entry]; diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index b75918419..2b7a83875 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -139,6 +139,7 @@ typedef HM_NAMESPACE::hash_map QuestLocaleMap; typedef HM_NAMESPACE::hash_map NpcTextLocaleMap; typedef HM_NAMESPACE::hash_map PageTextLocaleMap; typedef HM_NAMESPACE::hash_map MangosStringLocaleMap; +typedef HM_NAMESPACE::hash_map NpcOptionLocaleMap; typedef std::multimap QuestRelations; @@ -229,6 +230,7 @@ struct PlayerCondition // NPC gossip text id typedef HM_NAMESPACE::hash_map CacheNpcTextIdMap; +typedef std::list CacheNpcOptionList; typedef HM_NAMESPACE::hash_map CacheVendorItemMap; typedef HM_NAMESPACE::hash_map CacheTrainerSpellMap; @@ -516,6 +518,7 @@ class ObjectMgr void LoadQuestLocales(); void LoadNpcTextLocales(); void LoadPageTextLocales(); + void LoadNpcOptionLocales(); void LoadInstanceTemplate(); void LoadGossipText(); @@ -546,6 +549,7 @@ class ObjectMgr void LoadWeatherZoneChances(); void LoadGameTele(); + void LoadNpcOptions(); void LoadNpcTextId(); void LoadVendors(); void LoadTrainerSpell(); @@ -639,6 +643,12 @@ class ObjectMgr if(itr==mPageTextLocaleMap.end()) return NULL; return &itr->second; } + NpcOptionLocale const* GetNpcOptionLocale(uint32 entry) const + { + NpcOptionLocaleMap::const_iterator itr = mNpcOptionLocaleMap.find(entry); + if(itr==mNpcOptionLocaleMap.end()) return NULL; + return &itr->second; + } GameObjectData const* GetGOData(uint32 guid) const { @@ -714,6 +724,8 @@ class ObjectMgr bool AddGameTele(GameTele& data); bool DeleteGameTele(std::string name); + CacheNpcOptionList const& GetNpcOptions() const { return m_mCacheNpcOptionList; } + uint32 GetNpcGossip(uint32 entry) const { CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry); @@ -845,6 +857,7 @@ class ObjectMgr NpcTextLocaleMap mNpcTextLocaleMap; PageTextLocaleMap mPageTextLocaleMap; MangosStringLocaleMap mMangosStringLocaleMap; + NpcOptionLocaleMap mNpcOptionLocaleMap; RespawnTimes mCreatureRespawnTimes; RespawnTimes mGORespawnTimes; @@ -855,6 +868,7 @@ class ObjectMgr typedef std::vector ConditionStore; ConditionStore mConditions; + CacheNpcOptionList m_mCacheNpcOptionList; CacheNpcTextIdMap m_mCacheNpcTextIdMap; CacheVendorItemMap m_mCacheVendorItemMap; CacheTrainerSpellMap m_mCacheTrainerSpellMap; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index da02a58e5..d17f47657 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -427,10 +427,8 @@ Player::~Player () { CleanupsBeforeDelete(); - if(m_uint32Values) // only for fully created Object - { - sSocialMgr.RemovePlayerSocial(GetGUIDLow()); - } + // it must be unloaded already in PlayerLogout and accessed only for loggined player + //m_social = NULL; // Note: buy back item already deleted from DB when player was saved for(int i = 0; i < PLAYER_SLOTS_COUNT; ++i) diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp index 42eea5082..0334332a9 100644 --- a/src/game/QuestHandler.cpp +++ b/src/game/QuestHandler.cpp @@ -103,8 +103,8 @@ void WorldSession::HandleQuestgiverHelloOpcode( WorldPacket & recv_data ) if(Script->GossipHello( _player, pCreature ) ) return; - pCreature->prepareGossipMenu(_player,0); - pCreature->sendPreparedGossip( _player ); + pCreature->prepareGossipMenu(_player); + pCreature->sendPreparedGossip(_player); } void WorldSession::HandleQuestgiverAcceptQuestOpcode( WorldPacket & recv_data ) diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index a4b28a814..2b174aefb 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -4953,7 +4953,7 @@ void Spell::EffectDuel(uint32 i) Player *target = (Player*)unitTarget; // caster or target already have requested duel - if( caster->duel || target->duel || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) ) + if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) ) return; // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities) diff --git a/src/game/World.cpp b/src/game/World.cpp index f0b9ada8c..fa789a661 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -948,6 +948,7 @@ void World::SetInitialWorldSettings() objmgr.LoadQuestLocales(); objmgr.LoadNpcTextLocales(); objmgr.LoadPageTextLocales(); + objmgr.LoadNpcOptionLocales(); objmgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) sLog.outString( "Loading Page Texts..." ); @@ -1114,6 +1115,9 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading Npc Text Id..." ); objmgr.LoadNpcTextId(); // must be after load Creature and NpcText + sLog.outString( "Loading Npc Options..." ); + objmgr.LoadNpcOptions(); + sLog.outString( "Loading vendors..." ); objmgr.LoadVendors(); // must be after load CreatureTemplate and ItemTemplate diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 7e08e0871..136d74202 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -380,6 +380,7 @@ void WorldSession::LogoutPlayer(bool Save) ///- Delete the player object _player->CleanupsBeforeDelete(); // do some cleanup before deleting to prevent crash at crossreferences to already deleted data + sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); delete _player; _player = NULL; diff --git a/win/VC71/.gitignore b/win/VC71/.gitignore index c0bac5034..5c035e465 100644 --- a/win/VC71/.gitignore +++ b/win/VC71/.gitignore @@ -14,3 +14,4 @@ *__x64_Debug* *__Win32_Release* *__x64_Release* +*.user diff --git a/win/VC80/.gitignore b/win/VC80/.gitignore index c0bac5034..5c035e465 100644 --- a/win/VC80/.gitignore +++ b/win/VC80/.gitignore @@ -14,3 +14,4 @@ *__x64_Debug* *__Win32_Release* *__x64_Release* +*.user diff --git a/win/VC90/.gitignore b/win/VC90/.gitignore index 9123b0a96..5c035e465 100644 --- a/win/VC90/.gitignore +++ b/win/VC90/.gitignore @@ -14,4 +14,4 @@ *__x64_Debug* *__Win32_Release* *__x64_Release* -*.user \ No newline at end of file +*.user