Option to have character's face the player (#83)

Implements #83
This commit is contained in:
Nick 2022-05-01 18:02:30 -04:00
parent 1e8e307112
commit 45d8324cb3
4 changed files with 95 additions and 0 deletions

View File

@ -16,10 +16,16 @@ namespace NewHorizons.Builder.Props
{ {
public static void Make(GameObject go, Sector sector, PropModule.DialogueInfo info, IModBehaviour mod) public static void Make(GameObject go, Sector sector, PropModule.DialogueInfo info, IModBehaviour mod)
{ {
// In stock I think they disable dialogue stuff with conditions
// Here we just don't make it at all
if (info.blockAfterPersistentCondition != null && PlayerData._currentGameSave.GetPersistentCondition(info.blockAfterPersistentCondition)) return; if (info.blockAfterPersistentCondition != null && PlayerData._currentGameSave.GetPersistentCondition(info.blockAfterPersistentCondition)) return;
var dialogue = MakeConversationZone(go, sector, info, mod.ModHelper); var dialogue = MakeConversationZone(go, sector, info, mod.ModHelper);
if (info.remoteTriggerPosition != null) MakeRemoteDialogueTrigger(go, sector, info, dialogue); if (info.remoteTriggerPosition != null) MakeRemoteDialogueTrigger(go, sector, info, dialogue);
// Make the character look at the player
// Useful for dialogue replacement
if (!string.IsNullOrEmpty(info.pathToAnimController)) MakePlayerTrackingZone(go, dialogue, info);
} }
public static void MakeRemoteDialogueTrigger(GameObject go, Sector sector, PropModule.DialogueInfo info, CharacterDialogueTree dialogue) public static void MakeRemoteDialogueTrigger(GameObject go, Sector sector, PropModule.DialogueInfo info, CharacterDialogueTree dialogue)
@ -81,6 +87,83 @@ namespace NewHorizons.Builder.Props
return dialogueTree; return dialogueTree;
} }
public static void MakePlayerTrackingZone(GameObject go, CharacterDialogueTree dialogue, PropModule.DialogueInfo info)
{
var character = go.transform.Find(info.pathToAnimController);
// At most one of these should ever not be null
var nomaiController = character.GetComponent<SolanumAnimController>();
var controller = character.GetComponent<CharacterAnimController>();
var lookOnlyWhenTalking = info.lookAtRadius <= 0;
// To have them look when you start talking
if (controller != null)
{
controller._dialogueTree = dialogue;
controller.lookOnlyWhenTalking = lookOnlyWhenTalking;
}
else if(nomaiController != null)
{
if (lookOnlyWhenTalking)
{
dialogue.OnStartConversation += nomaiController.StartWatchingPlayer;
dialogue.OnEndConversation += nomaiController.StopWatchingPlayer;
}
}
else
{
// TODO: make a custom controller for basic characters to just turn them to face you
}
if (info.lookAtRadius > 0)
{
GameObject playerTrackingZone = new GameObject("PlayerTrackingZone");
playerTrackingZone.SetActive(false);
playerTrackingZone.layer = LayerMask.NameToLayer("BasicEffectVolume");
playerTrackingZone.SetActive(false);
var sphereCollider = playerTrackingZone.AddComponent<SphereCollider>();
sphereCollider.radius = info.lookAtRadius;
sphereCollider.isTrigger = true;
playerTrackingZone.AddComponent<OWCollider>();
var triggerVolume = playerTrackingZone.AddComponent<OWTriggerVolume>();
if (controller)
{
// Since the Awake method is CharacterAnimController was already called
if (controller.playerTrackingZone)
{
controller.playerTrackingZone.OnEntry -= controller.OnZoneEntry;
controller.playerTrackingZone.OnExit -= controller.OnZoneExit;
}
// Set it to use the new zone
controller.playerTrackingZone = triggerVolume;
triggerVolume.OnEntry += controller.OnZoneEntry;
triggerVolume.OnExit += controller.OnZoneExit;
}
// Simpler for the Nomai
else if(nomaiController)
{
triggerVolume.OnEntry += (_) => nomaiController.StartWatchingPlayer();
triggerVolume.OnExit += (_) => nomaiController.StopWatchingPlayer();
}
// No controller
else
{
// TODO
}
playerTrackingZone.transform.parent = dialogue.gameObject.transform;
playerTrackingZone.transform.localPosition = Vector3.zero;
playerTrackingZone.SetActive(true);
}
}
private static void AddTranslation(string xml) private static void AddTranslation(string xml)
{ {
XmlDocument xmlDocument = new XmlDocument(); XmlDocument xmlDocument = new XmlDocument();

View File

@ -56,6 +56,7 @@ namespace NewHorizons.Builder.Props
VolcanoBuilder.Make(go, sector, volcanoInfo); VolcanoBuilder.Make(go, sector, volcanoInfo);
} }
} }
// Reminder that dialogue has to be built after props if they're going to be using CharacterAnimController stuff
if (config.Props.Dialogue != null) if (config.Props.Dialogue != null)
{ {
foreach(var dialogueInfo in config.Props.Dialogue) foreach(var dialogueInfo in config.Props.Dialogue)

View File

@ -76,6 +76,8 @@ namespace NewHorizons.External
public string xmlFile; public string xmlFile;
public MVector3 remoteTriggerPosition; public MVector3 remoteTriggerPosition;
public string blockAfterPersistentCondition; public string blockAfterPersistentCondition;
public string pathToAnimController;
public float lookAtRadius;
} }
public class RevealInfo public class RevealInfo

View File

@ -667,6 +667,15 @@
"blockAfterPersistentCondition": { "blockAfterPersistentCondition": {
"type": "string", "type": "string",
"description": "Prevents the dialogue from being created after a specific persistent condition is set. Useful for remote dialogue triggers that you want to have happen only once." "description": "Prevents the dialogue from being created after a specific persistent condition is set. Useful for remote dialogue triggers that you want to have happen only once."
},
"pathToAnimController": {
"type": "string",
"description": "If this dialogue is meant for a character, this is the relative path from the planet to that character's CharacterAnimController or SolanumAnimController."
},
"lookAtRadius": {
"type": "number",
"default": 0,
"description": "If a pathToAnimController is supplied, if you are within this distance the character will look at you. If it is set to 0, they will only look at you when spoken to."
} }
} }
} }