• This is a read only backup of the old Emudevs forum. If you want to have anything removed, please message me on Discord: KittyKaev

Guildhouse Script

Neccta

Exalted Member
I'm using a guild house script by Lordpsyan it works fine but if all guild houses are bought it will crash the server when you click on "Buy Guildhouse" It should return with "Unfortunately, all GuildHouses are in use."
That part of the code starts on line 275. (This code will work on the latest TrinityCore, so It must be something with Eluna I would imagine).

Source: here

Code:
From 80ff52718e7520151567f4b582111a502c9240cf Mon Sep 17 00:00:00 2001
From: LordPsyan <realmsofwarcraft@gmail.com>
Date: Sun, 15 Jun 2014 18:15:27 -0400
Subject: [PATCH] GuildHouses

---
 .../guildhouses/world_guildhouses.sql              |   67 +++++
 src/server/game/Scripting/ScriptLoader.cpp         |    5 +-
 src/server/scripts/Custom/CMakeLists.txt           |    1 +
 src/server/scripts/Custom/guildmaster.cpp          |  316 ++++++++++++++++++++
 src/server/worldserver/worldserver.conf.dist       |   30 ++
 5 files changed, 418 insertions(+), 1 deletion(-)
 create mode 100644 sql/TrinityCore-Patches/guildhouses/world_guildhouses.sql
 create mode 100644 src/server/scripts/Custom/guildmaster.cpp

diff --git a/sql/TrinityCore-Patches/guildhouses/world_guildhouses.sql b/sql/TrinityCore-Patches/guildhouses/world_guildhouses.sql
new file mode 100644
index 0000000..71fe6f9
--- /dev/null
+++ b/sql/TrinityCore-Patches/guildhouses/world_guildhouses.sql
@@ -0,0 +1,67 @@
+-- ----------------------------
+-- Table structure for guildhouses
+-- ----------------------------
+
+DROP TABLE IF EXISTS `guildhouses`;
+
+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 AUTO_INCREMENT=42 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
+
+-- ----------------------------
+-- Records
+-- ----------------------------
+INSERT INTO `guildhouses` 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)'),
+('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) DELETE'),
+('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', '4654', '-3772', '944', '1', 'Kalimdor Hyjal (Aka World Tree)'),
+('23', '0', '2176', '-4766', '55', '1', 'The Ring of Valor (Aka. Orgrimmar Arena)'),
+('24', '0', '1951.512085', '1530.475586', '247.288147', '1', 'Stonetalon Logging Camp'),
+('25', '0', '2813.660645', '2248.552979', '215.524643', '1', 'Stonetalon Ruins'),
+('28', '0', '9725.27', '-21.43', '20.03', '1', 'Teldrassil Furbold camp'),
+('29', '0', '-3855', '-3479', '579', '0', 'Wetlands mountain camp'),
+('30', '0', '-5362', '-2540', '485', '0', 'Ortell\'s Hideout'),
+('31', '0', '-12865', '-1396', '115', '0', 'Stranglethorn Secret Cave'),
+('32', '0', '-11073', '-1956', '39', '0', 'Karazhan Smiley'),
+('33', '0', '-11084', '-1801', '53', '0', 'Well of the Forgotten (Aka. Karazhan Crypt or Lower Karazhan)'),
+('34', '0', '1683.235474', '286.458801', '-45.451775', '0', 'Undercity Top Tier'),
+('35', '0', '-8521.3', '599.5', '101.399338', '0', 'Stormwind Cut-Throat Alley'),
+('36', '0', '-5933', '452', '509', '0', 'Forgotten gnome camp'),
+('37', '0', '-920.231323', '7096.489258', '170.35289', '530', 'Outland Nagrand : Newton\'s Remains'),
+('38', '0', '-2140.501953', '9142.6875', '137.041855', '530', 'Outland Nagrand : Tomb'),
+('39', '0', '-483.401794', '7461.944824', '186.120987', '530', 'Outland Nagrand: Challe\'s Home for Little Tykes'),
+('40', '0', '2387.753906', '3191.757324', '152.669388', '530', 'Outland Netherstorm: Nova\'s Shrine');
+
+-- *************************
+-- * NPC Guildhouse Keeper *
+-- *************************
+
+DELETE FROM creature_template WHERE `entry`=13;
+
+INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `modelid1`, `modelid2`, `modelid3`, `modelid4`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `spell5`, `spell6`, `spell7`, `spell8`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `Health_mod`, `Mana_mod`, `Armor_mod`, `RacialLeader`, `questItem1`, `questItem2`, `questItem3`, `questItem4`, `questItem5`, `questItem6`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
+('13','0','0','0','0','0','26789','0','0','0','Beltez','Guildhouse Keeper',NULL,'0','80','80','0','35','1','1','1.14286','0.75','0','181','189','0','158','1','1400','1900','1','0','0','8','0','0','0','0','0','0','0','0','7','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','','1','3','1','1','1','1','0','0','0','0','0','0','0','0','1','0','0','guildmaster','12340');
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 07db809..991be6c 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -97,6 +97,8 @@ void AddSC_npc_innkeeper();
 void AddSC_npcs_special();
 void AddSC_npc_taxi();
 void AddSC_achievement_scripts();
