Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

Reply
 
Thread Tools Display Modes
  #1  
Old 01-19-2008, 06:59 PM
AiliaMorisato
Sarnak
 
Join Date: Sep 2005
Posts: 34
Default new command #advnpcspawn and related functions

first, appending ZoneDatabase::NPCSpawnDB(int8 command, const char* zone, Client *c, NPC* spawn, int32 extra)
two additional cases for the main switch
Code:
		case 5: { // add a spawn from spawngroup - Ailia
			char tmpstr[64];
			//char tmpstr2[64];
			if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawn2 (zone, x, y, z, respawntime, heading, spawngroupID) values('%s', %f, %f, %f, %i, %f, %i)", zone, c->GetX(), c->GetY(), c->GetZ(), 120, c->GetHeading(), extra), errbuf, 0, 0, &tmp)) {
				safe_delete(query);
				return false;
			}
			if(c) c->LogSQL(query);
			safe_delete_array(query);

			return true;
			break;
			}
		case 6: { // add npc_type - Ailia
			int32 npc_type_id, spawngroupid;
			char tmpstr[64];
			//char tmpstr2[64];
			EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
			if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO npc_types (name, level, race, class, hp, gender, texture, helmtexture, size, loottable_id, merchant_id, face, runspeed) values(\"%s\",%i,%i,%i,%i,%i,%i,%i,%f,%i,%i,%i,%f)", tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed()), errbuf, 0, 0, &npc_type_id)) {
				safe_delete(query);
				return false;
			}
			if(c) c->LogSQL(query);
			safe_delete_array(query);
			c->Message(0, "%s npc_type ID %i created successfully!", tmpstr, npc_type_id);
			return true;
			break;
		}
line 139-143 or so,spawn2.cpp
adding a catch to load missing spawngroups to allow worldbuilding without rebooting zone
Code:
		//grab our spawn group
		SpawnGroup* sg = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_);
		if (sg == NULL) {
			database.LoadSpawnGroupsByID(spawngroup_id_,&zone->spawn_group_list);
			sg = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_);
		}

		if (sg == NULL) {
			_log(SPAWNS__MAIN, "Spawn2 %d: Unable to locate spawn group %d. Disabling.", spawn2_id, spawngroup_id_);
			return false;
		}
LoadSpawnGroupsByID function from previous code block added to spawngroup.cpp
Code:
bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	

	// CODER new spawn code
	query = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT spawngroup.id, spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay FROM spawngroup WHERE spawngroup.ID='%i'", spawngroupid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result))) {
			SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]));
			spawn_group_list->AddSpawnGroup(newSpawnGroup);
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error2 in PopulateZoneLists query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	query = 0;
	if (RunQuery(query, MakeAnyLenString(&query, 
		"SELECT DISTINCT spawnentry.spawngroupID, spawnentry.npcid, spawnentry.chance, spawngroup.spawn_limit FROM spawnentry,spawngroup WHERE spawnentry.spawngroupID='%i' AND spawngroup.spawn_limit='0' ORDER by chance", spawngroupid), errbuf, &result)) {
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)))
		{
			SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
			SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
			if (sg)
				sg->AddSpawnEntry(newSpawnEntry);
			else
				cout << "Error in SpawngroupID: " << row[0] << endl;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error3 in PopulateZoneLists query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	// CODER end new spawn code
	return true;
}
loading random roaming data in spawn2.cpp following entity_list.LimitAddNPC(npc);
Code:
		if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay)
		npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay);
2ndary constructor for spawngroup to hold group roaming data
Code:
SpawnGroup::SpawnGroup( uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in ) {
	id = in_id;
	strncpy( name_, name, 120);
	group_spawn_limit = in_group_spawn_limit;
	roambox[0]=maxx;
	roambox[1]=minx;
	roambox[2]=maxy;
	roambox[3]=miny;
	roamdist=dist;
	delay=delay_in;
}
updated loadspawngroups function with slightly faster queries and support for roaming data
Code:
bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, SpawnGroupList* spawn_group_list) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
		
	// CODER new spawn code
	query = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay FROM spawn2,spawngroup WHERE spawn2.spawngroupID=spawngroup.ID and zone='%s'", zone_name), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result))) {
			SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]));
			spawn_group_list->AddSpawnGroup(newSpawnGroup);
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error2 in PopulateZoneLists query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	query = 0;
	if (RunQuery(query, MakeAnyLenString(&query, 
		"SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, "
		"npc_types.spawn_limit AS sl "
		"FROM spawnentry, spawn2, npc_types "
		"WHERE spawnentry.npcID=npc_types.id AND spawnentry.spawngroupID=spawn2.spawngroupID "
		"AND zone='%s' ORDER by chance", zone_name), errbuf, &result)) {
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)))
		{
			SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
			SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
			if (sg)
				sg->AddSpawnEntry(newSpawnEntry);
			else
				cout << "Error in SpawngroupID: " << row[0] << endl;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error3 in PopulateZoneLists query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	// CODER end new spawn code
	return true;
}
spawngroup.h adding public variables for roam data
Code:
	float roambox[4];
	float roamdist;
	int delay;
