Jump to content

Recommended Posts

Hello, everyone! 

To make it easier to add entity spawn locations, especially for those who don’t have FTP access to the server, I thought there should be a simpler solution.

So, here is a command created with this reason in mind, but it also speeds up the process even if you have access to the files or not. 🙂 

cmd.cpp
 

Spoiler
ACMD(do_create_regen);

	{ "create_regen", do_create_regen, 0, POS_DEAD, GM_IMPLEMENTOR },

 


cmd_gm.cpp

 

Spoiler

#include <fstream>
#include <map>
#include <string>

static std::map<int, std::string> g_mapIndexName;
static bool g_mapIndexLoaded = false;

void LoadMapIndex()
{
	std::string indexFile = LocaleService_GetMapPath() + "/index";

	std::ifstream file(indexFile);
	if (!file.is_open())
	{
		sys_err("Failed to open map index file: %s", indexFile.c_str());
		return;
	}

	g_mapIndexName.clear();

	int index;
	std::string name;

	while (file >> index >> name)
	{
		g_mapIndexName[index] = name;
	}

	file.close();
	g_mapIndexLoaded = true;

	sys_log(0, "Loaded %zu map entries from %s", g_mapIndexName.size(), indexFile.c_str());
}

const char* GetMapNameByIndex(int index)
{
	auto it = g_mapIndexName.find(index);
	if (it != g_mapIndexName.end())
		return it->second.c_str();

	return nullptr;
}

ACMD(do_create_regen)
{
	if (!g_mapIndexLoaded)
		LoadMapIndex();

	char fileType[16];
	char type = 'm';
	DWORD vnum;
	char respawn[32];
	char finalRespawn[64];
	int count;

	if (sscanf(argument, "%15s %c %u %31s %d",
			fileType, &type, &vnum, respawn, &count) != 5)
	{
		type = 'm';
		
		if (sscanf(argument, "%15s %u %31s %d",
				fileType, &vnum, respawn, &count) != 4)
		{
			ch->ChatPacket(CHAT_TYPE_INFO,
				"Usage: /create_regen <regen|stone|boss|npc> [type] <vnum> <respawn> <count>");
			ch->ChatPacket(CHAT_TYPE_INFO,
				"Type is optional (default: m)");
			return;
		}
	}

	if (type != 'm' && type != 'r')
	{
		type = 'm';
		ch->ChatPacket(CHAT_TYPE_INFO, 
			"Invalid type. Using default: m (mob). You can also use r for groups.");
	}

	if (count <= 0)
	{
		ch->ChatPacket(CHAT_TYPE_INFO, "Invalid count. Only positive values.");
		return;
	}

	bool validTime = false;
	int timeValue = 0;
	
	bool allDigits = true;
	for (size_t i = 0; i < strlen(respawn); i++)
	{
		if (!isdigit(respawn[i]))
		{
			allDigits = false;
			break;
		}
	}
	
	if (allDigits)
	{
		timeValue = atoi(respawn);
		if (timeValue > 0)
		{
			sprintf(finalRespawn, "%ds", timeValue);
			validTime = true;
		}
	}
	else
	{
		char unit = respawn[strlen(respawn) - 1];
		unit = tolower(unit);
		
		if (unit == 's' || unit == 'm' || unit == 'h')
		{
			char numberStr[32];
			strncpy(numberStr, respawn, strlen(respawn) - 1);
			numberStr[strlen(respawn) - 1] = '\0';
			
			bool numberValid = true;
			for (size_t i = 0; i < strlen(numberStr); i++)
			{
				if (!isdigit(numberStr[i]))
				{
					numberValid = false;
					break;
				}
			}
			
			if (numberValid)
			{
				timeValue = atoi(numberStr);
				if (timeValue > 0)
				{
					strcpy(finalRespawn, respawn);
					finalRespawn[strlen(finalRespawn) - 1] = unit;
					validTime = true;
				}
			}
		}
	}
	
	if (!validTime)
	{
		ch->ChatPacket(CHAT_TYPE_INFO, "Invalid time format. Use: 600, 10s, 5m, 1h. Using 600s as default.");
		strcpy(finalRespawn, "600s");
	}

	long mapIndex = ch->GetMapIndex();
	const char* mapName = GetMapNameByIndex(mapIndex);

	if (!mapName)
	{
		ch->ChatPacket(CHAT_TYPE_INFO,
			"Map index %ld not mapped in index file.", mapIndex);
		return;
	}

	if (strcmp(fileType, "regen") != 0 &&
		strcmp(fileType, "stone") != 0 &&
		strcmp(fileType, "boss") != 0 &&
		strcmp(fileType, "npc") != 0)
	{
		ch->ChatPacket(CHAT_TYPE_INFO,
			"Invalid file type. Use: regen / stone / boss / npc");
		return;
	}


	char path[512];
	snprintf(path, sizeof(path),
		"%s/%s/%s.txt",
		LocaleService_GetMapPath().c_str(),
		mapName,
		fileType);

	LPSECTREE_MAP pkMap = SECTREE_MANAGER::instance().GetMap(mapIndex);
	if (!pkMap)
	{
		ch->ChatPacket(CHAT_TYPE_INFO, "Cannot get map data.");
		return;
	}

	int x = (ch->GetX() - pkMap->m_setting.iBaseX) / 100;
	int y = (ch->GetY() - pkMap->m_setting.iBaseY) / 100;

	int offset_x = 4;
	int offset_y = 4;


	std::ofstream file(path, std::ios::app);
	if (!file.is_open())
	{
		ch->ChatPacket(CHAT_TYPE_INFO,
			"Cannot open file: %s", path);
		return;
	}

	file << type << "\t"
		<< x << "\t"
		<< y << "\t"
		<< offset_x << "\t"
		<< offset_y << "\t"
		<< 0 << "\t"
		<< 0 << "\t"
		<< finalRespawn << "\t"
		<< 100 << "\t"
		<< count << "\t"
		<< vnum << "\n";

	file.close();

	ch->ChatPacket(CHAT_TYPE_INFO,
		"Regen created: %s/%s.txt (vnum %u)",
		mapName, fileType, vnum);
}

 

 

  • Love 1
Link to comment
https://metin2.dev/topic/34319-regen-creator-command/
Share on other sites

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.