00001 '''
00002 Anoria (c) Gsk 2010
00003 '''
00004
00005
00006 import BigWorld
00007 import GUI as SYSGUI
00008 import Keys
00009 import math
00010
00011 from Resources import ResourceDB as RDB
00012 from AvatarModel import AvatarModelManager as AMM
00013
00014 import Anoria
00015 import AnGUI
00016 from Actor import Actor
00017 from Helpers import TargetCaps
00018
00019 from config.consts import *
00020 from config.anim import *
00021 from config.state import *
00022 from config import event
00023
00024 class Avatar(BigWorld.Entity, Actor):
00025
00026 def __init__(self):
00027 BigWorld.Entity.__init__(self)
00028 Actor.__init__(self)
00029 self.am = None
00030 self.targetCaps = [TargetCaps.CAP_CAN_HIT]
00031 self.hasMouseOverTarget = None
00032
00033 def enterWorld( self ):
00034
00035
00036 self.filter = BigWorld.AvatarFilter()
00037
00038
00039
00040 nm = AMM.makeModel( self.modelNumber, self.model )
00041 self.model = nm
00042
00043
00044 sword = BigWorld.Model("global/items/weapons/sword_bastard.model")
00045 self.model.right_hand = sword
00046
00047
00048 BigWorld.addShadowEntity(self)
00049
00050
00051 self.setupActionMatcher()
00052
00053
00054 self.matchCaps = [MATCH_CAP_ON_LAND,]
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 def facePosition(self, pos):
00066 print "Avatar.facePosition() not implemented yet!"
00067
00068
00069 def doTextSubst(self, text, val1=0):
00070
00071 if text.find('$SELF') != -1:
00072 name=self.name
00073 if self.isPlayer: name = RDB.strings[1000]
00074 text = text.replace('$SELF', name)
00075 if text.find('$POS') != -1:
00076 pos = RDB.strings[1001]
00077 if not self.isPlayer:
00078 if self.gender == GENDER_MALE:
00079 pos = RDB.strings[1002]
00080 if self.gender == GENDER_FEMALE:
00081 pos = RDB.strings[1003]
00082 if self.gender == GENDER_NEUTRAL:
00083 pos = RDB.strings[1004]
00084 text = text.replace('$POS', pos)
00085 if text.find('$3RA'):
00086 if not self.isPlayer:
00087 text = text.replace('$3RA', RDB.strings[1104])
00088 else:
00089 text = text.replace('$3RA', '')
00090 if text.find('$3RB'):
00091 if not self.isPlayer:
00092 text = text.replace('$3RB', RDB.strings[1105])
00093 else:
00094 text = text.replace('$3RB', '')
00095 if text.find('$1'):
00096 text = text.replace('$1', str(val1))
00097
00098 return text
00099
00100
00101
00102
00103
00104
00105
00106
00107 def attackStateChange(self, newState):
00108 self.states[STATE_ATTACK] = newState
00109 if newState == S_ATTACK_ON:
00110 if self.isPlayer:
00111 text=self.doTextSubst(RDB.strings[1], None)
00112 AnGUI.service.console.script.addMsg(text, 1l)
00113 self.facePosition(self.target.position)
00114
00115 self.addMatchCap(MATCH_CAP_MELEE_1)
00116 else:
00117 if self.isPlayer:
00118 text=self.doTextSubst(RDB.strings[2], None)
00119 AnGUI.service.console.script.addMsg(text, 1l)
00120
00121 self.delMatchCap(MATCH_CAP_MELEE_1)
00122
00123
00124
00125
00126
00127
00128 def rpc_chatText(self, text, channel):
00129
00130 AnGUI.service.console.script.addMsg(text, channel)
00131
00132 def rpc_printString(self, stringId, channel):
00133 " displays a system string in the output area designated by the channel parameter "
00134 text = RDB.strings[stringId]
00135 AnGUI.service.console.script.addMsg(text, channel)
00136
00137
00138 def rpcTargetLost(self):
00139 self.rpc_printString(11, MELEE_COMBAT_CHANNEL_ID)
00140 self.setTarget(None)
00141
00142
00143 def rpcMeleeAttack(self, entityId, hitType, damage):
00144
00145
00146
00147 if not self.hasMatchCap(MATCH_CAP_MELEE_1):
00148 self.addMatchCap(MATCH_CAP_MELEE_1)
00149
00150
00151 self.model.CCActFwdHit()
00152 try:
00153 entity=BigWorld.entities[entityId]
00154 BigWorld.callback(0.3, entity.model.Recoil)
00155 except:
00156 print "Avatar.rpcMeleeAttack(): cant find entity for passed in target entityId=%d" % (entityId)
00157
00158 text2 = None
00159 if hitType == HIT_TYPE_MISS:
00160 text = RDB.strings[6]
00161 elif hitType == HIT_TYPE_EVADE:
00162 text = RDB.strings[7]
00163 elif hitType == HIT_TYPE_CRIT:
00164 text = RDB.strings[8]
00165 text2= RDB.strings[5]
00166 elif hitType == HIT_TYPE_CRUSH:
00167 text = RDB.strings[9]
00168 text2= RDB.strings[5]
00169 elif hitType == HIT_TYPE_NORMAL:
00170 text = RDB.strings[5]
00171
00172 text = self.doTextSubst(text, val1=damage)
00173 self.rpc_chatText(text, MELEE_COMBAT_CHANNEL_ID)
00174 if text2 != None:
00175 text2 = self.doTextSubst(text2, val1=damage)
00176 self.rpc_chatText(text2, MELEE_COMBAT_CHANNEL_ID)
00177
00178
00179
00180
00181
00182
00183 class PlayerAvatar(Avatar):
00184
00185
00186
00187 def __init__(self):
00188 Avatar.__init__(self)
00189 print "PlayerAvatar.__init__()"
00190
00191
00192
00193
00194
00195
00196 def eventEntityKill(self, entityId, eventType, eventValue):
00197 xp = float(eventValue)/100.0
00198 self.rpc_printString(12, 0)
00199 AnGUI.service.proficienciesWindow.setXpBar(xp)
00200
00201 def eventProficiencyPointGain(self, entityId, eventType, eventValue):
00202 self.rpc_printString(13, 0)
00203 self.unspentProficiencyPoints += 1
00204 self.totalProficiencyPoints += 1
00205 AnGUI.service.proficienciesWindow.setPoints(self.unspentProficiencyPoints, self.totalProficiencyPoints)
00206
00207 def eventStatUpdate(self, entityId, eventType, eventValue):
00208 stat = None
00209 if eventType == event.STAT_UPDATE_CON:
00210 stat = self.characterStats.CON
00211 name = 'CON'
00212 elif eventType == event.STAT_UPDATE_STR:
00213 stat = self.characterStats.STR
00214 name = 'STR'
00215 elif eventType == event.STAT_UPDATE_DEX:
00216 stat = self.characterStats.DEX
00217 name = 'DEX'
00218 elif eventType == event.STAT_UPDATE_INT:
00219 stat = self.characterStats.INT
00220 name = 'INT'
00221
00222 if stat != None:
00223 stat.curValue=eventValue
00224 AnGUI.service.avatarHud.setStat(name, eventValue)
00225
00226
00227
00228
00229
00230
00231 def onLeaveWorld(self):
00232 print "PlayerAvatar.onLeaveWorld()"
00233 BigWorld.cancelCallback(self.callbackId)
00234 AnGUI.service.cancelListener(self)
00235
00236 def onEnterWorld( self, prereqs, initial=1 ):
00237
00238 if initial:
00239 Avatar.enterWorld(self)
00240
00241
00242 self.initStatsData()
00243
00244 self.in_mouse_move = False;
00245 self.isPlayer = True
00246
00247
00248 Actor.addEventProc(self, event.ENTITY_KILL, self.eventEntityKill)
00249 Actor.addEventProc(self, event.PROFICIENCY_POINT_GAIN, self.eventProficiencyPointGain)
00250 Actor.addEventProc(self, event.STAT_UPDATE_CON, self.eventStatUpdate)
00251 Actor.addEventProc(self, event.STAT_UPDATE_STR, self.eventStatUpdate)
00252 Actor.addEventProc(self, event.STAT_UPDATE_DEX, self.eventStatUpdate)
00253 Actor.addEventProc(self, event.STAT_UPDATE_INT, self.eventStatUpdate)
00254
00255
00256 weather = BigWorld.weather(self.spaceID)
00257 weatherSystem = weather.system("CLOUD")
00258 weatherSystem.direct(1, (0.8, 0.5, 0 , 0), 1)
00259 weather.windAverage(0.45, 0.7)
00260 weather.windGustiness(0.9)
00261
00262
00263 self.filter = BigWorld.PlayerAvatarFilter()
00264
00265
00266 self.physics = BigWorld.STANDARD_PHYSICS
00267 self.physics.velocity = ( 0.0, 0.0, 0.0 )
00268 self.physics.velocityMouse = "Direction"
00269 self.physics.angular = 0
00270 self.physics.collide = 1
00271 self.physics.fall = 1
00272 self.physics.modelWidth = 0.47
00273 self.physics.modelDepth = 0.3
00274
00275
00276 self.am.velocityProvider = self.physics.uncorrectedVelocity
00277
00278
00279
00280 self.enableMouseTargetting()
00281 BigWorld.target.caps(TargetCaps.CAP_CAN_HIT)
00282 self.minAimScore = 0.0
00283 self.maxAimScore = 0.99
00284 self.enableMouseTargetting()
00285
00286
00287 self.devwin=SYSGUI.load("gui/devwin.gui")
00288 self.devwin.script.active(True)
00289
00290
00291 self.callbackId = BigWorld.callback(1.0, self.updateCallback)
00292
00293
00294 AnGUI.service.addListener(self, AnGUI.GuiEvent("AutoAttackToggle"))
00295
00296
00297 AnGUI.service.proficienciesWindow.setPoints(self.unspentProficiencyPoints, self.totalProficiencyPoints, self.proficienciesList)
00298
00299
00300 AnGUI.service.avatarHud.setStats(str=self.getStat('STR'), con=self.getStat('CON'),
00301 dex=self.getStat('DEX'), int=self.getStat('INT'))
00302 AnGUI.service.avatarHud.setHpBar(self.healthPercent / 100.0)
00303
00304 def _sign(self, num):
00305 if num > 0.0:
00306 return 1
00307 elif num == 0.0:
00308 return 0
00309 else:
00310 return -1
00311
00312
00313 def handleKeyEvent( self, isDown, key, mods ):
00314
00315
00316
00317 if key==Keys.KEY_RIGHTMOUSE:
00318 self.handleRightMouseButton(isDown)
00319 elif key==Keys.KEY_LEFTMOUSE:
00320 self.handleLeftMouseButton(isDown)
00321 elif key==Keys.KEY_ESCAPE:
00322 self.handleEscapeKey(isDown)
00323
00324
00325 v = self.physics.velocity
00326
00327
00328 if key in (Keys.KEY_W,Keys.KEY_S,Keys.KEY_A,Keys.KEY_D):
00329 if isDown:
00330 self.pushMatchCaps()
00331 self.delMatchCap(9)
00332 else:
00333 self.popMatchCaps()
00334
00335
00336 speed = 5.0
00337 if key == Keys.KEY_W:
00338 v.z = isDown * speed
00339 elif key == Keys.KEY_S:
00340 v.z = isDown * -speed
00341 elif key == Keys.KEY_A:
00342 v.x = isDown * -speed
00343 elif key == Keys.KEY_D:
00344 v.x = isDown * speed
00345
00346 if v.x != 0.0 and v.z != 0.0:
00347 v.x = self._sign(v.x)*speed*0.707
00348 v.z = self._sign(v.z)*speed*0.707
00349
00350
00351 self.physics.velocity = v
00352
00353
00354
00355 def updateCallback(self):
00356 self.callbackId = BigWorld.callback(0.1, self.updateCallback)
00357 p=self.position
00358 self.devwin.line1.text="%.2f,%.2f,%.2f,%.2f" % (p.x, p.y, p.z,self.yaw)
00359 try:
00360 self.devwin.line2.text= "fps: %.2f" % (float(BigWorld.getWatcher("Render/FPSAverage")))
00361 except:
00362 pass
00363
00364
00365 e=BigWorld.target()
00366 if e != None:
00367 self.hasMouseOverTarget = True
00368 AnGUI.service.targetHud.gui.script.active(True)
00369 AnGUI.service.targetHud.targetFocus(e)
00370 elif self.hasMouseOverTarget:
00371 self.hasMouseOverTarget = False
00372
00373 if self.target==None:
00374 AnGUI.service.targetHud.gui.script.active(False)
00375 else:
00376 AnGUI.service.targetHud.targetFocus(self.target)
00377
00378
00379
00380 def handleConsoleInput(self, line):
00381 AnGUI.service.console.script.addMsg("You say: %s" % (line), 1l)
00382 self.cell.rpcSay(line)
00383
00384
00385 def handleGuiEvent(self, event):
00386 eventName = event.name
00387 eventAction = event.action
00388
00389 if eventName == "AutoAttackToggle":
00390 self.cell.rpcAutoAttackToggle()
00391
00392
00393
00394
00395
00396
00397
00398
00399 def facePosition(self, pos):
00400 vector = (pos[0] - self.position[0], 0, pos[2] - self.position[2])
00401 yaw = math.atan2(vector[0], vector[2])
00402
00403 self.physics.turn = yaw-self.yaw
00404 BigWorld.dcursor().yaw=yaw
00405
00406 def enableMouseTargetting( self ):
00407 if not hasattr( self, "mouseTargettingMatrix" ):
00408 self.mouseTargettingMatrix = BigWorld.MouseTargettingMatrix()
00409 BigWorld.target.source = self.mouseTargettingMatrix
00410 BigWorld.target.selectionFovDegrees = 2.0
00411 BigWorld.target.deselectionFovDegrees = 5.0
00412
00413
00414 def disableMouseTargetting( self ):
00415 if not hasattr( self, "playerTargettingMatrix" ):
00416 self.playerTargettingMatrix = BigWorld.ThirdPersonTargettingMatrix( BigWorld.PlayerMatrix() )
00417 BigWorld.target.source = self.playerTargettingMatrix
00418 BigWorld.target.selectionFovDegrees = 15.0
00419 BigWorld.target.deselectionFovDegrees = 20.0
00420
00421
00422
00423
00424
00425 def setTarget(self, entity):
00426 if entity != None:
00427 self.target = entity
00428 self.devwin.line3.text='target: %s' % (entity.name)
00429
00430 self.cell.rpc_setTarget(entity.id)
00431 else:
00432 self.target = None
00433 self.devwin.line3.text='target:'
00434 self.cell.rpc_setTarget(0)
00435
00436
00437
00438
00439
00440 def handleLeftMouseButton(self, isDown):
00441 ''' left mouse button click handler
00442 store the entity that BigWorld.target() returns (if any) a current target
00443 '''
00444 if isDown:
00445 e=BigWorld.target()
00446 if e != None:
00447 self.setTarget(e)
00448
00449 def handleRightMouseButton(self, isDown):
00450 ''' Note that showCursor() below actually does a lot more than just switching the
00451 cursor display on/off! When the GUI cursor is "switched" off the BigWorld cursor
00452 is set to to the DC (direction cursor) and this actually couples mouse movement
00453 onto your entity/avatar model (see the init() set up in Anoria.py '''
00454
00455 if isDown and not self.in_mouse_move:
00456 self.in_mouse_move = True
00457 self.physics.userDirected = 1
00458 AnGUI.Cursor.showCursor(False)
00459 if not isDown and self.in_mouse_move:
00460 self.in_mouse_move = False
00461 self.physics.userDirected = 0
00462 AnGUI.Cursor.showCursor(True)
00463
00464
00465
00466
00467 def handleEscapeKey(self, isDown):
00468 if isDown and self.target != None:
00469 self.setTarget(None)
00470