ok i found the problem i was having with groups not sticking after zoneing its in my bot code can anyone see if they can help me fix it? what happens is they zone and stay in group but it seems its clearing them from the database or the group itself.. then when they zone back into the zone it kills the group and everyone has to reform.
Code:
void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
#ifdef EQBOTS
// EQoffline: Remove the group if the leader is grouped
Mob *clientmob = CastToMob();
if(clientmob) {
int16 cmid = clientmob->GetID();
if(clientmob->IsBotRaiding()) {
BotRaids* br = entity_list.GetBotRaidByMob(clientmob);
if(br) {
br->RemoveRaidBots();
br = NULL;
}
}
if(clientmob->IsGrouped()) {
Group *g = entity_list.GetGroupByMob(clientmob);
if(g) {
for(int i=5; i>=0; i--) {
if(g->members[i] && g->members[i]->IsBot()) {
g->members[i]->Kill();
}
}
if(g->BotGroupCount() <= 1) {
g->DisbandGroup();
}
}
}
database.CleanBotLeader(cmid);
}
#endif //EQBOTS
zoning = true;
if (app->size != sizeof(ZoneChange_Struct)) {
LogFile->write(EQEMuLog::Debug, "Wrong size: OP_ZoneChange, size=%d, expected %d", app->size, sizeof(ZoneChange_Struct));
return;
}
#if EQDEBUG >= 5
LogFile->write(EQEMuLog::Debug, "Zone request from %s", GetName());
DumpPacket(app);
#endif
ZoneChange_Struct* zc=(ZoneChange_Struct*)app->pBuffer;
uint16 target_zone_id = 0;
ZonePoint* zone_point = NULL;
//figure out where they are going.
if(zc->zoneID == 0) {
//client dosent know where they are going...
//try to figure it out for them.
switch(zone_mode) {
case EvacToSafeCoords:
case ZoneToSafeCoords:
//going to safe coords, but client dosent know where?
//assume it is this zone for now.
cheat_timer.Start(35000,false);
target_zone_id = zone->GetZoneID();
break;
case GMSummon:
target_zone_id = zonesummon_id;
break;
case GateToBindPoint:
target_zone_id = m_pp.binds[0].zoneId;
break;
case ZoneToBindPoint:
target_zone_id = m_pp.binds[0].zoneId;
break;
case ZoneSolicited: //we told the client to zone somewhere, so we know where they are going.
cheat_timer.Start(35000,false);
target_zone_id = zonesummon_id;
break;
case ZoneUnsolicited: //client came up with this on its own.
zone_point = zone->GetClosestZonePointWithoutZone(GetX(), GetY(), GetZ(), ZONEPOINT_NOZONE_RANGE);
if(zone_point) {
//we found a zone point, which is a reasonable distance away
//assume that is the one were going with.
target_zone_id = zone_point->target_zone_id;
} else {
//unable to find a zone point... is there anything else
//that can be a valid un-zolicited zone request?
CheatDetected(MQZone);
Message(13, "Invalid unsolicited zone request.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id);
SendZoneCancel(zc);
return;
}
break;
};
}
else {
// This is to allow both 6.2 and Titanium clients to perform a proper zoning of the client when evac/succor
// WildcardX 27 January 2008
if(zone_mode == EvacToSafeCoords && zonesummon_id > 0)
target_zone_id = zonesummon_id;
else
target_zone_id = zc->zoneID;
//if we are zoning to a specific zone unsolicied,
//then until otherwise determined, they must be zoning
//on a zone line.
if(zone_mode == ZoneUnsolicited) {
zone_point = zone->GetClosestZonePoint(GetX(), GetY(), GetZ(), target_zone_id, ZONEPOINT_ZONE_RANGE);
//if we didnt get a zone point, or its to a different zone,
//then we assume this is invalid.
if(!zone_point || zone_point->target_zone_id != target_zone_id) {
Message(13, "Invalid unsolicited zone request.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id);
if ((cheat_timer.GetRemainingTime())<1 || (!cheat_timer.Enabled())){ //Lieka: Disable MQGate Detector if timer is active.
CheatDetected(MQGate);
}
SendZoneCancel(zc);
return;
}
}
}
//make sure its a valid zone.
const char *target_zone_name = database.GetZoneName(target_zone_id);
if(target_zone_name == NULL) {
//invalid zone...
Message(13, "Invalid target zone ID.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Unable to get zone name for zone id '%d'.", GetName(), target_zone_id);
SendZoneCancel(zc);
return;
}
//load up the safe coords, restrictions, and verify the zone name
float safe_x, safe_y, safe_z;
sint16 minstatus = 0;
int8 minlevel = 0;
char flag_needed[128];
if(!database.GetSafePoints(target_zone_name, &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, flag_needed)) {
//invalid zone...
Message(13, "Invalid target zone while getting safe points.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Unable to get safe coordinates for zone '%s'.", GetName(), target_zone_name);
SendZoneCancel(zc);
return;
}
#ifdef EMBPERL
char buf[10];
snprintf(buf, 9, "%d", target_zone_id);
buf[9] = '\0';
((PerlembParser*)parse)->Event(EVENT_ZONE, 0, buf, (NPC*)NULL, this);
#endif
//handle circumvention of zone restrictions
//we need the value when creating the outgoing packet as well.
int8 ignorerestrictions = zonesummon_ignorerestrictions;
zonesummon_ignorerestrictions = 0;
float dest_x=0, dest_y=0, dest_z=0, dest_h;
dest_h = GetHeading();
switch(zone_mode) {
case EvacToSafeCoords:
case ZoneToSafeCoords:
LogFile->write(EQEMuLog::Debug, "Zoning %s to safe coords (%f,%f,%f) in %s (%d)", GetName(), safe_x, safe_y, safe_z, target_zone_name, target_zone_id);
dest_x = safe_x;
dest_y = safe_y;
dest_z = safe_z;
break;
case GMSummon:
dest_x = zonesummon_x;
dest_y = zonesummon_y;
dest_z = zonesummon_z;
ignorerestrictions = 1;
break;
case GateToBindPoint:
dest_x = m_pp.binds[0].x;
dest_y = m_pp.binds[0].y;
dest_z = m_pp.binds[0].z;
break;
case ZoneToBindPoint:
dest_x = m_pp.binds[0].x;
dest_y = m_pp.binds[0].y;
dest_z = m_pp.binds[0].z;
ignorerestrictions = 1; //can always get to our bind point? seems exploitable
break;
case ZoneSolicited: //we told the client to zone somewhere, so we know where they are going.
//recycle zonesummon variables
cheat_timer.Start(3500,false);
dest_x = zonesummon_x;
dest_y = zonesummon_y;
dest_z = zonesummon_z;
break;
case ZoneUnsolicited: //client came up with this on its own.
//client requested a zoning... what are the cases when this could happen?
//Handle zone point case:
if(zone_point != NULL) {
//they are zoning using a valid zone point, figure out coords
//999999 is a placeholder for 'same as where they were from'
if(zone_point->target_x == 999999)
dest_x = GetX();
else
dest_x = zone_point->target_x;
if(zone_point->target_y == 999999)
dest_y = GetY();
else
dest_y = zone_point->target_y;
if(zone_point->target_z == 999999)
dest_z=GetZ();
else
dest_z = zone_point->target_z;
if(zone_point->target_heading == 999)
dest_h = GetHeading();
else
dest_h = zone_point->target_heading;
break;
}
//for now, there are no other cases...
//could not find a valid reason for them to be zoning, stop it.
CheatDetected(MQZone);
Message(13, "Invalid unsolicited zone request.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%s'. Not near a zone point.", GetName(), target_zone_name);
SendZoneCancel(zc);
return;
};
//OK, now we should know where were going...
//Check some rules first.
sint8 myerror = 1; //1 is succes
//not sure when we would use ZONE_ERROR_NOTREADY
//enforce min status and level
if (!ignorerestrictions && (Admin() < minstatus || GetLevel() < minlevel)) {
cheat_timer.Start(3500,false); //Lieka: Don't set off warp detector for when a player is moved to the safe-spot for trying to access a zone without the appropriate level or status requirements (i.e. zoning into FearPlane at level 30, etc)
myerror = ZONE_ERROR_NOEXPERIENCE;
}
if(!ignorerestrictions && flag_needed[0] != '\0') {
//the flag needed string is not empty, meaning a flag is required.
if(Admin() < minStatusToIgnoreZoneFlags && !HasZoneFlag(target_zone_id)) {
Message(13, "You must have the flag %s to enter this zone.");
myerror = ZONE_ERROR_NOEXPERIENCE;
cheat_timer.Start(3500,false);
}
}
//Enforce ldon doungeon entrance rules
if(myerror == 1 && database.IsLDoNDungeon(target_zone_id)
// && !ignorerestrictions
) {
//this zone is an ldon dungeon
int advid = GetAdventureID();
if(advid > 0){
//we are in an adventure... make sure its the right one
AdventureInfo ai = database.GetAdventureInfo(advid);
if(target_zone_id != ai.zonedungeonid) {
Message(13, "You are not allowed to enter this dungeon!");
LogFile->write(EQEMuLog::Error, "Zoning %s: Not allowed to enter dungeon '%s' (%d). Not in the right adventure.", GetName(), target_zone_name, target_zone_id);
SendZoneCancel(zc);
return;
}
} else {
Message(13, "You are not allowed to enter this dungeon!");
LogFile->write(EQEMuLog::Error, "Zoning %s: Not allowed to enter dungeon '%s' (%d). Not in any adventure.", GetName(), target_zone_name, target_zone_id);
SendZoneCancel(zc);
return;
}
}
if(myerror == 1) {
//we have successfully zoned
DoZoneSuccess(zc, target_zone_id, dest_x, dest_y, dest_z, dest_h, ignorerestrictions);
} else {
LogFile->write(EQEMuLog::Error, "Zoning %s: Rules prevent this char from zoning into '%s'", GetName(), target_zone_name);
SendZoneError(zc, myerror);
}
}
the problem is the remove bots call if i comment it out and don't have bots the group stays intact if i have bots it destroys the group on zoneing and leaves the bots in the last zone.