Reply With Quote
  #2  
Old 01-19-2008, 06:59 PM
AiliaMorisato
Sarnak
 
Join Date: Sep 2005
Posts: 34
Default

finally, the actual command to be added to command.cpp
Code:
void command_advnpcspawn(Client *c, const Seperator *sep)
{
	Mob *target=c->GetTarget();
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
    MYSQL_ROW row;
	int32 tmp = 0;
	int32 tmp2 = 0;
    int32 last_insert_id = 0;

		if (strcasecmp(sep->arg[1], "maketype") == 0){
			if(target && target->IsNPC())
			{
			database.NPCSpawnDB(6, zone->GetShortName(), c, target->CastToNPC());
			}
			else
			c->Message(0, "Target Required!");
		}
		else if (strcasecmp(sep->arg[1], "makegroup") == 0) {
			if(sep->arg[2])
			{
				if (!database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawngroup (name,spawn_limit,dist,max_x,min_x,max_y,min_y,delay) VALUES (\"%s\",%i,%f,%f,%f,%f,%f,%i)", sep->arg[2], (sep->arg[3]?atoi(sep->arg[3]):0), (sep->arg[4]?atof(sep->arg[4]):0), (sep->arg[5]?atof(sep->arg[5]):0), (sep->arg[6]?atof(sep->arg[6]):0), (sep->arg[7]?atof(sep->arg[7]):0), (sep->arg[8]?atof(sep->arg[8]):0), (sep->arg[9]?atoi(sep->arg[9]):0)), errbuf, 0, 0, &last_insert_id)) 
				{
					c->Message(0, "Invalid Arguments -- MySQL gave the following error:");
					c->Message(13, errbuf);
				}
				else
				{
				c->LogSQL(query);
				c->Message(0, "Group ID %i created successfully!", last_insert_id);
				}
				safe_delete_array(query);
			}
			else
			{
				c->Message(0, "Format: #advnpdspawn makegroup <name> [spawn limit] [dist] [max x] [min x] [max y] [min y] [delay]");
			}
		}
		else if (strcasecmp(sep->arg[1], "addgroupentry") == 0) {
			if(atoi(sep->arg[2]) && atoi(sep->arg[3]) && atoi(sep->arg[4]))
			{
				if (!database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawnentry (spawngroupID,npcID,chance) VALUES (%i,%i,%i)", atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), errbuf, 0, 0, &last_insert_id)))
				{
					c->Message(0, "Invalid Arguments -- MySQL gave the following error:");
					c->Message(13, errbuf);
				}
				else
				{
				c->LogSQL(query);
				c->Message(0, "NPC %i added to group %i with %i chance!", atoi(sep->arg[3]), atoi(sep->arg[2]), atoi(sep->arg[4]) );
				}
				safe_delete(query);
			}
			else
			{
				c->Message(0, "Format: #advnpdspawn addgroupentry <spawnggroupID> <npcID> <chance>");
			}
		}
		else if (strcasecmp(sep->arg[1], "editgroupbox") == 0) {
			if(atof(sep->arg[2]) && atof(sep->arg[3]) && atof(sep->arg[4]) && atof(sep->arg[5]) && atof(sep->arg[6]) && atof(sep->arg[7]) && atof(sep->arg[8]))
			{
				if (!database.RunQuery(query, MakeAnyLenString(&query, "UPDATE spawngroup SET dist='%f',max_x='%f',min_x='%f',max_y='%f',min_y='%f',delay='%i' WHERE id='%i'", atof(sep->arg[3]),atof(sep->arg[4]),atof(sep->arg[5]),atof(sep->arg[6]),atof(sep->arg[7]),atoi(sep->arg[8]),atoi(sep->arg[2]), errbuf, 0, 0, &last_insert_id)))
				{
					c->Message(0, "Invalid Arguments -- MySQL gave the following error:");
					c->Message(13, errbuf);
				}
				else
				{
				c->LogSQL(query);
				c->Message(0, "Group ID %i created successfully!", last_insert_id);
				}
				safe_delete_array(query);
			}
			else
			{
				c->Message(0, "Format: #advnpdspawn editgroupbox <spawngroupID> <dist> <max x> <min x> <max y> <min y> <delay>");
			}
		}
		else if (strcasecmp(sep->arg[1], "cleargroupbox") == 0) {
			if(atoi(sep->arg[2]))
			{
				if (!database.RunQuery(query, MakeAnyLenString(&query, "UPDATE spawngroup SET dist='0',max_x='0',min_x='0',max_y='0',min_y='0',delay='0' WHERE id='%i'",atoi(sep->arg[2])), errbuf, 0, 0, &last_insert_id)) 
				{
					c->Message(0, "Invalid Arguments -- MySQL gave the following error:");
					c->Message(13, errbuf);
				}
				else
				{
				c->LogSQL(query);
				c->Message(0, "Group ID %i created successfully!", last_insert_id);
				}
				safe_delete_array(query);
			}
			else
			{
				c->Message(0, "Format: #advnpdspawn cleargroupbox <spawngroupID>");
			}
		}
		else if (strcasecmp(sep->arg[1], "addgroupspawn") == 0 && atoi(sep->arg[2])!=0) {
			database.NPCSpawnDB(5, zone->GetShortName(), c, 0, atoi(sep->arg[2]));
			c->Message(0, "Mob of group %i added successfully!", atoi(sep->arg[2]));
		}
		else if (strcasecmp(sep->arg[1], "removegroupspawn") == 0) {
			if (!target || !target->IsNPC())
				c->Message(0, "Error: Need an NPC target.");
			else {
				Spawn2* s2 = target->CastToNPC()->respawn2;

				if(!s2) {
					c->Message(0, "removegroupspawn FAILED -- cannot determine which spawn entry in the database this mob came from.");
				}
				else
				{
					if(database.RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawn2 WHERE id='%i'",s2->GetID()), errbuf))
					{
						c->LogSQL(query);
						c->Message(0, "Spawnpoint Removed successfully.");
						target->Depop(false);
					}
					else
					{
						c->Message(13, "Update failed! MySQL gave the following error:");
						c->Message(13, errbuf);
	  				}
					safe_delete_array(query);
				}
			} 
		}
		else if (strcasecmp(sep->arg[1], "movespawn") == 0) {
			if (!target || !target->IsNPC())
				c->Message(0, "Error: Need an NPC target.");
			else {
				Spawn2* s2 = target->CastToNPC()->respawn2;

				if(!s2) {
					c->Message(0, "movespawn FAILED -- cannot determine which spawn entry in the database this mob came from.");
				}
				else
				{
					if(database.RunQuery(query, MakeAnyLenString(&query, "UPDATE spawn2 SET x='%f', y='%f', z='%f', heading='%f' WHERE id='%i'",c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(),s2->GetID()), errbuf))
					{
						c->LogSQL(query);
						c->Message(0, "Updating coordinates successful.");
						target->CastToNPC()->GMMove(c->GetX(), c->GetY(), c->GetZ(), c->GetHeading());
						target->CastToNPC()->SaveGuardSpot(true);
						target->SendPosition();
					}
					else
					{
						c->Message(13, "Update failed! MySQL gave the following error:");
						c->Message(13, errbuf);
	  				}
					safe_delete_array(query);
				}
			} 
		}
		else if (strcasecmp(sep->arg[1], "testload") == 0 && atoi(sep->arg[2])!=0) {
			database.LoadSpawnGroupsByID(atoi(sep->arg[2]),&zone->spawn_group_list);
			c->Message(0, "Group %i loaded successfully!", atoi(sep->arg[2]));
		}
		else {
			c->Message(0, "Error: #advnpcspawn: Invalid command.");
			c->Message(0, "Usage: #advnpcspawn [maketype|makegroup|addgroupentry|addgroupspawn]");
			c->Message(0, "Usage: #advnpcspawn [removegroupspawn|movespawn|editgroupbox|cleargroupbox]");
		}
}
Hope thats everything, probably forgot some header changes but those should be easy enough to fix.

Code currently being used on the server EDGE as our primary worldbuilding tool due to not creating redundant spawngroups and spawnentries allowing much faster queries and less redundancy in the database.
Reply With Quote
  #3  
Old 01-19-2008, 07:23 PM
AiliaMorisato
Sarnak
 
Join Date: Sep 2005
Posts: 34
Default

before i forget, you need to add the following to the spawngroup table
dist, max_x, min_x, max_y, min_y, delay
delay is an integer, rest are floats
default all to 0

Cripp edit:: Here is the SQL syntax for adding the fields..

Code:
ALTER TABLE `spawngroup` ADD `dist` FLOAT NOT NULL DEFAULT '0.0',
ADD `max_x` FLOAT NOT NULL DEFAULT '0.0',
ADD `min_x` FLOAT NOT NULL DEFAULT '0.0',
ADD `max_y` FLOAT NOT NULL DEFAULT '0.0',
ADD `min_y` FLOAT NOT NULL DEFAULT '0.0',
ADD `delay` INT NOT NULL DEFAULT '0';
Reply With Quote
  #4  
Old 01-24-2008, 05:50 PM
AiliaMorisato
Sarnak
 
Join Date: Sep 2005
Posts: 34
Default

Find -- if (!CalculateNewPosition2(roambox_movingto_x, roambox_movingto_y, GetZ(), walksp, true))
Code:
		{
			roambox_movingto_x = roambox_max_x + 1; // force update
			pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_delay, roambox_delay + 5000);
			SetMoving(false);
			SendPosition();	// makes mobs stop clientside
		}
