//Father Nitwit's LOS code bool Mob::CheckLosFN(Mob* other) { bool Result = false; if(other) Result = CheckLosFN(other->GetX(), other->GetY(), other->GetZ(), other->GetSize()); return Result; }
/* 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()) 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.Out(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 ( //old InZone check taken care of above by !mob->CastToClient()->Connected() ( ( GetINT() <= RuleI(Aggro, IntAggroThreshold) ) ||( mob->IsClient() && mob->CastToClient()->IsSitting() ) ||( mob->GetLevelCon(GetLevel()) != CON_GREEN ) ) && ( ( 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.Out(Logs::Detail, Logs::Aggro, "Check aggro for %s target %s.", GetName(), mob->GetName()); return( mod_will_aggro(mob, this) ); } } Log.Out(Logs::Detail, Logs::Aggro, "Is In zone?:%d\n", mob->InZone()); Log.Out(Logs::Detail, Logs::Aggro, "Dist^2: %f\n", dist2); Log.Out(Logs::Detail, Logs::Aggro, "Range^2: %f\n", iAggroRange2); Log.Out(Logs::Detail, Logs::Aggro, "Faction: %d\n", fv); Log.Out(Logs::Detail, Logs::Aggro, "Int: %d\n", GetINT()); Log.Out(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(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GREEN ) { 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()); }
void NPC::CalculateNewWaypoint() { int old_wp = cur_wp; bool reached_end = false; bool reached_beginning = false; if (cur_wp == max_wp) reached_end = true; if (cur_wp == 0) reached_beginning = true; switch(wandertype) { case 0: //circle { if (reached_end) cur_wp = 0; else cur_wp = cur_wp + 1; break; } case 1: //10 closest { std::list<wplist> closest; GetClosestWaypoint(closest, 10, glm::vec3(GetPosition())); std::list<wplist>::iterator iter = closest.begin(); if(closest.size() != 0) { iter = closest.begin(); std::advance(iter, zone->random.Int(0, closest.size() - 1)); cur_wp = (*iter).index; } break; } case 2: //random { cur_wp = zone->random.Int(0, Waypoints.size() - 1); if(cur_wp == old_wp) { if(cur_wp == (Waypoints.size() - 1)) { if(cur_wp > 0) { cur_wp--; } } else if(cur_wp == 0) { if((Waypoints.size() - 1) > 0) { cur_wp++; } } } break; } case 3: //patrol { if(reached_end) patrol = 1; else if(reached_beginning) patrol = 0; if(patrol == 1) cur_wp = cur_wp - 1; else cur_wp = cur_wp + 1; break; } case 4: //goto the end and depop with spawn timer case 6: //goto the end and depop without spawn timer { cur_wp = cur_wp + 1; break; } case 5: //pick random closest 5 and pick one that's in sight { std::list<wplist> closest; GetClosestWaypoint(closest, 5, glm::vec3(GetPosition())); std::list<wplist>::iterator iter = closest.begin(); while(iter != closest.end()) { if(CheckLosFN((*iter).x, (*iter).y, (*iter).z, GetSize())) { ++iter; } else { iter = closest.erase(iter); } } if(closest.size() != 0) { iter = closest.begin(); std::advance(iter, zone->random.Int(0, closest.size() - 1)); cur_wp = (*iter).index; } break; } } tar_ndx = 52; // Preserve waypoint setting for quest controlled NPCs if (cur_wp < 0) cur_wp = old_wp; // Check to see if we need to update the waypoint. if (cur_wp != old_wp) UpdateWaypoint(cur_wp); }