+//guildhouse
+void AddSC_guildmaster();
 
 //eastern kingdoms
 void AddSC_alterac_valley();                 //Alterac Valley
@@ -1441,6 +1443,7 @@ void AddCustomScripts()
 {
 #ifdef SCRIPTS
     /* This is where custom scripts should be added. */
-
+    //guildhouse
+    AddSC_guildmaster();
 #endif
 }
diff --git a/src/server/scripts/Custom/CMakeLists.txt b/src/server/scripts/Custom/CMakeLists.txt
index 78db719..2dda6bb 100644
--- a/src/server/scripts/Custom/CMakeLists.txt
+++ b/src/server/scripts/Custom/CMakeLists.txt
@@ -10,6 +10,7 @@
 
 set(scripts_STAT_SRCS
   ${scripts_STAT_SRCS}
+  Custom/guildmaster.cpp
 )
 
 message("  -> Prepared: Custom")
diff --git a/src/server/scripts/Custom/guildmaster.cpp b/src/server/scripts/Custom/guildmaster.cpp
new file mode 100644
index 0000000..d978c1c
--- /dev/null
+++ b/src/server/scripts/Custom/guildmaster.cpp
@@ -0,0 +1,316 @@
+#include "ScriptPCH.h"
+#include "Config.h"
+
+//extern DatabaseMysql SD2Database;
+
+//extern WorldDatabaseWorkerPool WorldDatabase;
+
+#define MSG_GOSSIP_TELE          "Teleport to GuildHouse"
+#define MSG_GOSSIP_BUY           "Buy GuildHouse"
+#define MSG_GOSSIP_SELL          "Sell GuildHouse"
+#define MSG_GOSSIP_NEXTPAGE      "Next -->"
+#define MSG_INCOMBAT             "You are in combat and cannot be teleported to your GuildHouse."
+#define MSG_NOGUILDHOUSE         "Your guild currently does not own a GuildHouse."
+#define MSG_NOFREEGH             "Unfortunately, all GuildHouses are in use."
+#define MSG_ALREADYHAVEGH        "Sorry, but you already own a GuildHouse (%s)."
+#define MSG_NOTENOUGHMONEY       "You do not have the %u gold required to purchase a GuildHouse."
+#define MSG_GHOCCUPIED           "This GuildHouse is unavailable for purchase as it is currently in use."
+#define MSG_CONGRATULATIONS      "Congratulations! You have successfully purchased a GuildHouse."
+#define MSG_SOLD                 "You have sold your GuildHouse and have received %u gold."
+#define MSG_NOTINGUILD           "You need to be in a guild before you can use a GuildHouse."
+#define MSG_SELL_CONFIRM         "Are you sure you want to sell your guildhouse for half the buy price?"
+
+#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 10000000 //1000 g.
+#define COST_GH_SELL 5000000 //500 g.
+
+#define GOSSIP_COUNT_MAX 10
+
+class guildmaster : public CreatureScript
+{
+ public:
+ guildmaster() : CreatureScript("guildmaster") { }
+
+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 = WorldDatabase.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();
+ return true;
+ }
+
+ return false;
+}
+
+void teleportPlayerToGuildHouse(Player *player, Creature *_creature)
+{
+ if (player->GetGuildId() == 0)
+ {
+ //if player has no guild
+ _creature->MonsterWhisper(MSG_NOTINGUILD, player);
+ return;
+ }
+
+ if (!player->getAttackers().empty())
+ {
+ //if player in combat
+ _creature->MonsterSay(MSG_INCOMBAT, LANG_UNIVERSAL, player);
+ 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);
+}
+
+bool showBuyList(Player *player, Creature *_creature, uint32 showFromId = 0)
+{
+ //show not occupied guildhouses
+
+ QueryResult result;
+ result = WorldDatabase.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);
+ }
+
+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, _creature->GetGUID());
+
+ return true;
+ }
+ else
+ {
+ if (showFromId = 0)
+ {
+ //all guildhouses are occupied
+ _creature->MonsterWhisper(MSG_NOFREEGH, player);
+ 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 = WorldDatabase.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].GetCString());
+ _creature->MonsterWhisper(msg, player);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void buyGuildhouse(Player *player, Creature *_creature, uint32 guildhouseId)
+{
+
+ bool token = sConfigMgr->GetBoolDefault("GuildHouse.TokenOrGold", false);
+ int cost = sConfigMgr->GetBoolDefault("GuildHouse.Cost", false);
+ 
+ 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 - sConfigMgr->GetBoolDefault("GuildHouse.Cost", false));
+ _creature->MonsterWhisper(msg, player);
+ return;
+ }
+
+ if (isPlayerHasGuildhouse(player, _creature, true))
+ {
+ //player already have GH
+ return;
+ }
+
+ QueryResult result;
+
+ //check if somebody already occupied this GH
+ result = WorldDatabase.PQuery("SELECT `id` FROM `guildhouses` WHERE `id` = %u AND `guildId` <> 0", guildhouseId);
+
+ if (result)
+ {
+ _creature->MonsterWhisper(MSG_GHOCCUPIED, player);
+ return;
+ }
+
+ //update DB
+ result = WorldDatabase.PQuery("UPDATE `guildhouses` SET `guildId` = %u WHERE `id` = %u",
+ player->GetGuildId(), guildhouseId);
+
+
+ player->ModifyMoney(-sConfigMgr->GetIntDefault("GuildHouse.BuyCost", false) * 10000);
+
+ //player->DestroyItemCount(token, cost, true);
+ _creature->MonsterSay(MSG_CONGRATULATIONS, LANG_UNIVERSAL, player);
+
+}
+
+void sellGuildhouse(Player *player, Creature *_creature)
+{
+ if (isPlayerHasGuildhouse(player, _creature))
+ {
+ QueryResult result;
+ result = WorldDatabase.PQuery("UPDATE `guildhouses` SET `guildId` = 0 WHERE `guildId` = %u",
+ player->GetGuildId());
+
+ player->ModifyMoney(sConfigMgr->GetIntDefault("GuildHouse.SellCost", false) * 10000);
+
+ //display message e.g. "here your money etc."
+ char msg[100];
+ sprintf(msg, MSG_SOLD, sConfigMgr->GetIntDefault("GuildHouse.SellCost", false));
+ _creature->MonsterWhisper(msg, player);
+ }
+}
+
+ bool OnGossipSelect(Player *player, Creature *_creature, uint32 sender, uint32 action)
+ {
+ player->PlayerTalkClass->ClearMenus();
+ 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;
+ case ACTION_SELL_GUILDHOUSE:
+  sellGuildhouse(player, _creature);
+  player->CLOSE_GOSSIP_MENU();
+ 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 OnGossipHello(Player *player, Creature *_creature)
+ {
+ player->ADD_GOSSIP_ITEM(ICON_GOSSIP_BALOON, MSG_GOSSIP_TELE, GOSSIP_SENDER_MAIN, ACTION_TELE);
+
+ if (isPlayerGuildLeader(player))
+ {
+ if (isPlayerHasGuildhouse(player, _creature))
+ {
+ //and additional for guildhouse owner (Removed :
+ player->ADD_GOSSIP_ITEM_EXTENDED(ICON_GOSSIP_GOLD, MSG_GOSSIP_SELL, GOSSIP_SENDER_MAIN, ACTION_SELL_GUILDHOUSE, MSG_SELL_CONFIRM, 0, false);
+ 
+ }
+ else
+ {
+ //show additional menu for guild leader
+ player->ADD_GOSSIP_ITEM(ICON_GOSSIP_GOLD, MSG_GOSSIP_BUY, GOSSIP_SENDER_MAIN, ACTION_SHOW_BUYLIST);
+ }
+ }
+
+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, _creature->GetGUID());
+ return true;
+ }
+
+
+};
+void AddSC_guildmaster()
+{
+ new guildmaster();
+}
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index f71ef5d..a8fa3a5 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -2771,3 +2771,33 @@ PacketSpoof.BanDuration = 86400
 
 #
 ###################################################################################################