Reply With Quote
  #5  
Old 01-24-2008, 06:23 PM
KLS
Administrator
 
Join Date: Sep 2006
Posts: 1,348
Default

I'll get to this and hopefully the remaining submissions I haven't gotten to within the next couple days I hope I hope.
Reply With Quote
  #6  
Old 04-07-2008, 01:44 PM
Cripp's Avatar
Cripp
Discordant
 
Join Date: Oct 2003
Location: The Shire
Posts: 474
Default

added a addspawn2 option for #advnpcspawn.. so you can manually add spawn2 entrys.




edit:: apparently "theres no point" in my spawn2 entry addition.. thanks ailia
__________________
Nug Blazers - ServerOP / founder
^^comming... later!

www.nugblazers.com

Last edited by Cripp; 04-08-2008 at 09:58 PM..
Reply With Quote
  #7  
Old 09-06-2008, 06:26 PM
Flare83
Sarnak
 
Join Date: Aug 2008
Location: usa
Posts: 43
Default

did this ever make into source? if not could it be put on the list again? =) thanks in advance KLS keep up the good work.
__________________
thenameless.site88.net
Reply With Quote
  #8  
Old 09-12-2008, 03:25 PM
Secrets's Avatar
Secrets
Demi-God
 
Join Date: May 2007
Location: b
Posts: 1,450
Default

