root/trunk/acceptance/epic4.rb

Revision 277, 5.7 kB (checked in by ged, 7 months ago)
  • Updated the build system substantially, including stuff from both the ThingFish? and Arrow projects.
  • Updated keywords on everything.
  • Reorganized the specs to match the convention of spec <-> lib hierarchies matching.
  • Added the loadpath library
  • Started refactor of bogswiddle to use Sequel instead of ActiveRecord?
  • Merged improvements from Arrow's logging system back into the FaerieMUD logger.
  • Updated documentation in FaerieMUD::SimpleVerb?
  • Refactored some of the early NLG code out into FaerieMUD::Linguistics
  • Fixed a bug in the recursive-containment detection code that missed containment more than two levels deep.
  • Corrected FaerieMUD::Item description
  • Added a VERSION constant to the toplevel FaerieMUD module.
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author URL Id
Line 
1#!/usr/bin/env ruby
2#
3#       FaerieMUD - The Hidden Path - Epic 4: Action
4#
5# == Authors
6#
7# * Michael Granger <ged@FaerieMUD.org>
8# * Martin Chase <stillflame@FaerieMUD.org>
9# * Aidan Rogers <aidan@FaerieMUD.org>
10#
11# == Legal
12#
13# Copyright (c) 2000-2005 The FaerieMUD Consortium. Some rights reserved.
14#
15# This is free software. You may use, modify, and/or redistribute this software
16# under the terms of the Creative Commons Attribution-NonCommercial-ShareAlike
17# license, version 2.0 or greater.
18#
19# See http://creativecommons.org/licenses/by-nc-sa/2.0/ for more information.
20#
21
22
23# Put some local directories in the load path
24BEGIN {
25        $basedir = File.dirname( File.dirname(__FILE__) )
26
27        %w{lib redist}.each do |dir|
28                $LOAD_PATH.unshift( File.join($basedir, dir) )
29        end
30}
31
32require "#$basedir/utils"
33require "fm"
34require 'fm/mixins'
35require 'fm/linguistics'
36
37
38### Clocks can 'tick'
39class TickVerb < FaerieMUD::Verb
40        def invoke( instigator, origin=nil )
41                origin ||= instigator
42                return FaerieMUD::AuditoryEvent.new(
43                        :instigator => instigator,
44                        :origin => origin,
45                        :verb => self,
46                        :noticability => 0.05
47                        )
48        end
49end
50
51### ...and also 'chime'
52class ChimeVerb < FaerieMUD::Verb
53        def invoke( instigator, origin=nil )
54                origin ||= instigator
55                return FaerieMUD::AuditoryEvent.new(
56                        :instigator => instigator,
57                        :origin => origin,
58                        :verb => self,
59                        :noticability => 0.25
60                        )
61        end
62end
63
64### Clock is a Locus instead of an Instrument for purposes of simplification.
65class Clock < FaerieMUD::Locus
66
67        ### Create a new clock object. You can configure the object with the
68        ### following attributes:
69        ### [:count]::  Specify how many ticks the clock should generate before
70        ###                     returning on its thread of execution.
71        ### [:interval]:: Specify how many floating-point seconds to sleep between
72        ###                       ticks. An +interval+ of +0+ causes the clock to tick as
73        ###                               fast as it can.
74        def initialize( args={} )
75                @thread = nil
76                @tickCount = 0
77                @verbs = {
78                        :tick => TickVerb.instance,
79                        :chime => ChimeVerb.instance,
80                }
81                @count = 120
82                @interval = 0.5
83
84                super
85        end
86
87        attr_accessor :count, :interval
88
89        ### Start a new thread, start ticking in it and return the thread.     
90        def start
91                @thread = Thread.new do
92                        Thread.current.abort_on_exception = true
93                        @count.times do
94                                self.tick
95                                sleep @interval unless @interval == 0.0
96                        end
97                end
98        end
99
100        ### Execute one tick of the clock, sending appropriate events to
101        ### the environment.
102        def tick
103                @tickCount += 1
104                self.log.debug "Tick %d" % [@tickCount]
105                events = @verbs[:tick].invoke( self )
106                self.disperse_events( events )
107                self.chime if (@tickCount % 10).zero?
108        end
109
110
111        ### Send an auditory chime event to the surrounding environment.
112        def chime
113                self.log.debug "Chime!"
114                events = @verbs[:chime].invoke( self )
115                self.disperse_events( events )
116        end
117end
118
119
120### The quasi-orc can 'say' stuff.
121class SayVerb < FaerieMUD::Verb
122
123        # The speaker will always be both instigator and origin, so combine them in
124        # the overridden method. Ventriloquism doesn't count. =:P
125
126        def invoke( speaker, language, words )
127                return FaerieMUD::SpeechEvent.new(
128                        :instigator => speaker,
129                        :origin => speaker,
130                        :verb => self,
131                        :language => language,
132                        :words => words,
133                        :noticability => 0.65
134                        )
135        end
136end
137
138### A simulacrum quasi-orc object.
139class QuasiOrc < FaerieMUD::Locus
140
141        ### Create a new simulated orc. He will assume he's on duty.
142        def initialize
143                @onDuty = true
144                @chimeCount = 0
145                @sayVerb = SayVerb.instance
146
147                super
148        end
149
150        ### Handle stuff heard from the environment. QuasiOrcs only care about chimes that tell
151        ### them they're on duty or off.
152        def handleAuditoryEvent( ev )
153                if ev.verb.class.name =~ /chime/i
154                        self.log.debug "Heard a chime!"
155                        results = self.respondToChime
156                        self.log.debug "Result from responding to chime: %p" %
157                                [ results ]
158                        self.disperse_events( results ) if results
159                else
160                        self.log.debug "Ignoring %s" % [ ev.class.name ]
161                        # Ignore
162                end
163        end
164
165
166        ### Respond to hearing a chime -- he is on duty every three hours.
167        def respondToChime
168                @chimeCount += 1
169                self.changeDutyStatus if ( @chimeCount % 3 ).zero?
170        end
171
172
173        ### After hearing a third chime, either go on duty or come off, and announce it.
174        def changeDutyStatus
175                @onDuty = !@onDuty
176
177                if @onDuty
178                        msg = "Back to work!"
179                else
180                        msg = "Ah, off duty now."
181                end
182               
183                return @sayVerb.invoke( self, :trade, msg )
184        end
185end
186
187
188### A bodiless observer object class -- just reports events observed from its
189### environment to $defout.
190class Observer < FaerieMUD::Locus
191
192        include FaerieMUD::Linguistics
193
194        ### Handle events that are sensed through auditory perception
195        def handleAuditoryEvent( ev )
196                $defout.puts "Observer heard: %s" % describe_event( ev )
197        end
198
199        ### Handle auditory events that contain speech specially.
200        def handleSpeechEvent( ev )
201                prelude = "Observer heard: %s" % describe_event( ev )
202                $defout.puts %q{%s, "%s"} % [ prelude, ev.words ]
203        end
204
205        ### Handle events sensed through visual perception.
206        def handleVisualEvent( ev )
207                $defout.puts "Observer saw: %s" % describe_event( ev )
208        end
209
210        ### Create a sentence to describe an event.
211        def describe_event( ev )
212                $deferr.puts ev.inspect
213
214                prep_phrase = "in %s" % objectToNounPhrase( ev.origin ) if ev.origin != ev.instigator
215                sentence = Sentence.new( ev.instigator, ev.verb, ev.target, prep_phrase )
216
217                return sentence.to_s
218        end
219
220end
221
222
223if $0 == __FILE__
224        if $DEBUG
225                FaerieMUD::Logger.global.outputters <<
226                        FaerieMUD::Logger::Outputter.create( 'file', $stderr, "STDERR" )
227                FaerieMUD::Logger.global.level = :debug
228        end
229
230        # Set up the scene
231        topArea = FaerieMUD::Area.new
232        punchbag = QuasiOrc.new
233        clock = Clock.new
234        observer = Observer.new
235
236        # Put the clock and punchbag into the void
237        topArea << punchbag
238        topArea << clock
239        topArea << observer
240
241        # Start the clock ticking
242        clock.interval = 0.1
243        clock.start.join
244end
245
246
Note: See TracBrowser for help on using the browser.