# Copyright 2003-2004 Kevin Reid. # This source code and related files are distributed under the MIT License, as described in the document named "License.txt" which should be provided with this source distribution. pragma.enable("explicit-result-guard") pragma.disable("no-dot-call") pragma.disable("easy-return") pragma.enable("accumulator") pragma.enable("importer") pragma.enable("exporter") pragma.enable("pattern-default") pragma.enable("map-tail") def := #def := #def := def lazy := def SturdyIdentity := SturdyRef def makeCharacter := lazy(fn{ }) def speak := lazy(fn{ }) def &en := lazy.slot(fn{ }) def makeNPCAuthor { to __optUncall() :any { return [, "get", [meta.context().getFQNPrefix().split("$")[0]]] } to run(timer, entropy) :any { def makeNPC { to __optUncall() :any { [makeNPCAuthor, "run", [timer, entropy]] } to run([ => self := (def npc; npc), "super" => optSuper := null ] | superArgs) :any { def outerSuper := if (optSuper != null) { optSuper } else { makeCharacter([=> self] | superArgs | ["name" => "someone", "description" => "Twitchy."]) } var isMoving := false bind npc extends outerSuper { to __optUncall() :any { [makeNPC, "run", [[=> self, => super]]] } to __conformTo(guard) :any { if (guard.__respondsTo("isDenDetailGuard", 0) && guard.isDenDetailGuard()) { #def outerPanel # #def superDetail := guard.sprout().coerce(super).getComponent() # #bind outerPanel := JPanel` # ${superDetail} #` # #def detail { # to isDenDetail() :any { true } # to getComponent() :any { outerPanel } #} super.__conformTo(guard) } else { npc } } to exterior_hear(event, extract) :void { super.exterior_hear(event, extract) if (isMoving) { return } def locationInfo := self.getExterior().getLocationInfo() def speechTexts :Map[SturdyIdentity, String] := accum [].asMap() for k => [v, _] in extract["assertionsMerged"].fetch("org.cubik.den.speech.text", fn{[].asMap()}) { _.with(k, v) } def speakerAssertions :Map[SturdyIdentity, SturdyIdentity] := accum [].asMap() for k => [v, _] in extract["assertionsMerged"].fetch("org.cubik.den.speech.speaker", fn{[].asMap()}) { _.with(k, v) } def reply(t) :void { speak(self.getExterior(), speakerAssertions.getValues(), t) } timer.whenAlarm(timer.now() + 500, def doneDelay() :void { if ( isMoving \ || speechTexts == [].asMap() \ || speechTexts.maps(self.getExterior().getIdentityHolder().getIdentity()) \ || self.getExterior().getLocationInfo() != locationInfo ) { return } isMoving := true def location := locationInfo.getLocation() reply("Leaving") def tryExits when (location <- getContentIdentities()) -> doneNeighbors(neighborIds) :void { # potential entrances to use var entrances := [] # number of unresolved potential entrances var remaining := neighborIds.size() # eventually retrieve nonnull entrances for id in neighborIds { self.getRecognizer().hintRelevantIdentity(id) when (location <- getContentExterior(id) <- getOptEntrance()) -> done(optEntrance) :void { if (optEntrance != null) { entrances with= [id, optEntrance] } } catch p { throw(p) } finally { remaining -= 1 self.getOwner().trace("npc", `${self.getName()} retrieved an exit`) } } def tryMove() :void { self.getOwner().trace("npc", `${self.getName()} tryMove ($entrances $remaining)`) if (entrances =~ []) { if (remaining == 0) { reply("Stuck!") # delay finishing for a while so we don't trigger on other NPCs complaining timer.whenAlarm(timer.now() + 2000, fn{ self.getOwner().trace("npc", `${self.getName()} reset`) isMoving := false }) } else { timer.whenAlarm(timer.now() + 500, tryMove) } return } def i := entropy.nextInt(entrances.size()) def [exitId, entrance] := entrances[i] # entrances := entrances(0..(entrances.size()) &! i..i) entrances := entrances(0, i) + entrances(i + 1, entrances.size()) when ( self.getExterior() <- moveInto(entrance, [].asMap()) ) -> doneMove(_) :void { # all done isMoving := false } catch p { # NOTE: uncertain: should we support identities in speech? # FIXME: language choice reply(`Couldn't use ${self.getRecognizer().getNameReporter(exitId, en, [].asMap())[]} ($p)`) tryMove <- () } } tryMove() } catch p { throw(p) } }) #end timer.whenPast } #end to hear } #end bind npc } #end run } #end makeNPC } #end run } #end makeNPCAuthor ? def makeNPCAuthor := # value: ? def makeNPC := makeNPCAuthor(timer, entropy) # value: ?# fixme: more updoc