Browse Source

Disabling buy item supported, few crash fixes

Fix #326 - buy from merchant can have the 'buy' button disabled
function buy_display_flags(Item, Spawn)
    return 128
end

charactersProperties -> character_properties

CREATE TABLE `character_properties` (
  `charid` int(10) unsigned NOT NULL DEFAULT 0,
  `propname` varchar(64) NOT NULL DEFAULT '',
  `propvalue` varchar(64) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
drop table charactersProperties;
drop table charactersproperties;

- some misc crash fixes, sql escape issue, etc.
Image 3 years ago
parent
commit
5656ad22ce

+ 2 - 2
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -3095,13 +3095,13 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 		}
 		case COMMAND_USE: {
 			Spawn* target = cmdTarget;
-			if (target->IsWidget())
+			if (target && target->IsWidget())
 				((Widget*)target)->HandleUse(client, "use");
 			break;
 		}
 		case COMMAND_OPEN: {
 			Spawn* target = cmdTarget;
-			if (target->IsWidget())
+			if (target && target->IsWidget())
 				((Widget*)target)->HandleUse(client, "Open", WIDGET_TYPE_DOOR);
 			break;
 		}

+ 1 - 0
EQ2/source/WorldServer/Items/Items.h

@@ -603,6 +603,7 @@ extern MasterItemList master_item_list;
 #define	DISPLAY_FLAG_NO_GUILD_STATUS	8
 #define	DISPLAY_FLAG_NO_BUYBACK			16
 #define	DISPLAY_FLAG_NOT_FOR_SALE		64
