00001 import BigWorld 00002 import GUI 00003 import Math 00004 00005 import Anoria 00006 from Actor import Actor 00007 from Helpers import TargetCaps 00008 00009 # GREETER_MODEL_NAME = "characters/barbarian.model" 00010 GREETER_MODEL_NAME = "characters/npc/fd_orc_guard/orc.model" 00011 00012 class Greeter(BigWorld.Entity, Actor): 00013 00014 def __init__(self): 00015 BigWorld.Entity.__init__(self) 00016 Actor.__init__(self) 00017 00018 # ------------------------------------------------------------------------- 00019 # Section: BigWorld Callbacks 00020 # ------------------------------------------------------------------------- 00021 00022 def prerequisites( self ): 00023 # Make sure our model is loaded asynchronously before putting us 00024 # into the world. 00025 return [ GREETER_MODEL_NAME ] 00026 00027 def onEnterWorld( self, prereqs ): 00028 # The entity has entered this client's AoI and has been added to 00029 # the set of entities that this client knows about. Note that this 00030 # method is not called until all prerequisite resources have been 00031 # loaded. 00032 00033 # set target caps 00034 self.targetCaps = [ TargetCaps.CAP_CAN_HIT ] 00035 00036 # Model has been loaded and is in the engine resource cache. Construct 00037 # the model and assign it as the primary entity model. 00038 self.model = BigWorld.Model( GREETER_MODEL_NAME ) 00039 00040 # add a shadow 00041 BigWorld.addShadowEntity( self ) 00042 00043 # Setup an appropriate filter. Since this entity is never going to move 00044 # we can use the simple "dumb" filter (performs no interpolation). 00045 self.filter = BigWorld.DumbFilter() 00046 00047 # Initialise some members. 00048 self._messageAttachment = None 00049 self._messageTimerHandle = None 00050 00051 def onLeaveWorld( self ): 00052 # The entity has left this client's AoI and has been removed from 00053 # the set of entities that this client knows about. 00054 00055 # Clean up our resources. 00056 BigWorld.delShadowEntity(self) 00057 self._clearMessage() 00058 self.model = None 00059 # self.filter = None 00060 00061 # ------------------------------------------------------------------------- 00062 # Section: RPC 00063 # ------------------------------------------------------------------------- 00064 00065 00066 00067 00068 # ------------------------------------------------------------------------- 00069 # Section: Tutorial "Greeter" supplied functionality 00070 # ------------------------------------------------------------------------- 00071 00072 00073 def use( self ): 00074 # Implement a generic "use" function so that when the player "uses" 00075 # this entity, it will toggle the activation state on the server. 00076 self.cell.toggleActive() 00077 00078 def greet( self, targetID, msg ): 00079 # The server part of the entity has instructed us to "greet" the target 00080 # entity ID. 00081 00082 # Get the target entity. This client should know about the targe entity 00083 # since it's all happening in the same vicinity. In the few cases that 00084 # we don't know about the entity (e.g. race condition between issuing 00085 # command and the target leaving the AoI, or the Greeter and the target 00086 # entity are sitting right near the edge of the AoI) we can simply just 00087 # ignore the greet command. 00088 try: 00089 targetEntity = BigWorld.entities[targetID] 00090 except KeyError: 00091 return 00092 00093 # Play the Wave action on our model (the Wave action is setup in 00094 # Model Editor). Note how we can call the action as if it were 00095 # a standard Python method call. To stop the code from breaking 00096 # because the artist forgot to add an action, we can catch the 00097 # exception and print an error. 00098 try: 00099 self.model.Wave() 00100 except AttributeError: 00101 print "WARNING: Greeter model missing Wave action (%s)" % self.model.sources 00102 00103 # Display the greet message above our head. 00104 addressee = targetEntity.name 00105 if targetID == BigWorld.player().id: 00106 addressee += "! Yes you" 00107 00108 self._displayMessage( "Hey %s! '%s'!" % (addressee, msg) ) 00109 00110 def set_activated( self, oldValue ): 00111 # This method is automatically called by the engine when the activated 00112 # property is changed by the server. This set_ prefix naming scheme will 00113 # work with any client exposed property. 00114 if self.activated: 00115 self._displayMessage( "Alright! I'm now ready to GREET." ) 00116 else: 00117 self._displayMessage( "Shutting up now." ) 00118 00119 def _displayMessage( self, msg ): 00120 # Helper method to temporarily display a text message floating above 00121 # our head. This is achieved by creating a GUI text component, and 00122 # then using a GUI.Attachment to display the GUI element within the 00123 # 3D world. 00124 00125 # First make sure any previous message is cleared. 00126 self._clearMessage() 00127 00128 # Create our text component. Since we want to diplsay it in the world 00129 # we shall explicitly set our width and height in world units. 00130 text = GUI.Text( msg ) 00131 text.explicitSize = True 00132 text.size = ( 0, 0.5 ) # Specifying 0 for x to auto-calculate aspect ratio. 00133 text.colour = (255, 0, 0, 255) # Change the colour. 00134 text.filterType = "LINEAR" # Don't use point filtering. 00135 text.verticalAnchor = "BOTTOM" # Position relative to the bottom of the text. 00136 00137 # The origin of our model is at our feet. To place the text above 00138 # our head, move it up on the Y by our model's height. 00139 text.position = (0, self.model.height + 0.1, 0) 00140 00141 # Setup our GUI->World attachment. Tell it that we want the GUI 00142 # component to always face the camera. 00143 atch = GUI.Attachment() 00144 atch.component = text 00145 atch.faceCamera = True 00146 00147 # Attach to our model's root node. Another way of doing this might 00148 # be to create a specialised hard point within the model itself. 00149 # This would make the message position artist definable. 00150 self.model.root.attach( atch ) 00151 00152 # Save a reference to the attachment so we can clean it up later. 00153 self._messageAttachment = atch 00154 00155 # Setup the timer. 00156 self._setMessageHideTimer() 00157 00158 def _clearMessage( self ): 00159 # Helper method to remove any message currently above our head. 00160 00161 # Make sure any timer is cancelled. 00162 self._cancelMessageTimer() 00163 00164 # Detach from our model and forget about it. 00165 if self._messageAttachment is not None: 00166 self.model.root.detach( self._messageAttachment ) 00167 self._messageAttachment = None 00168 00169 def _setMessageHideTimer( self, timeout=5.0 ): 00170 # Helper method to setup a timer to hide the message above our head 00171 # after a given amount of time. If a timer already exists then we 00172 # cancel it before resetting. 00173 self._cancelMessageTimer() 00174 00175 self._messageTimerHandle = \ 00176 BigWorld.callback( timeout, self._handleMessageHideTimer ) 00177 00178 def _cancelMessageTimer( self ): 00179 # Helper method to cancel any current timer callback. 00180 if self._messageTimerHandle is not None: 00181 BigWorld.cancelCallback( self._messageTimerHandle ) 00182 self._messageTimerHandle = None 00183 00184 def _handleMessageHideTimer( self ): 00185 # This will get called by the engine when the hide timer has 00186 # expired. Reset the timer handle and clear any message. 00187 self._messageTimerHandle = None 00188 self._clearMessage() 00189 00190 00191
1.7.1