VOID PluginsAddSpawn(PSPAWNINFO pNewSpawn) { DWORD BodyType=GetBodyType(pNewSpawn); PluginDebug("PluginsAddSpawn(%s,%d,%d)",pNewSpawn->Name,pNewSpawn->mActorClient.Race,BodyType); if (!bPluginCS) return; if (GetGameState()>GAMESTATE_CHARSELECT) SetNameSpriteState(pNewSpawn,1); if (GetBodyTypeDesc(BodyType)[0]=='*') { WriteChatf("Spawn '%s' has unknown bodytype %d",pNewSpawn->Name,BodyType); } CAutoLock Lock(&gPluginCS); PMQPLUGIN pPlugin=pPlugins; while(pPlugin) { if (pPlugin->AddSpawn) { pPlugin->AddSpawn(pNewSpawn); } pPlugin=pPlugin->pNext; } }
/* If you change this function, you should update the above function to keep the #aggro command accurate. */ bool Mob::CheckWillAggro(Mob *mob) { if(!mob) return false; //sometimes if a client has some lag while zoning into a dangerous place while either invis or a GM //they will aggro mobs even though it's supposed to be impossible, to lets make sure we've finished connecting if (mob->IsClient()) { if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->zoning) return false; } Mob *ownr = mob->GetOwner(); if(ownr && ownr->IsClient() && !ownr->CastToClient()->ClientFinishedLoading()) return false; float iAggroRange = GetAggroRange(); // Check If it's invisible and if we can see invis // Check if it's a client, and that the client is connected and not linkdead, // and that the client isn't Playing an NPC, with thier gm flag on // Check if it's not a Interactive NPC // Trumpcard: The 1st 3 checks are low cost calcs to filter out unnessecary distance checks. Leave them at the beginning, they are the most likely occurence. // Image: I moved this up by itself above faction and distance checks because if one of these return true, theres no reason to go through the other information float t1, t2, t3; t1 = mob->GetX() - GetX(); t2 = mob->GetY() - GetY(); t3 = mob->GetZ() - GetZ(); //Cheap ABS() if(t1 < 0) t1 = 0 - t1; if(t2 < 0) t2 = 0 - t2; if(t3 < 0) t3 = 0 - t3; if(( t1 > iAggroRange) || ( t2 > iAggroRange) || ( t3 > iAggroRange) || (mob->IsInvisible(this)) || (mob->IsClient() && (!mob->CastToClient()->Connected() || mob->CastToClient()->IsLD() || mob->CastToClient()->IsBecomeNPC() || mob->CastToClient()->GetGM() ) )) { return(false); } // Don't aggro new clients if we are already engaged unless PROX_AGGRO is set if (IsEngaged() && (!GetSpecialAbility(PROX_AGGRO) || (GetSpecialAbility(PROX_AGGRO) && !CombatRange(mob)))) { Log(Logs::Moderate, Logs::Aggro, "%s is in combat, and does not have prox_aggro, or does and is out of combat range with %s", GetName(), mob->GetName()); return false; } //im not sure I understand this.. //if I have an owner and it is not this mob, then I cannot //aggro this mob...??? //changed to be 'if I have an owner and this is it' if(mob == GetOwner()) { return(false); } float dist2 = DistanceSquared(mob->GetPosition(), m_Position); float iAggroRange2 = iAggroRange*iAggroRange; if( dist2 > iAggroRange2 ) { // Skip it, out of range return(false); } //Image: Get their current target and faction value now that its required //this function call should seem backwards FACTION_VALUE fv = mob->GetReverseFactionCon(this); // Make sure they're still in the zone // Are they in range? // Are they kos? // Are we stupid or are they green // and they don't have their gm flag on int heroicCHA_mod = mob->itembonuses.HeroicCHA/25; // 800 Heroic CHA cap if(heroicCHA_mod > THREATENLY_ARRGO_CHANCE) heroicCHA_mod = THREATENLY_ARRGO_CHANCE; if (RuleB(Aggro, UseLevelAggro) && ( //old InZone check taken care of above by !mob->CastToClient()->Connected() ( ( GetLevel() >= 18 ) ||(GetBodyType() == 3) ||( mob->IsClient() && mob->CastToClient()->IsSitting() ) ||( mob->GetLevelCon(GetLevel()) != CON_GRAY) ) && ( ( fv == FACTION_SCOWLS || (mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr) || ( fv == FACTION_THREATENLY && zone->random.Roll(THREATENLY_ARRGO_CHANCE - heroicCHA_mod) ) ) ) ) ) { //FatherNiwtit: make sure we can see them. last since it is very expensive if(CheckLosFN(mob)) { Log(Logs::Detail, Logs::Aggro, "Check aggro for %s target %s.", GetName(), mob->GetName()); return( mod_will_aggro(mob, this) ); } } else { if ( //old InZone check taken care of above by !mob->CastToClient()->Connected() ( ( GetINT() <= RuleI(Aggro, IntAggroThreshold) ) ||( mob->IsClient() && mob->CastToClient()->IsSitting() ) ||( mob->GetLevelCon(GetLevel()) != CON_GRAY) ) && ( ( fv == FACTION_SCOWLS || (mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr) || ( fv == FACTION_THREATENLY && zone->random.Roll(THREATENLY_ARRGO_CHANCE - heroicCHA_mod) ) ) ) ) { //FatherNiwtit: make sure we can see them. last since it is very expensive if(CheckLosFN(mob)) { Log(Logs::Detail, Logs::Aggro, "Check aggro for %s target %s.", GetName(), mob->GetName()); return( mod_will_aggro(mob, this) ); } } } Log(Logs::Detail, Logs::Aggro, "Is In zone?:%d\n", mob->InZone()); Log(Logs::Detail, Logs::Aggro, "Dist^2: %f\n", dist2); Log(Logs::Detail, Logs::Aggro, "Range^2: %f\n", iAggroRange2); Log(Logs::Detail, Logs::Aggro, "Faction: %d\n", fv); Log(Logs::Detail, Logs::Aggro, "Int: %d\n", GetINT()); Log(Logs::Detail, Logs::Aggro, "Con: %d\n", GetLevelCon(mob->GetLevel())); return(false); }
void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) { //this logic is duplicated from below, try to keep it up to date. float iAggroRange = GetAggroRange(); float t1, t2, t3; t1 = mob->GetX() - GetX(); t2 = mob->GetY() - GetY(); t3 = mob->GetZ() - GetZ(); //Cheap ABS() if(t1 < 0) t1 = 0 - t1; if(t2 < 0) t2 = 0 - t2; if(t3 < 0) t3 = 0 - t3; if(( t1 > iAggroRange) || ( t2 > iAggroRange) || ( t3 > iAggroRange) ) { towho->Message(0, "...%s is out of range (fast). distances (%.3f,%.3f,%.3f), range %.3f", mob->GetName(), t1, t2, t3, iAggroRange); return; } if(mob->IsInvisible(this)) { towho->Message(0, "...%s is invisible to me. ", mob->GetName()); return; } if((mob->IsClient() && (!mob->CastToClient()->Connected() || mob->CastToClient()->IsLD() || mob->CastToClient()->IsBecomeNPC() || mob->CastToClient()->GetGM() ) )) { towho->Message(0, "...%s is my owner. ", mob->GetName()); return; } if(mob == GetOwner()) { towho->Message(0, "...%s a GM or is not connected. ", mob->GetName()); return; } float dist2 = DistanceSquared(mob->GetPosition(), m_Position); float iAggroRange2 = iAggroRange*iAggroRange; if( dist2 > iAggroRange2 ) { towho->Message(0, "...%s is out of range. %.3f > %.3f ", mob->GetName(), dist2, iAggroRange2); return; } if (RuleB(Aggro, UseLevelAggro)) { if (GetLevel() < 18 && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3) { towho->Message(0, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2); return; } } else { if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GRAY ) { towho->Message(0, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2); return; } } if(verbose) { int my_primary = GetPrimaryFaction(); int mob_primary = mob->GetPrimaryFaction(); Mob *own = GetOwner(); if(own != nullptr) my_primary = own->GetPrimaryFaction(); own = mob->GetOwner(); if(mob_primary > 0 && own != nullptr) mob_primary = own->GetPrimaryFaction(); if(mob_primary == 0) { towho->Message(0, "...%s has no primary faction", mob->GetName()); } else if(mob_primary < 0) { towho->Message(0, "...%s is on special faction %d", mob->GetName(), mob_primary); } else { char namebuf[256]; if(!database.GetFactionName(mob_primary, namebuf, sizeof(namebuf))) strcpy(namebuf, "(Unknown)"); std::list<struct NPCFaction*>::iterator cur,end; cur = faction_list.begin(); end = faction_list.end(); bool res = false; for(; cur != end; ++cur) { struct NPCFaction* fac = *cur; if ((int32)fac->factionID == mob_primary) { if (fac->npc_value > 0) { towho->Message(0, "...%s is on ALLY faction %s (%d) with %d", mob->GetName(), namebuf, mob_primary, fac->npc_value); res = true; break; } else if (fac->npc_value < 0) { towho->Message(0, "...%s is on ENEMY faction %s (%d) with %d", mob->GetName(), namebuf, mob_primary, fac->npc_value); res = true; break; } else { towho->Message(0, "...%s is on NEUTRAL faction %s (%d) with 0", mob->GetName(), namebuf, mob_primary); res = true; break; } } } if(!res) { towho->Message(0, "...%s is on faction %s (%d), which I have no entry for.", mob->GetName(), namebuf, mob_primary); } } } FACTION_VALUE fv = mob->GetReverseFactionCon(this); if(!( fv == FACTION_SCOWLS || (mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr) || fv == FACTION_THREATENLY )) { towho->Message(0, "...%s faction not low enough. value='%s'", mob->GetName(), FactionValueToString(fv)); return; } if(fv == FACTION_THREATENLY) { towho->Message(0, "...%s threatening to me, so they only have a %d chance per check of attacking.", mob->GetName()); } if(!CheckLosFN(mob)) { towho->Message(0, "...%s is out of sight.", mob->GetName()); } towho->Message(0, "...%s meets all conditions, I should be attacking them.", mob->GetName()); }