+
+###################################################################################################
+# GuildHouse
+#
+# Settings for the GuildHouse Keeper.
+#
+#    Guildhouse.TokenOrGold
+#        Description: Use tokens or money to buy guild houses.
+#        Default:     0 - Use Money
+#                     1 - Use Token
+#
+
+Guildhouse.TokenOrGold = 0
+
+#    GuildHouse.BuyCost
+#        Description: Amount of gold or quantity of tokens to buy guildhouse.
+#        Default:     1000 - 1000 gold
+#
+
+Guildhouse.BuyCost = 1000
+
+#    GuildHouse.BuyCost
+#        Description: Amount of gold or quantity of tokens gained when selling guildhouse.
+#        Default:     5000000 - 500 gold
+#
+
+Guildhouse.SellCost = 500
+
+#
+###################################################################################################
-- 
1.7.10.4
 

Tommy

Founder
It's most likely crashing because the 'comment' in "showBuyList" isn't casting for a const char* 'c_str();'.

Code:

Search:
Code:
player->ADD_GOSSIP_ITEM(ICON_GOSSIP_TABARD, comment, GOSSIP_SENDER_MAIN, guildhouseId + OFFSET_GH_ID_TO_ACTION);

And replace it with:
Code:
player->ADD_GOSSIP_ITEM(ICON_GOSSIP_TABARD, comment.c_str(), GOSSIP_SENDER_MAIN, guildhouseId + OFFSET_GH_ID_TO_ACTION);

That's the only thing I see related to your issue that could cause a crash.
 
Last edited:

Tommy

Founder
Kinda hard to depicted the issue. Some random person who didn't know what they were doing probably made this and didn't care about the bugs. If it wasn't that, then it could be the query result. For me, that query doesn't make sense at all and it appears that it wouldn't obtain any rows how it is written. Wish I could help more towards this, but hopefully that bit of information could help.
 
Top