/// <summary> /// Call into Prolog to respond to EVENTDESCRIPTION /// </summary> /// <param name="eventDescription">Term representing the event</param> private void NotifyEvent(object eventDescription) { ELNode.Store(eventHistory / Term.CopyInstantiation(eventDescription)); if (!this.IsTrue(new Structure(SNotifyEvent, eventDescription))) { Debug.LogError("notify_event/1 failed: " + ISOPrologWriter.WriteToString(eventDescription)); } }
private void SetSpeechTimeout(string speech) { currentlySpeaking = true; ELNode.Store(motorRoot / SIAmSpeaking); clearSpeechTime = Time.time + Math.Max( SpeechDelayMinimum, Math.Min(SpeechDelayMaximum, speech.Length * SpeechDelaySecondsPerChar)); }
private void UpdateLocations() { // TODO: FIX THIS SO THAT DESTROYED OBJECTS GET THEIR ENTRIES GC'ed. foreach (var p in Registry <PhysicalObject>()) { var o = p.gameObject; var n = locationRoot.ChildWithKey(o); // Don't do anything if /perception/location/O:Location:override in database, // which would mean the character is brainwashed about O's position. if (n == null || n.Children.Count == 0 || !n.Children[0].ContainsKey(brainwashedSymbol)) { if (!p.Exists) { // Dead; remove it. locationRoot.DeleteKey(o); } // Determine if it's inside something else if (p.Container == null) { // It's not inside another object, so find what room it's in. if (n == null || !n.ExclusiveKeyValue <GameObject>().GetComponent <Room>().Contains(o)) { var r = TileMap.TheTileMap.TileRoom(o); var location = r != null?(r.gameObject):null; if (location == null && p is Door) { location = ((Door)p).ForceRoom; } ELNode.Store(locationRoot / o % location); if (o == gameObject) { myCurrentRoom = r; } } } else { if (!p.IsHidden) { ELNode.Store((locationRoot / o % p.Container)); } } } } }
void UpdateLocomotionBidsAndPath() { //foreach (var pair in bidTotals) // bidTotals[pair.Key] = 0; bidTotals.Clear(); elRoot.WalkTree(SConcerns, updateConcernBids); GameObject winner = null; float winningBid = 0; foreach (var pair in bidTotals) { if (pair.Value > winningBid) { winningBid = pair.Value; winner = pair.Key; } } if (winner != null) { // Replan if destination has changed or if destination has moved away from current path. var newDestination = (winner != CurrentDestination && winner != CurrentlyDockedWith); if (newDestination || (currentDestination != null && currentPath == null) || (currentDestination != null && currentPath != null && !CurrentDestination.DockingTiles().Contains(currentPath.FinalTile))) { if (newDestination) { Dismount(); ELNode.Store(eventHistory / new Structure("goto", winner)); // Log change for debugging purposes. } CurrentDestination = winner; if (currentDestination.DockingTiles().Contains(gameObject.TilePosition())) { QueueEvent("arrived_at", currentDestination); } else { currentPath = planner.Plan(gameObject.TilePosition(), CurrentDestination.DockingTiles()); } } } }
private void UpdateLocations() { foreach (var p in Registry <PhysicalObject>()) { var o = p.gameObject; var n = this.locationRoot.ChildWithKey(o); // Don't do anything if /perception/location/O:Location:override in database, // which would mean the character is brainwashed about O's position. if (n == null || n.Children.Count == 0 || !n.Children[0].ContainsKey(this.brainwashedSymbol)) { // Determine if it's inside something if (p.Container == null) { // It's not inside another object, so find what room it's in. if (n == null || !n.ExclusiveKeyValue <GameObject>().GetComponent <Room>().Contains(o)) { foreach (var r in Registry <Room>()) { if (r.Contains(o)) { ELNode.Store(this.locationRoot / o % (r.gameObject)); if (o == this.gameObject) { this.myCurrentRoom = r; } } } } } else { if (!p.IsHidden) { ELNode.Store((this.locationRoot / o % p.Container)); } } } } }
internal void Start() { updateConcernBids = this.UpdateConcernBids; elRoot = this.KnowledgeBase().ELRoot; this.perceptionRoot = elRoot / Symbol.Intern("perception"); this.locationRoot = perceptionRoot / Symbol.Intern("location"); this.conversationalSpace = perceptionRoot / Symbol.Intern("conversational_space"); this.socialSpace = perceptionRoot / Symbol.Intern("social_space"); this.motorRoot = elRoot / Symbol.Intern("motor_state"); this.physiologicalStates = elRoot / Symbol.Intern("physiological_states"); this.eventHistory = elRoot / Symbol.Intern("event_history"); this.lastDestination = elRoot / Symbol.Intern("last_destination"); ELNode.Store(lastDestination % null); // Need a placeholder last destination so that /last_destination/X doesn't fail. if (!KB.Global.IsTrue("register_character", gameObject)) { throw new Exception("Can't register character " + name); } if (greyOutTexture == null) { greyOutTexture = new Texture2D(1, 1); greyOutTexture.SetPixel(0, 0, new Color(0, 0, 0, 128)); } }
private void InitiateAction(object action) { if (action == null) { return; } var actionCopy = Term.CopyInstantiation(action); ELNode.Store(motorRoot / SLastAction % actionCopy); var structure = action as Structure; if (structure != null) { switch (structure.Functor.Name) { case "face": Face(structure.Argument <GameObject>(0)); break; case "say": // Say a fixed string Say(structure.Argument <string>(0), gameObject); break; case "cons": // It's a list of actions to initiate. InitiateAction(structure.Argument(0)); InitiateAction(structure.Argument(1)); break; case "pause": pauseUntil = Time.time + Convert.ToSingle(structure.Argument(0)); break; case "pickup": { var patient = structure.Argument <GameObject>(0); if (patient == gameObject) { throw new InvalidOperationException(name + ": tried to pickup() self!"); } if (patient == gameObject) { return; } if (patient == null) { throw new NullReferenceException("Argument to pickup is not a gameobject"); } var physob = patient.GetComponent <PhysicalObject>(); if (physob == null) { throw new NullReferenceException("Argument to pickup is not a physical object."); } physob.MoveTo(gameObject); break; } case "ingest": { var patient = structure.Argument <GameObject>(0); if (patient == null) { throw new NullReferenceException("Argument to ingest is not a gameobject"); } var physob = patient.GetComponent <PhysicalObject>(); if (physob == null) { throw new NullReferenceException("Argument to ingest is not a physical object."); } physob.Destroy(); // TODO: FIX LOCATION UPDATE SO WE DON'T NEED TO KLUGE THIS locationRoot.DeleteKey(patient); var propinfo = patient.GetComponent <PropInfo>(); if (propinfo != null) { if (propinfo.IsFood) { physiologicalStates.DeleteKey(Symbol.Intern("hungry")); } if (propinfo.IsBeverage) { physiologicalStates.DeleteKey(Symbol.Intern("thirsty")); } } break; } case "putdown": { var patient = structure.Argument <GameObject>(0); if (patient == gameObject) { throw new InvalidOperationException(name + ": tried to putdown() self!"); } if (patient == null) { throw new NullReferenceException("Argument to putdown is not a gameobject"); } var physob = patient.GetComponent <PhysicalObject>(); if (physob == null) { throw new NullReferenceException("Argument to putdown is not a physical object."); } var dest = structure.Argument <GameObject>(1); if (dest == null) { throw new NullReferenceException("Argument to putdown is not a gameobject"); } physob.MoveTo(dest); break; } case "flash": { flashColorA = structure.Argument <Color>(0); flashColorB = structure.Argument <Color>(1); flashPeriod = Convert.ToSingle(structure.Argument(2)); flashStartTime = Time.time; flashEndTime = flashStartTime + Convert.ToSingle(structure.Argument(3)); break; } case "get_in": GetIn(structure.Argument <GameObject>(0)); break; case "dismount": Dismount(); break; case "end_game": Application.Quit(); break; default: // Assume it's dialog this.IsTrue("log_dialog_act", structure); GameObject thisAddressee = ((structure.Arity >= 2) ? structure.Argument(1) as GameObject : gameObject) ?? gameObject; var talkingToSelf = thisAddressee == gameObject; if (!talkingToSelf || ShowMentalMonologue) { var textVar = new LogicVariable("DialogText"); object text = null; try { text = gameObject.SolveFor(textVar, "generate_text", structure, textVar); } catch (Exception e) { Debug.LogError(string.Format("Exception while generating text for {0}", gameObject.name)); Debug.LogException(e); } var textString = text as string; if (textString == null) { throw new Exception( "generate_text returned " + ISOPrologWriter.WriteToString(text) + " for " + ISOPrologWriter.WriteToString(structure)); } var talkingToPlayer = structure.Arity >= 2 && ReferenceEquals(structure.Argument(1), playerSymbol); SetSpeechTimeout(textString); if (talkingToPlayer) // Character is talking to zhimself { if (nlPrompt != null) { nlPrompt.OutputToPlayer(textString); } else { Say(string.Format("({0})", textString), thisAddressee); } } else { Say(textString, thisAddressee); } if (!talkingToPlayer && !talkingToSelf) { // Tell the other characters foreach (var node in socialSpace.Children) { var character = (GameObject)(node.Key); if (character != gameObject) { character.QueueEvent((Structure)Term.CopyInstantiation(structure)); } } // TODO: fix it so that when characters appear, the system computes their social // spaces from scratch. Then we won't need this kluge. if (!socialSpace.ContainsKey(thisAddressee)) { thisAddressee.QueueEvent((Structure)Term.CopyInstantiation(structure)); } } } break; } if (structure.Functor.Name != "pause") { // Report back to the character that the action has occurred. QueueEvent(structure); } } else { throw new InvalidOperationException("Unknown action: " + ISOPrologWriter.WriteToString(action)); } }
/// <summary> /// Update the set of character's within this characters' conversational space /// and generate any necessary enter/leave events. /// </summary> private void UpdateSpace(Collider2D[] colliders, float radius, ELNode statusNode, string enterEvent, string exitEvent, bool updateNobodySpeaking) { var characterCount = Physics2D.OverlapCircleNonAlloc( transform.position, radius, colliders, 1 << gameObject.layer); if (characterCount == MaxConversationalSpaceColliders) { throw new Exception("Too many colliders in conversational space!"); } // Clean out entries that are no longer in the area statusNode.DeleteAll( node => { // Look to see if node's key (a character) appears in the colliders for (var i = 0; i < characterCount; i++) { if (ReferenceEquals(node.Key, colliders[i].gameObject)) { return(false); } } // It doesn't, so the character left this character's conversational space. // Tell this character about it QueueEvent(exitEvent, node.Key); // Remove the character return(true); }); // Add new entries for (var i = 0; i < characterCount; i++) { var character = colliders[i].gameObject; if (character != gameObject && !statusNode.ContainsKey(character) && myCurrentRoom != null && myCurrentRoom.Contains(character)) { // The character just arrived in this character's conversational space // Tell this character QueueEvent(enterEvent, character); // Update the KB ELNode.Store(statusNode / character); } } if (updateNobodySpeaking) { bool nobodySpeaking = true; for (var i = 0; i < characterCount; i++) { if (colliders[i].GetComponent <SimController>().IsSpeaking) { nobodySpeaking = false; } } if (currentlySpeaking) { nobodySpeaking = false; } if (nobodySpeaking) { ELNode.Store(perceptionRoot / SNobodySpeaking); } else { if (perceptionRoot.ContainsKey(SNobodySpeaking)) { perceptionRoot.DeleteKey(SNobodySpeaking); pollActions = true; } } } }