Browse Source

sub commands /loot list [add/remove/clearall]

Fixes #28

/loot list add loottable_id
/loot list remove loottable_id
/loot list clearall

auto reloads loot, purges previous loot and re-assigns loot to selected spawn.

If you have multiple of the same spawn, then /repop the zone and it will repopulate after one is updated.
Image 4 years ago
parent
commit
2ea621db1b

+ 94 - 21
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -1853,31 +1853,104 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 		case COMMAND_LOOT_LIST:{
 			Spawn* spawn = cmdTarget;
 			if(spawn && spawn->IsEntity()){
-				vector<int32> loot_list = client->GetCurrentZone()->GetSpawnLootList(spawn->GetDatabaseID(), spawn->GetZone()->GetZoneID(), spawn->GetLevel(), race_types_list.GetRaceType(spawn->GetModelType()));
-				if(loot_list.size() > 0){
-					client->Message(CHANNEL_COLOR_YELLOW, "%s belongs to the following loot lists: ", spawn->GetName());
-					vector<int32>::iterator list_itr;
-					LootTable* table = 0;
-					for(list_itr = loot_list.begin(); list_itr != loot_list.end(); list_itr++){
-						table = client->GetCurrentZone()->GetLootTable(*list_itr);
-						if(table)
-							client->Message(CHANNEL_COLOR_YELLOW, "%u - %s", *list_itr, table->name.c_str());
+				if (sep && sep->arg[0]) {
+					if (!spawn->GetDatabaseID())
+					{
+						client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Spawn has no database id to assign to loottables.");
+						break;
 					}
-				}
-				Entity* target = (Entity*)spawn;
-				client->Message(CHANNEL_COLOR_YELLOW, "Coins being carried: %u", target->GetLootCoins());
-				vector<Item*>* items = target->GetLootItems();
-				if(items){
-					client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Spawn is carrying the following items: ");
-					vector<Item*>::iterator itr;
-					Item* item = 0;
-					for(itr = items->begin(); itr != items->end(); itr++){
-						item = *itr;
-						client->Message(CHANNEL_COLOR_YELLOW, "%u - %s", item->details.item_id, item->name.c_str());
+					else if (!spawn->IsNPC())
+					{
+						client->SimpleMessage(CHANNEL_COLOR_YELLOW, "these /loot list [add/remove/clearall] sub-commands are only designed for an NPC.");
+						break;
+					}
+
+					bool reloadLoot = false;
+					if (!stricmp(sep->arg[0], "remove") && sep->arg[1] && sep->IsNumber(1))
+					{
+						int32 loottable_id = atoul(sep->arg[1]);
+						if (loottable_id > 0 && database.RemoveSpawnLootTable(spawn, loottable_id))
+						{
+							client->Message(CHANNEL_COLOR_YELLOW, "Spawn %u loot table %u removed.", spawn->GetDatabaseID(), loottable_id);
+							reloadLoot = true;
+						}
+						else
+							client->Message(CHANNEL_COLOR_YELLOW, "/loot list remove [loottableid] - could not match any spawn_id entries against loottable_id %u.", loottable_id);
+					}
+					else if (!stricmp(sep->arg[0], "add") && sep->arg[1] && sep->IsNumber(1))
+					{
+
+						int32 loottable_id = atoul(sep->arg[1]);
+						if (loottable_id > 0)
+						{
+							database.AddLootTableToSpawn(spawn, loottable_id);
+							client->Message(CHANNEL_COLOR_YELLOW, "Spawn %u loot table %u added.", spawn->GetDatabaseID(), loottable_id);
+							reloadLoot = true;
+						}
+						else
+							client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/loot list add [loottableid] - cannot add a loottable id of 0.");
 					}
+					else if (!stricmp(sep->arg[0], "clearall"))
+					{
+						if (database.RemoveSpawnLootTable(spawn, 0))
+						{
+							client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Spawn loot tables removed.");
+							reloadLoot = true;
+						}
+						else
+							client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/loot list clearall - could not match any spawn_id entries in loottable_id.");
+					}
+					else
+					{
+						client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/loot list argument not supported.");
+						client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/loot list add [loottableid] - add new loottable to spawn");
+						client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/loot list remove [loottableid] - remove existing loottable from spawn");
+						client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/loot list clearall - remove all loottables from spawn");
+						break;
+					}
+					
+					if (reloadLoot)
+					{
+							database.LoadSpawnLoot(spawn->GetZone(), spawn);
+							if (spawn->IsNPC())
+							{
+								Entity* ent = (Entity*)spawn;
+								ent->SetLootCoins(0);
+								ent->ClearLootList();
+								spawn->GetZone()->AddLoot((NPC*)spawn);
+								client->Message(CHANNEL_COLOR_YELLOW, "Spawn %u active loot purged and reloaded.", spawn->GetDatabaseID());
+							}
+					}
+					break; // nothing further this is the end of these sub commands
 				}
 				else
-					client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Spawn is not carrying any items.");
+				{
+					vector<int32> loot_list = client->GetCurrentZone()->GetSpawnLootList(spawn->GetDatabaseID(), spawn->GetZone()->GetZoneID(), spawn->GetLevel(), race_types_list.GetRaceType(spawn->GetModelType()));
+					if (loot_list.size() > 0) {
+						client->Message(CHANNEL_COLOR_YELLOW, "%s belongs to the following loot lists: ", spawn->GetName());
+						vector<int32>::iterator list_itr;
+						LootTable* table = 0;
+						for (list_itr = loot_list.begin(); list_itr != loot_list.end(); list_itr++) {
+							table = client->GetCurrentZone()->GetLootTable(*list_itr);
+							if (table)
+								client->Message(CHANNEL_COLOR_YELLOW, "%u - %s", *list_itr, table->name.c_str());
+						}
+					}
+					Entity* target = (Entity*)spawn;
+					client->Message(CHANNEL_COLOR_YELLOW, "Coins being carried: %u", target->GetLootCoins());
+					vector<Item*>* items = target->GetLootItems();
+					if (items) {
+						client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Spawn is carrying the following items: ");
+						vector<Item*>::iterator itr;
+						Item* item = 0;
+						for (itr = items->begin(); itr != items->end(); itr++) {
+							item = *itr;
+							client->Message(CHANNEL_COLOR_YELLOW, "%u - %s", item->details.item_id, item->name.c_str());
+						}
+					}
+					else
+						client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Spawn is not carrying any items.");
+				}
 			}
 			break;
 							   }

+ 9 - 0
EQ2/source/WorldServer/Entity.h

@@ -808,6 +808,15 @@ public:
 	void UpdateGroupMemberInfo();
 
 	void CustomizeAppearance(PacketStruct* packet);
+
+	void ClearLootList() {
+		vector<Item*>::iterator itr;
+		for (itr = loot_items.begin(); itr != loot_items.end(); itr++)
+			safe_delete(*itr);
+
+		loot_items.clear();
+	}
+
 	Trade* trade;
 
 	// Keep track of entities that hate this spawn.

+ 53 - 0
EQ2/source/WorldServer/Items/LootDB.cpp

@@ -150,4 +150,57 @@ void WorldDatabase::LoadGlobalLoot(ZoneServer* zone) {
 
 		LogWrite(LOOT__DEBUG, 0, "Loot", "--Loaded %u Global loot list%s.", count, count == 1 ? "" : "s");
 	}
+}
+
+bool WorldDatabase::LoadSpawnLoot(ZoneServer* zone, Spawn* spawn)
+{
+	if (!spawn->GetDatabaseID())
+		return false;
+
+	DatabaseResult result;
+	int32 count = 0;
+
+	zone->ClearSpawnLootList(spawn->GetDatabaseID());
+	// Finally, load loot tables into spawns that are set to use these loot tables
+	if (database_new.Select(&result, "SELECT spawn_id, loottable_id FROM spawn_loot where spawn_id=%u",spawn->GetDatabaseID())) {
+		count = 0;
+		LogWrite(LOOT__DEBUG, 0, "Loot", "--Assigning loot table(s) to spawn(s)...");
+
+		while (result.Next()) {
+			int32 spawn_id = result.GetInt32Str("spawn_id");
+			int32 table_id = result.GetInt32Str("loottable_id");
+			zone->AddSpawnLootList(spawn_id, table_id);
+			LogWrite(LOOT__DEBUG, 5, "Loot", "---Adding loot table %u to spawn %u", table_id, spawn_id);
+			count++;
+		}
+		LogWrite(LOOT__DEBUG, 0, "Loot", "--Loaded %u spawn loot list%s.", count, count == 1 ? "" : "s");
+		return true;
+	}
+	return false;
+}
+
+void WorldDatabase::AddLootTableToSpawn(Spawn* spawn, int32 loottable_id) {
+	Query query;
+	query.RunQuery2(Q_INSERT, "insert into spawn_loot set spawn_id=%u,loottable_id=%u", spawn->GetDatabaseID(), loottable_id);
+}
+
+bool WorldDatabase::RemoveSpawnLootTable(Spawn* spawn, int32 loottable_id) {
+	Query query;
+	if (loottable_id)
+	{
+		string delete_char = string("delete from spawn_loot where spawn_id=%i and loottable_id=%i");
+		query.RunQuery2(Q_DELETE, delete_char.c_str(), spawn->GetDatabaseID(), loottable_id);
+	}
+	else
+	{
+		string delete_char = string("delete from spawn_loot where spawn_id=%i");
+		query.RunQuery2(Q_DELETE, delete_char.c_str(), spawn->GetDatabaseID());
+	}
+	if (!query.GetAffectedRows())
+	{
+		//No error just in case ppl try doing stupid stuff
+		return false;
+	}
+
+	return true;
 }

+ 3 - 0
EQ2/source/WorldServer/WorldDatabase.h

@@ -512,6 +512,9 @@ public:
 	/* Loot */
 	void				LoadLoot(ZoneServer* zone);
 	void				LoadGlobalLoot(ZoneServer* zone);
+	bool				LoadSpawnLoot(ZoneServer* zone, Spawn* spawn);
+	void				AddLootTableToSpawn(Spawn* spawn, int32 loottable_id);
+	bool				RemoveSpawnLootTable(Spawn* spawn, int32 loottable_id);
 
 	void				LoadCharacterHistory(int32 char_id, Player *player);
 	void				LoadSpellErrors();

+ 5 - 1
EQ2/source/WorldServer/zoneserver.cpp

@@ -6663,10 +6663,14 @@ void ZoneServer::AddLootDrop(int32 id, LootDrop* drop){
 	loot_drops[id].push_back(drop);
 }
 
-void ZoneServer::AddSpawnLootList(int32 spawn_id, int32 id){
+void ZoneServer::AddSpawnLootList(int32 spawn_id, int32 id) {
 	spawn_loot_list[spawn_id].push_back(id);
 }
 
+void ZoneServer::ClearSpawnLootList(int32 spawn_id) {
+	spawn_loot_list[spawn_id].clear();
+}
+
 void ZoneServer::AddLevelLootList(GlobalLoot* loot) {
 	level_loot_list.push_back(loot);
 }

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

@@ -963,6 +963,7 @@ public:
 	void				AddLootTable(int32 id, LootTable* table);
 	void				AddLootDrop(int32 id, LootDrop* drop);
 	void				AddSpawnLootList(int32 spawn_id, int32 id);
+	void				ClearSpawnLootList(int32 spawn_id);
 	void				AddLevelLootList(GlobalLoot* loot);
 	void				AddRacialLootList(int16 racial_id, GlobalLoot* loot);
 	void				AddZoneLootList(int32 zone, GlobalLoot* loot);