diff --git a/src/main/java/com/projectswg/holocore/resources/support/npc/ai/NpcCombatMode.kt b/src/main/java/com/projectswg/holocore/resources/support/npc/ai/NpcCombatMode.kt index 9c3350fb9..f130519d3 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/npc/ai/NpcCombatMode.kt +++ b/src/main/java/com/projectswg/holocore/resources/support/npc/ai/NpcCombatMode.kt @@ -1,9 +1,11 @@ package com.projectswg.holocore.resources.support.npc.ai +import com.projectswg.common.data.RGB +import com.projectswg.common.data.encodables.oob.StringId import com.projectswg.common.data.encodables.tangible.Posture import com.projectswg.common.data.location.Location import com.projectswg.common.data.location.Point3D -import com.projectswg.common.data.objects.GameObjectType +import com.projectswg.common.network.packets.swg.zone.object_controller.ShowFlyText import com.projectswg.holocore.intents.support.global.command.QueueCommandIntent import com.projectswg.holocore.intents.support.npc.ai.ScheduleNpcModeIntent import com.projectswg.holocore.intents.support.npc.ai.StartNpcCombatIntent @@ -54,10 +56,15 @@ class NpcCombatMode(obj: AIObject) : NpcMode(obj) { } override fun onModeStart() { + showExclamationMarkAboveNpc() StopNpcMovementIntent.broadcast(ai) returnLocation.set(NavigationPoint.at(ai.parent, ai.location, npcRunSpeed)) } + private fun showExclamationMarkAboveNpc() { + ai.sendObservers(ShowFlyText(ai.objectId, StringId("npc_reaction/flytext", "threaten"), ShowFlyText.Scale.SMALL, RGB(204, 0, 0))) + } + override fun onModeEnd() { val obj = ai obj.lookAtTargetId = 0 diff --git a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/custom/AIObject.java b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/custom/AIObject.java index 6b6e27747..305bd14ae 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/custom/AIObject.java +++ b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/custom/AIObject.java @@ -26,7 +26,11 @@ ***********************************************************************************/ package com.projectswg.holocore.resources.support.objects.swg.custom; +import com.projectswg.common.data.RGB; +import com.projectswg.common.data.encodables.oob.StringId; +import com.projectswg.common.data.location.Location; import com.projectswg.common.network.packets.swg.zone.baselines.Baseline.BaselineType; +import com.projectswg.common.network.packets.swg.zone.object_controller.ShowFlyText; import com.projectswg.holocore.intents.support.npc.ai.ScheduleNpcModeIntent; import com.projectswg.holocore.intents.support.npc.ai.StartNpcCombatIntent; import com.projectswg.holocore.resources.support.npc.spawn.Spawner; @@ -41,6 +45,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -62,6 +67,7 @@ public class AIObject extends CreatureObject { private ScheduledThreadPool executor; private ScheduledFuture previousScheduled; private String creatureId; + private Instant questionMarkBlockedUntil; public AIObject(long objectId) { super(objectId); @@ -77,6 +83,7 @@ public AIObject(long objectId) { this.activeMode = null; this.creatureId = null; incapSafetyTimer = new IncapSafetyTimer(45_000); + questionMarkBlockedUntil = Instant.now(); } @Override @@ -130,9 +137,42 @@ public void onObjectMoveInAware(SWGObject aware) { return; playersNearby.add(player); + boolean npcIsInCombat = isInCombat(); + + Instant now = Instant.now(); + + boolean questionMarkTimerExpired = now.isAfter(questionMarkBlockedUntil); + + if (!npcIsInCombat) { + boolean npcIsAggressiveTowardsPlayer = isAttackable(player); + + if (npcIsAggressiveTowardsPlayer) { + boolean playerIsInLineOfSight = isLineOfSight(player); + + if (playerIsInLineOfSight) { + Location playerWorldLocation = player.getWorldLocation(); + Location aiWorldLocation = this.getWorldLocation(); + double questionMarkRange = 64; + double distanceBetweenNpcAndPlayer = aiWorldLocation.distanceTo(playerWorldLocation); + boolean playerIsInRange = distanceBetweenNpcAndPlayer <= questionMarkRange; + + if (playerIsInRange) { + if (questionMarkTimerExpired) { + showQuestionMarkAboveNpc(); + questionMarkBlockedUntil = Instant.now().plusSeconds(60); + } + } + } + } + } + checkAwareAttack(player); } + private void showQuestionMarkAboveNpc() { + this.sendObservers(new ShowFlyText(this.getObjectId(), new StringId("npc_reaction/flytext", "alert"), ShowFlyText.Scale.SMALL, new RGB(204, 0, 0))); + } + private void checkAwareAttack(CreatureObject player) { boolean incapSafetyTimerExpired = incapSafetyTimer.isExpired(System.currentTimeMillis(), player.getLastIncapTime());