diff --git a/tools/RunicNpcTest.cs b/tools/RunicNpcTest.cs
index f2fdb27..78bffaf 100644
--- a/tools/RunicNpcTest.cs
+++ b/tools/RunicNpcTest.cs
@@ -45,7 +45,7 @@ namespace Oxide.Plugins
/// a made-up user id (11400000001 and up), so IsNpc is false. They take no damage.
///
///
- [Info("RunicNpcTest", "Runic Gateway", "0.7.4")]
+ [Info("RunicNpcTest", "Runic Gateway", "0.7.5")]
[Description("RunicNPC stage 2 to 7 tests, the stage 6 spike and stage 9's cost check. A developer tool: never ship it.")]
internal class RunicNpcTest : RustPlugin
{
@@ -1753,6 +1753,31 @@ namespace Oxide.Plugins
return false;
}
+ ///
+ /// Where a stage 5 fight's second NPC stands: m from the first, on the navmesh,
+ /// with a clear line between their eyes. North first, as the fights were laid out; then the other seven
+ /// ways round. On the drill's 3500 map a cliff rock stood between the victim and the bully north of it,
+ /// so neither ever saw the other and s5.fight.shootBack failed on every run (issue #20).
+ ///
+ private Vector3 Partner(Vector3 at, float dist)
+ {
+ for (int k = 0; k < 8; k++)
+ {
+ float angle = k * Mathf.PI / 4f;
+ Vector3 p = OnMesh(at + new Vector3(Mathf.Sin(angle), 0f, Mathf.Cos(angle)) * dist);
+ NavMeshHit hit;
+ if (!SampleNavmesh(p, 1f, out hit)) continue;
+ // Each one's eyes to the other's centre, both ways, as RunicNPC's own line of sight runs.
+ if (Physics.Linecast(at + Vector3.up * 1.6f, p + Vector3.up * 0.9f, 1218519041, QueryTriggerInteraction.Ignore) ||
+ Physics.Linecast(p + Vector3.up * 1.6f, at + Vector3.up * 0.9f, 1218519041, QueryTriggerInteraction.Ignore)) continue;
+ if (k > 0) Note($"s5: the partner {dist:0} m from {at} stands {k * 45}° round from north (no clear line north)");
+ return p;
+ }
+
+ Note($"s5: no clear line {dist:0} m round {at}; the partner stands north as before");
+ return OnMesh(at + new Vector3(0, 0, dist));
+ }
+
private int HorrorLeft() => BaseNetworkable.serverEntities.OfType().Count(c => !c.IsDestroyed && c.faction == BaseCombatEntity.Faction.Horror);
private IEnumerator Stage5()
@@ -1793,16 +1818,18 @@ namespace Oxide.Plugins
Vector3 d = OnMesh(f + new Vector3(70, 0, 0));
Vector3 e = OnMesh(f + new Vector3(140, 0, 0));
+ // Each fight's second NPC where the two can see each other (issue #20), found before anyone stands there.
+ Vector3 aTo = Partner(a, 15f), bTo = Partner(b, 15f), cTo = Partner(c, 15f), dTo = Partner(d, 25f), eTo = Partner(e, 15f);
BasePlayer red = Spawn(a, "t_red");
- BasePlayer blue = Spawn(OnMesh(a + new Vector3(0, 0, 15)), "t_blue");
+ BasePlayer blue = Spawn(aTo, "t_blue");
BasePlayer hunter = Spawn(b, "t_hunter");
- ScientistNPC prey = SpawnScientist(b + new Vector3(0, 0, 15));
+ ScientistNPC prey = SpawnScientist(bTo);
BasePlayer neutral = Spawn(c, "t_roam");
- ScientistNPC bystander = SpawnScientist(c + new Vector3(0, 0, 15));
+ ScientistNPC bystander = SpawnScientist(cTo);
BasePlayer leashed = Spawn(d, "t_leashed");
- ScientistNPC far = SpawnScientist(d + new Vector3(0, 0, 25));
+ ScientistNPC far = SpawnScientist(dTo);
BasePlayer victim = Spawn(e, "t_roam");
- BasePlayer bully = Spawn(OnMesh(e + new Vector3(0, 0, 15)), "t_bully");
+ BasePlayer bully = Spawn(eTo, "t_bully");
var fighters = new Dictionary
{
{ "red", red }, { "blue", blue }, { "hunter", hunter }, { "prey", prey }, { "neutral", neutral },
@@ -1823,7 +1850,16 @@ namespace Oxide.Plugins
if (factionsAt < 0f && (Gone(red) || Gone(blue))) factionsAt = t;
if (scientistAt < 0f && Gone(prey)) scientistAt = t;
if (!Gone(neutral) && TargetOf(Describe(neutral)) != "none") neutralFought = true;
- if (!Gone(leashed) && TargetOf(Describe(leashed)) != "none") leashedFought = true;
+ if (!leashedFought && !Gone(leashed) && TargetOf(Describe(leashed)) != "none")
+ {
+ leashedFought = true;
+ // Run 49 failed here once and it has not been seen since: say how it came to fight. A target its
+ // own sense found is within its chase (8 m) of home; a hurt one was shot; otherwise an ally's alarm.
+ Dictionary dl = Describe(leashed);
+ Vector3 leashHome = V(dl["home"]);
+ Note($"s5.fight.leash: fighting at {t} s, target {dl["target"]}, health {Convert.ToSingle(dl["health"]):0}/{Convert.ToSingle(dl["maxHealth"]):0}, " +
+ $"{Flat(V(dl["position"]), leashHome):0.0} m from home; the scientist {(Gone(far) ? "gone" : $"{Flat(far.transform.position, leashHome):0.0} m from its home, {far.health:0} hp")}");
+ }
if (!Gone(victim) && TargetOf(Describe(victim)) != "none") victimAnswered = true;
foreach (BasePlayer x in new[] { red, blue, hunter })
{