EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Server Code Submissions (https://www.eqemulator.org/forums/forumdisplay.php?f=669)
-   -   new command #advnpcspawn and related functions (https://www.eqemulator.org/forums/showthread.php?t=24208)

AiliaMorisato 01-19-2008 06:59 PM

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;


AiliaMorisato 01-19-2008 06:59 PM

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.

AiliaMorisato 01-19-2008 07:23 PM

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';


AiliaMorisato 01-24-2008 05:50 PM

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
                }



All times are GMT -4. The time now is 09:26 PM.

Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.