It did not. It's a shame, good code, I use it still.

Especially roamboxes, they work wonders if you know how to use them.

Can replace grids in open areas.
Reply With Quote
  #9  
Old 09-12-2008, 04:34 PM
Angelox
AX Classic Developer
 
Join Date: May 2006
Location: filler
Posts: 2,049
Default

This is why I say, if it looks good, put it in and let everyone try and decide ASAP. You can always take it out again.
This guy got his code ignored, when he probably would have been a great help to the project. Now hes gone :(
Reply With Quote
  #10  
Old 10-05-2008, 06:56 PM
ChaosSlayer
Demi-God
 
Join Date: May 2007
Posts: 1,032
Default

could someone elaborate WHAt does advnpcspawn actual does?
and how to use it?
Reply With Quote
  #11  
Old 10-05-2008, 09:27 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Code:
Format: #advnpdspawn makegroup <name> [spawn limit] [dist] [max x] [min x] [max y] [min y] [delay]
I think instead of doing an add on the NPC to add it to the zone, you make a spawngroup with this command that will also add in roam boxes as well as add more NPCs to an existing spawngroup (I think).
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #12  
Old 10-05-2008, 10:39 PM
ChaosSlayer
Demi-God
 
Join Date: May 2007
Posts: 1,032
Default

hmm so you teling me if i want to make a randomly roaming npc, this thing will essentialy substitute the need of making a grid for random area roamers?

wouldn't this require a whole new table in DB? and it should also store a zone id somewhere no?
Reply With Quote
  #13  
Old 10-06-2008, 12:40 PM
Secrets's Avatar
Secrets
Demi-God
 
Join Date: May 2007
Location: b
Posts: 1,450
Default

Quote:
Originally Posted by ChaosSlayer View Post
hmm so you teling me if i want to make a randomly roaming npc, this thing will essentialy substitute the need of making a grid for random area roamers?

wouldn't this require a whole new table in DB? and it should also store a zone id somewhere no?
1)Yes, it will. No more grids for wide open areas.
2) No, it doesn't require a new table in the DB.
The spawngroup is loaded on a repop or zone bootup with this code, and because of this, the zone ID is stored in spawn2 rather than spawngroup.

Also, roamboxes are stored in spawngroup so a random NPC can spawn each time.

If no roambox is specified, the NPC finds a grid. If no grid is specifed, the NPC stays static and does nothing. Pretty easy system.
Reply With Quote
  #14  
Old 10-06-2008, 01:34 PM
cavedude's Avatar
cavedude
The PEQ Dude
 
Join Date: Apr 2003
Location: -
Posts: 1,988
Default

This code is in the SVN for anybody who wishes to fiddle with it. It worked pretty well in my limited testing.
Reply With Quote
  #15  
Old 11-22-2008, 10:55 AM
warsonofrage
Fire Beetle
 
Join Date: Mar 2003
Posts: 22
Default

wondering....need to remove a spawn group. client side how do i do that with this set of cmd's?

didnt see an argument to remove a spawngroup id so need to know how to do this remotely from the server
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 04:14 AM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3