+#define	DISPLAY_FLAG_NO_BUY				128 // disables buying on merchant 'buy' list
 
 #pragma pack(1)
 struct ItemStatsValues{

+ 1 - 1
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -396,7 +396,7 @@ int EQ2Emu_lua_SendStateCommand(lua_State* state) {
 		}
 		else
 		{
-			spawn->GetZone()->SendStateCommand(spawn, new_state);
+			spawn->GetZone()->QueueStateCommandToClients(spawn->GetID(), new_state);
 			lua_interface->SetBooleanValue(state, true);
 			return 1;
 		}

+ 10 - 4
EQ2/source/WorldServer/WorldDatabase.cpp

@@ -1864,11 +1864,11 @@ bool WorldDatabase::UpdateCharacterTimeStamp(int32 account_id, int32 character_i
 bool WorldDatabase::insertCharacterProperty(Client* client, char* propName, char* propValue) {
 	Query query;
 
-	string update_status = string("update charactersProperties set propvalue='%s' where charid=%i and propname='%s'");
+	string update_status = string("update character_properties set propvalue='%s' where charid=%i and propname='%s'");
 	query.RunQuery2(Q_UPDATE, update_status.c_str(), propValue, client->GetCharacterID(), propName);
 	if (!query.GetAffectedRows())
 	{
-		query.RunQuery2(Q_UPDATE, "insert into charactersProperties (charid, propname, propvalue) values(%i, '%s', '%s')", client->GetCharacterID(), propName, propValue);
+		query.RunQuery2(Q_UPDATE, "insert into character_properties (charid, propname, propvalue) values(%i, '%s', '%s')", client->GetCharacterID(), propName, propValue);
 		if (query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF) {
 			LogWrite(WORLD__ERROR, 0, "World", "Error in insertCharacterProperty query '%s': %s", query.GetQuery(), query.GetError());
 			return false;
@@ -1881,7 +1881,7 @@ bool WorldDatabase::loadCharacterProperties(Client* client) {
 	Query query;
 	MYSQL_ROW row;
 	int32 id = 0;
-	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT propname, propvalue FROM charactersProperties where charid = %i", client->GetCharacterID());
+	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT propname, propvalue FROM character_properties where charid = %i", client->GetCharacterID());
 	// no character found
 	if (result == NULL) {
 		LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character properties for '%s'", client->GetPlayer()->GetName());
@@ -2766,12 +2766,14 @@ void WorldDatabase::SaveZoneInfo(int32 zone_id, const char* field, const char* v
 int32 WorldDatabase::GetZoneID(const char* name) {
 	int32 zone_id = 0;
 	Query query;
-	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id` FROM zones WHERE `name`='%s'", name);
+	char* escaped = getEscapeString(name);
+	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id` FROM zones WHERE `name`=\"%s\"", escaped);
 	if (result && mysql_num_rows(result) > 0) {
 		MYSQL_ROW row;
 		row = mysql_fetch_row(result);
 		zone_id = atoi(row[0]);
 	}
+	safe_delete_array(escaped);
 	return zone_id;
 }
 
@@ -4941,6 +4943,10 @@ int32 WorldDatabase::LoadQuests(){
 				total++;
 				master_quest_list.AddQuest(id, quest);
 			}
+			else
+			{
+				LogWrite(QUEST__ERROR, 5, "Quests", "\tFAILED LOADING QUEST: '%s' (%u), check that script file exists/permissions correct: %s", name, id, (script && strlen(script)) ? script : "Not Set, Missing!");
+			}
 		}
 	}
 	LogWrite(QUEST__DEBUG, 0, "Quest", "\tLoaded %i Quest(s)", total);

+ 24 - 1
EQ2/source/WorldServer/client.cpp

@@ -6570,7 +6570,11 @@ void Client::BuyBack(int32 item_id, int16 quantity) {
 				else
 					item->details.count = closest->quantity;
 			}
-			if (!player->item_list.HasFreeSlot() && !player->item_list.CanStack(item))
+			bool itemAdded = false;
+			sint64 dispFlags = 0;
+			if (item && item->GetItemScript() && lua_interface && lua_interface->RunItemScript(item->GetItemScript(), "buyback_display_flags", item, player, &dispFlags) && (dispFlags & DISPLAY_FLAG_NO_BUY))
+				SimpleMessage(CHANNEL_NARRATIVE, "You do not meet all the requirements to buy this item.");
+			else if (!player->item_list.HasFreeSlot() && !player->item_list.CanStack(item))
 				SimpleMessage(CHANNEL_COLOR_RED, "You do not have any slots available for this item.");
 			else if (player->RemoveCoins(closest->quantity * closest->price)) {
 				bool removed = false;
@@ -6590,6 +6594,7 @@ void Client::BuyBack(int32 item_id, int16 quantity) {
 					closest->save_needed = true;
 				}
 				AddItem(item);
+				itemAdded = true;
 				//EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
 				//if(outapp)
 					//QueuePacket(outapp);
@@ -6604,6 +6609,9 @@ void Client::BuyBack(int32 item_id, int16 quantity) {
 			}
 			else
 				SimpleMessage(CHANNEL_COLOR_RED, "You cannot afford this item.");
+
+			if(!itemAdded)
+				safe_delete(item);
 		}
 	}
 
@@ -6645,6 +6653,12 @@ void Client::BuyItem(int32 item_id, int16 quantity) {
 				if (quantity > total_available)
 					quantity = total_available;
 			}
+			sint64 dispFlags = 0;
+			if (master_item->GetItemScript() && lua_interface && lua_interface->RunItemScript(master_item->GetItemScript(), "buy_display_flags", master_item, player, &dispFlags) && (dispFlags & DISPLAY_FLAG_NO_BUY))
+			{
+				SimpleMessage(CHANNEL_NARRATIVE, "You do not meet all the requirements to buy this item.");
+				return;
+			}
 			if(quantity < 1)
 			{
 				SimpleMessage(CHANNEL_COLOR_RED, "Merchant does not have item for purchase (quantity < 1).");
@@ -7019,6 +7033,10 @@ void Client::SendBuyMerchantList(bool sell) {
 					packet->setArrayDataByName("quantity", ItemInfo.quantity, i);
 					packet->setArrayDataByName("unknown5", 255, i);
 					packet->setArrayDataByName("stack_size2", item->stack_count, i);
+
+					sint64 dispFlags = 0;
+					if (item->GetItemScript() && lua_interface && lua_interface->RunItemScript(item->GetItemScript(), "buy_display_flags", item, player, &dispFlags))
+						packet->setArrayDataByName("display_flags", (int8)dispFlags, i);
 					
 					std::string overrideValueStr;
 					// classic client isn't properly tracking this field, DoF we don't have it identified yet, but no field to cause any issues (can add later if identified)
@@ -7275,6 +7293,11 @@ void Client::SendBuyBackList(bool sell) {
 					if (item_difficulty < 0)
 						item_difficulty *= -1;
 					packet->setArrayDataByName("item_difficulty", item_difficulty, i);
+
+					sint64 dispFlags = 0;
+					if (master_item->GetItemScript() && lua_interface && lua_interface->RunItemScript(master_item->GetItemScript(), "buyback_display_flags", master_item, player, &dispFlags))
+						packet->setArrayDataByName("display_flags", (int8)dispFlags, i);
+					
 					if (buyback->quantity == 1)
 						packet->setArrayDataByName("quantity", 0xFFFF, i);
 					else

+ 2 - 7
EQ2/source/WorldServer/zoneserver.cpp

@@ -1882,9 +1882,6 @@ void ZoneServer::SendSpawnChanges(){
 	Spawn* spawn = 0;
 
 	MSpawnList.readlock(__FUNCTION__, __LINE__);
-
-	int32 max_updates = 100;
-	
 	MutexList<int32>::iterator spawn_iter = changed_spawns.begin();
 	int count = 0;
 	while(spawn_iter.Next()){		
@@ -1895,9 +1892,6 @@ void ZoneServer::SendSpawnChanges(){
 		}
 		if (!spawn)
 			changed_spawns.Remove(spawn_iter->value);
-
-		if(count >= max_updates)
-			break;
 	}
 	//changed_spawns.clear() is not thread safe, advise we rely on what was removed and continue on, get any others in next batch
 
@@ -1906,7 +1900,8 @@ void ZoneServer::SendSpawnChanges(){
 	MClientList.readlock(__FUNCTION__, __LINE__);
 	for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) {
 		client = *client_itr;
-		client->SendSpawnChanges(spawns_to_send);
+		if(client)
+			client->SendSpawnChanges(spawns_to_send);
 	}
 	MClientList.releasereadlock(__FUNCTION__, __LINE__);