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)); } } } } }
private void UpdateSpeechBubble() { // Clear speech bubble if it's time. if (currentlySpeaking && Time.time > clearSpeechTime) { currentSpeechBubbleText = null; currentlySpeaking = false; motorRoot.DeleteKey(SIAmSpeaking); } }
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; } } } }