Index: guildmaster.patch =================================================================== Index: Makefile.am =================================================================== --- Makefile.am (revision 1707) +++ Makefile.am (working copy) @@ -48,6 +48,7 @@ include/sc_instance.cpp \ include/sc_instance.h \ scripts/battlegrounds/battleground.cpp \ +scripts/custom/guildmaster.cpp \ scripts/eastern_kingdoms/alterac_mountains.cpp \ scripts/eastern_kingdoms/arathi_highlands.cpp \ scripts/eastern_kingdoms/blasted_lands.cpp \ Index: scripts/custom/guildmaster.cpp =================================================================== --- scripts/custom/guildmaster.cpp (revision 0) +++ scripts/custom/guildmaster.cpp (revision 0) @@ -0,0 +1,342 @@ +/* проверка русского */ +#include "precompiled.h" + +extern DatabaseMysql SD2Database; + +#define MSG_GOSSIP_TELE "Отправиться в Резиденцию гильдии" +#define MSG_GOSSIP_BUY "Купить Резиденцию гильдии (35 000 золотых)" +#define MSG_GOSSIP_SELL "Продать Резиденцию гильдии (20 000 золотых)" +#define MSG_GOSSIP_NEXTPAGE "Далее -->" +#define MSG_INCOMBAT "Вы в бою!" +#define MSG_NOGUILDHOUSE "Ваша гильдия не имеет Резиденции!" +#define MSG_NOFREEGH "Все Резиденции куплены." +#define MSG_ALREADYHAVEGH "У вас уже есть Резиденция (%s)." +#define MSG_NOTENOUGHMONEY "Денег не хватает. Требуется %u золотых для покупки Резиденции." +#define MSG_GHOCCUPIED "Эта Резиденция уже выкуплена" +#define MSG_CONGRATULATIONS "Поздравляю! Теперь у вашей гильдии есть Резиденция." +#define MSG_SOLD "Вы продали Резиденцию гильдии и получили %u золотых." +#define MSG_NOTINGUILD "Вы не состоите в гильдии, найдите себе что-нибудь." + +#define CODE_SELL "SELL" +#define MSG_CODEBOX_SELL "Введите \"" CODE_SELL "\" в следующем окне, если и правда хотите продать Резиденцию гильдии." + +#define OFFSET_GH_ID_TO_ACTION 1500 +#define OFFSET_SHOWBUY_FROM 10000 + +#define ACTION_TELE 1001 +#define ACTION_SHOW_BUYLIST 1002 //deprecated. Use (OFFSET_SHOWBUY_FROM + 0) instead +#define ACTION_SELL_GUILDHOUSE 1003 + +#define ICON_GOSSIP_BALOON 0 +#define ICON_GOSSIP_WING 2 +#define ICON_GOSSIP_BOOK 3 +#define ICON_GOSSIP_WHEEL1 4 +#define ICON_GOSSIP_WHEEL2 5 +#define ICON_GOSSIP_GOLD 6 +#define ICON_GOSSIP_BALOONDOTS 7 +#define ICON_GOSSIP_TABARD 8 +#define ICON_GOSSIP_XSWORDS 9 + +#define COST_GH_BUY 350000000 // 35 000 g. +#define COST_GH_SELL 200000000 // 20 000 g. + +#define GOSSIP_COUNT_MAX 10 + +bool isPlayerGuildLeader(Player *player) +{ + return (player->GetRank() == 0) && (player->GetGuildId() != 0); +} + +bool getGuildHouseCoords(uint32 guildId, float &x, float &y, float &z, uint32 &map) +{ + if (guildId == 0) + { + //if player has no guild + return false; + } + + QueryResult *result; + result = SD2Database.PQuery("SELECT `x`, `y`, `z`, `map` FROM `guildhouses` WHERE `guildId` = %u", guildId); + if(result) + { + Field *fields = result->Fetch(); + x = fields[0].GetFloat(); + y = fields[1].GetFloat(); + z = fields[2].GetFloat(); + map = fields[3].GetUInt32(); + delete result; + return true; + } + return false; +} + +void teleportPlayerToGuildHouse(Player *player, Creature *_creature) +{ + if (player->GetGuildId() == 0) + { + //if player has no guild + _creature->MonsterWhisper(MSG_NOTINGUILD, player->GetGUID()); + return; + } + + if (!player->getAttackers().empty()) + { + //if player in combat + _creature->MonsterSay(MSG_INCOMBAT, LANG_UNIVERSAL, player->GetGUID()); + return; + } + + float x, y, z; + uint32 map; + + if (getGuildHouseCoords(player->GetGuildId(), x, y, z, map)) + { + //teleport player to the specified location + player->TeleportTo(map, x, y, z, 0.0f); + } + else + _creature->MonsterWhisper(MSG_NOGUILDHOUSE, player->GetGUID()); + +} + +bool showBuyList(Player *player, Creature *_creature, uint32 showFromId = 0) +{ + //show not occupied guildhouses + + QueryResult *result; + result = SD2Database.PQuery("SELECT `id`, `comment` FROM `guildhouses` WHERE `guildId` = 0 AND `id` > %u ORDER BY `id` ASC LIMIT %u", + showFromId, GOSSIP_COUNT_MAX); + + if (result) + { + uint32 guildhouseId = 0; + std::string comment = ""; + do + { + + Field *fields = result->Fetch(); + + guildhouseId = fields[0].GetInt32(); + comment = fields[1].GetString(); + + //send comment as a gossip item + //transmit guildhouseId in Action variable + player->ADD_GOSSIP_ITEM(ICON_GOSSIP_TABARD, comment, GOSSIP_SENDER_MAIN, + guildhouseId + OFFSET_GH_ID_TO_ACTION); + + } while (result->NextRow()); + + if (result->GetRowCount() == GOSSIP_COUNT_MAX) + { + //assume that we have additional page + //add link to next GOSSIP_COUNT_MAX items + player->ADD_GOSSIP_ITEM(ICON_GOSSIP_BALOONDOTS, MSG_GOSSIP_NEXTPAGE, GOSSIP_SENDER_MAIN, + guildhouseId + OFFSET_SHOWBUY_FROM); + } + + delete result; + + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, _creature->GetGUID()); + + return true; + } else + { + if (!showFromId) + { + //all guildhouses are occupied + _creature->MonsterWhisper(MSG_NOFREEGH, player->GetGUID()); + player->CLOSE_GOSSIP_MENU(); + } else + { + //this condition occurs when COUNT(guildhouses) % GOSSIP_COUNT_MAX == 0 + //just show GHs from beginning + showBuyList(player, _creature, 0); + } + } + + return false; +} + +bool isPlayerHasGuildhouse(Player *player, Creature *_creature, bool whisper = false) +{ + + QueryResult *result; + + result = SD2Database.PQuery("SELECT `comment` FROM `guildhouses` WHERE `guildId` = %u", + player->GetGuildId()); + + if (result) + { + if (whisper) + { + //whisper to player "already have etc..." + Field *fields = result->Fetch(); + char msg[100]; + sprintf(msg, MSG_ALREADYHAVEGH, fields[0].GetString()); + _creature->MonsterWhisper(msg, player->GetGUID()); + } + + delete result; + return true; + } + return false; + +} + +void buyGuildhouse(Player *player, Creature *_creature, uint32 guildhouseId) +{ + if (player->GetMoney() < COST_GH_BUY) + { + //show how much money player need to buy GH (in gold) + char msg[100]; + sprintf(msg, MSG_NOTENOUGHMONEY, COST_GH_BUY / 10000); + _creature->MonsterWhisper(msg, player->GetGUID()); + return; + } + + if (isPlayerHasGuildhouse(player, _creature, true)) + { + //player already have GH + return; + } + + QueryResult *result; + + //check if somebody already occupied this GH + result = SD2Database.PQuery("SELECT `id` FROM `guildhouses` WHERE `id` = %u AND `guildId` <> 0", + guildhouseId); + + if (result) + { + delete result; + _creature->MonsterWhisper(MSG_GHOCCUPIED, player->GetGUID()); + return; + } + + //update DB + result = SD2Database.PQuery("UPDATE `guildhouses` SET `guildId` = %u WHERE `id` = %u", + player->GetGuildId(), guildhouseId); + + if (result) + delete result; + + player->ModifyMoney(-COST_GH_BUY); + _creature->MonsterSay(MSG_CONGRATULATIONS, LANG_UNIVERSAL, player->GetGUID()); + +} + +void sellGuildhouse(Player *player, Creature *_creature) +{ + if (isPlayerHasGuildhouse(player, _creature)) + { + QueryResult *result; + + result = SD2Database.PQuery("UPDATE `guildhouses` SET `guildId` = 0 WHERE `guildId` = %u", + player->GetGuildId()); + + if (result) + delete result; + + player->ModifyMoney(COST_GH_SELL); + + //display message e.g. "here your money etc." + char msg[100]; + sprintf(msg, MSG_SOLD, COST_GH_SELL / 10000); + _creature->MonsterWhisper(msg, player->GetGUID()); + } +} + +bool GossipHello_guildmaster(Player *player, Creature *_creature) +{ + player->ADD_GOSSIP_ITEM(ICON_GOSSIP_BALOON, MSG_GOSSIP_TELE, + GOSSIP_SENDER_MAIN, ACTION_TELE); + + if (isPlayerGuildLeader(player)) + { + //show additional menu for guild leader + player->ADD_GOSSIP_ITEM(ICON_GOSSIP_GOLD, MSG_GOSSIP_BUY, + GOSSIP_SENDER_MAIN, ACTION_SHOW_BUYLIST); + if (isPlayerHasGuildhouse(player, _creature)) + { + //and additional for guildhouse owner + player->PlayerTalkClass->GetGossipMenu().AddMenuItem(ICON_GOSSIP_GOLD, MSG_GOSSIP_SELL, GOSSIP_SENDER_MAIN, ACTION_SELL_GUILDHOUSE, MSG_CODEBOX_SELL, 0, true); + } + } + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, _creature->GetGUID()); + return true; +} + + +bool GossipSelect_guildmaster(Player *player, Creature *_creature, uint32 sender, uint32 action ) +{ + if (sender != GOSSIP_SENDER_MAIN) + return false; + + switch (action) + { + case ACTION_TELE: + //teleport player to GH + player->CLOSE_GOSSIP_MENU(); + teleportPlayerToGuildHouse(player, _creature); + break; + case ACTION_SHOW_BUYLIST: + //show list of GHs which currently not occupied + showBuyList(player, _creature); + break; + default: + if (action > OFFSET_SHOWBUY_FROM) + { + showBuyList(player, _creature, action - OFFSET_SHOWBUY_FROM); + } else if (action > OFFSET_GH_ID_TO_ACTION) + { + //player clicked on buy list + player->CLOSE_GOSSIP_MENU(); + //get guildhouseId from action + //guildhouseId = action - OFFSET_GH_ID_TO_ACTION + buyGuildhouse(player, _creature, action - OFFSET_GH_ID_TO_ACTION); + } + break; + } + + return true; +} + +bool GossipSelectWithCode_guildmaster( Player *player, Creature *_creature, + uint32 sender, uint32 action, const char* sCode ) +{ + if(sender == GOSSIP_SENDER_MAIN) + { + if(action == ACTION_SELL_GUILDHOUSE) + { + int i = -1; + try + { + //compare code + if (strlen(sCode) + 1 == sizeof CODE_SELL) + i = strcmp(CODE_SELL, sCode); + + } catch(char *str) {error_db_log(str);} + + if (i == 0) + { + //right code + sellGuildhouse(player, _creature); + } + player->CLOSE_GOSSIP_MENU(); + return true; + } + } + return false; +} + + +void AddSC_guildmaster() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "guildmaster"; + newscript->pGossipHello = &GossipHello_guildmaster; + newscript->pGossipSelect = &GossipSelect_guildmaster; + newscript->pGossipSelectWithCode = &GossipSelectWithCode_guildmaster; + newscript->RegisterSelf(); +} Index: sql/guildmaster_mangos.sql =================================================================== --- sql/guildmaster_mangos.sql (revision 0) +++ sql/guildmaster_mangos.sql (revision 0) @@ -0,0 +1,19 @@ + +INSERT INTO `creature_template` (`entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed_walk`, `speed_run`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `dynamicflags`, `family`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `unk16`, `unk17`, `RacialLeader`, `RegenHealth`, `equipment_id`, `flags_extra`, `ScriptName`) VALUES +(13, 18748, 5525, 20711, 17895, 'Bruenno Guilde', 'Guildhouse Keeper', 81, 82, 6700, 24000, 5598, 5875, 10328, 35, 35, 1, 1.48, 1.14286, 1, 0, 339, 509, 0, 127, 1, 1500, 1500, 2, 0, 0, 0, 271, 407, 102, 7, 0, 0, 0, 0, 0, 0, '', 1, 3, 1, 1, 0, 1, 0, 0, 'guildmaster'); + +INSERT INTO `locales_creature` (`entry`, `name_loc8`, `subname_loc8`) VALUES +(13, 'Брюенно Гвильде', 'Хранитель Гильдейских Домов'); + +INSERT INTO `creature` (`id`, `map`, `spawnMask`, `phaseMask`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `currentwaypoint`, `curhealth`, `curmana`, `DeathState`, `MovementType`) VALUES +(131001, 13, 0, 1, 1, 0, 0, -8888.29, 607.158, 102.304, 1.83473, 360, 0, 0, 6700, 5598, 0, 0), +(131002, 13, 1, 1, 1, 0, 0, 1585.22, -4295.73, 37.8993, 2.62324, 360, 0, 0, 6700, 5598, 0, 0), +(131003, 13, 530, 1, 1, 5525, 0, -4083.11, -11629.9, -138.654, 3.41019, 360, 0, 0, 6700, 5598, 0, 0), +(131004, 13, 530, 1, 1, 5525, 0, 9469.36, -7353.5, 23.4994, 1.98703, 360, 0, 0, 6700, 5598, 0, 0), +(131005, 13, 1, 1, 1, 0, 0, 10078.7, 2184.92, 1346.62, 1.63859, 360, 0, 0, 6700, 5598, 0, 0), +(131006, 13, 0, 1, 1, 5525, 0, -5011.4, -992.523, 503.882, 3.81506, 360, 0, 0, 6700, 5598, 0, 0), +(131007, 13, 530, 1, 1, 0, 0, -1867.98, 5421.33, -10.4635, 1.10935, 360, 0, 0, 6700, 5598, 0, 0), +(131008, 13, 0, 1, 1, 0, 0, 1591.84, 202.21, -55.3424, 1.66698, 360, 0, 0, 6700, 5598, 0, 0), +(131009, 13, 1, 1, 1, 0, 0, -1299.16, 131.465, 131.464, 5.34853, 360, 0, 0, 6700, 5598, 0, 0), +(131010, 13, 1, 1, 1, 0, 0, 16212.6, 16256.7, 14.7189, 0.270119, 300, 0, 0, 6700, 5598, 0, 0), +(131011, 13, 1, 1, 1, 0, 0, 16211.3, 16262.3, 14.7766, 0.346283, 300, 0, 0, 6700, 5598, 0, 0); Index: sql/guildmaster_scriptdev2.sql =================================================================== --- sql/guildmaster_scriptdev2.sql (revision 0) +++ sql/guildmaster_scriptdev2.sql (revision 0) @@ -0,0 +1,35 @@ + +CREATE TABLE `guildhouses` ( + `id` int(8) unsigned NOT NULL AUTO_INCREMENT, + `guildId` bigint(20) NOT NULL DEFAULT '0', + `x` double NOT NULL, + `y` double NOT NULL, + `z` double NOT NULL, + `map` int(11) NOT NULL, + `comment` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC AUTO_INCREMENT=23; + +INSERT INTO `guildhouses` (`id`, `guildId`, `x`, `y`, `z`, `map`, `comment`) VALUES +(1, 0, 16222, 16266, 14.2, 1, 'GM Island'), +(2, 0, -10711, 2483, 8, 1, 'Tauren village at Veiled Sea (Silithus)'), +(3, 0, -8323, -343, 146, 0, 'Fishing outside an Northshire Abbey (Elwynn Forest'), +(4, 0, 7368, -1560, 163, 1, 'Troll Village in mountains (Darkshore)'), +(5, 0, -4151, -1400, 198, 0, 'Dwarven village outside Ironforge (Wetlands)'), +(6, 0, -1840, -4233, 2.14, 0, 'Dwarven village (Arathi Highlands, Forbidding Sea)'), +(7, 0, -2612, -2163, 166, 0, 'Crashed zeppelin (Wetlands, Dun Modr)'), +(8, 0, -723, -1076, 179, 1, 'Tauren camp (Mulgore, Red Rock)'), +(9, 0, -206, 1666, 80, 0, 'Shadowfang Keep an outside instance (Silverpine Forest)'), +(10, 0, -6374, 1262, 7, 0, 'Harbor house outside Stormwind (Elwynn Forest)'), +(11, 0, -8640, 580, 96, 0, 'Empty jail between canals (Stormwind)'), +(12, 0, -4844, -1066, 502, 0, 'Old Ironforge'), +(13, 0, -4863, -1658, 503.5, 0, 'Ironforge Airport'), +(14, 0, 1146, -165, 313, 37, 'Azshara Crater instance (Alliance entrance)'), +(15, 0, -123, 858, 298, 37, 'Azshara Crater instance (Horde entrance)'), +(16, 0, 4303, -2760, 16.8, 0, 'Quel''Thalas Tower'), +(17, 0, -6161, -790, 423, 0, 'Crashed gnome airplane (between Dun Morogh and Searing Gorge)'), +(18, 0, -11790, -1640, 54.7, 0, 'Zul''Gurub an outside instance (Stranglethorn Vale)'), +(19, 0, -11805, -4754, 6, 1, 'Goblin village (Tanaris, South Seas)'), +(20, 0, -9296, 670, 132, 0, 'Villains camp outside an Stormwind (Elwynn Forest)'), +(21, 0, 3414, -3380, 142.2, 0, 'Stratholm an outside instance'), +(22, 0, 4858, -1840, 1156, 1, 'Inside Hyjal Cave'); Index: system/ScriptLoader.cpp =================================================================== --- system/ScriptLoader.cpp (revision 1707) +++ system/ScriptLoader.cpp (working copy) @@ -8,6 +8,7 @@ extern void AddSC_battleground(); //custom +extern void AddSC_guildmaster(); //examples extern void AddSC_example_creature(); @@ -416,6 +417,7 @@ AddSC_battleground(); //custom + AddSC_guildmaster(); //examples AddSC_example_creature(); Index: VC100/100ScriptDev2.vcxproj =================================================================== --- VC100/100ScriptDev2.vcxproj (revision 1707) +++ VC100/100ScriptDev2.vcxproj (working copy) @@ -215,6 +215,7 @@ + Index: VC80/80ScriptDev2.vcproj =================================================================== --- VC80/80ScriptDev2.vcproj (revision 1707) +++ VC80/80ScriptDev2.vcproj (working copy) @@ -405,6 +405,7 @@ Name="custom" > + Index: VC90/90ScriptDev2.vcproj =================================================================== --- VC90/90ScriptDev2.vcproj (revision 1707) +++ VC90/90ScriptDev2.vcproj (working copy) @@ -404,6 +404,7 @@ Name="custom" > +