svc_slash.py (80240B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\devtools\script\svc_slash.py 2 from future.utils import raise_ 3 import logging 4 import os 5 import random 6 import sys 7 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText 8 from carbonui.primitives.containerAutoSize import ContainerAutoSize 9 from collections import defaultdict 10 import blue 11 import dogma.data 12 import evetypes 13 import localization 14 import log 15 import trinity 16 import triui 17 import uiblinker 18 import uthread 19 import utillib 20 from avatardisplay.avatardisplay import AvatarDisplay as ad 21 from carbon.common.script.sys import sessions 22 from carbon.common.script.sys.service import Service 23 from carbon.common.script.sys.serviceConst import ROLE_ANY, ROLE_LOGIN, ROLE_PLAYER, ROLE_WORLDMOD, SERVICE_RUNNING, SERVICE_START_PENDING 24 from carbonui import uiconst 25 from carbonui.primitives.container import Container 26 from carbonui.uicore import uicore 27 from controltowerresources.data import get_control_tower_resources 28 from eve.client.script.ui.control import eveEdit, eveLabel 29 from carbonui.button.group import ButtonGroup 30 from carbonui.control.window import Window 31 from player_messaging.client.ui_message import prompt_player, prompt_player_fsd_dialog 32 from eve.client.script.ui.util import uix 33 from eve.common.lib import appConst as const 34 from eve.common.script.net import eveMoniker 35 from eve.common.script.sys import eveCfg 36 from eve.devtools.script import param 37 from eve.devtools.script.slashError import Error 38 from eveexceptions import UserError 39 from eveprefs import boot 40 from eveservices.menu import GetMenuService 41 from eveservices.xmppchat import GetChatService 42 from inventorycommon.const import typePlex 43 from inventorycommon.typeHelpers import GetAveragePrice 44 import plex.client.api.repository as plex_api 45 from slash.client.event_publisher import SlashEventPublisher 46 from player_messaging import IGNORE_TO_TOP 47 from uihighlighting.const import DIRECTION_STRING_TO_ID 48 from uihighlighting.ui.uiutil import UI_CLASS_BY_NAME 49 logger = logging.getLogger('svc_slash') 50 SERVICENAME = 'slash' 51 TOKEN = '$' 52 aliasFile = 'aliases.ini' 53 macroFile = 'macros.ini' 54 version = 2.4 55 56 def Message(title, body, icon = triui.INFO): 57 prompt_player(body, title, options=uiconst.OK, icon=icon) 58 59 60 def AsyncMessage(*args): 61 uthread.new(Message, *args) 62 63 64 def Progress(title, text, current, total): 65 sm.GetService('loading').ProgressWnd(title, text, current, total) 66 67 68 class InlineFunctionResolver(): 69 70 def __init__(self): 71 pass 72 73 def __getitem__(self, func): 74 if ':' in func: 75 func, args = func.split(':', 1) 76 else: 77 args = () 78 method = getattr(self, 'f_' + func.lower(), None) 79 if func is None: 80 raise Error("unknown inline function '%s'" % func) 81 if args: 82 args = args.split(',') 83 return method(*args) 84 85 def _getinvrow(self, *args): 86 if len(args) == 1: 87 containerID = session.shipid 88 flag = args[0] 89 elif len(args) == 2: 90 if args[0].lower() == 'me': 91 containerID = session.shipid 92 else: 93 containerID = int(args[0]) 94 flag = args[1] 95 flag = getattr(const, 'flag' + flag.capitalize()) 96 for rec in sm.GetService('invCache').GetInventoryFromId(containerID).List(): 97 if rec.flag == flag: 98 return rec 99 100 def f_itemid(self, *args, **kw): 101 return self._getinvrow(*args).itemID 102 103 def f_typeid(self, *args): 104 return self._getinvrow(*args).typeID 105 106 107 def GetCharacter(name, ignoreNotFound = False): 108 result = sm.RemoteSvc('lookupSvc').LookupCharacters(name, 1) 109 if result: 110 cfg.eveowners.Prime([ each.characterID for each in result ]) 111 return result[0] 112 try: 113 return cfg.eveowners.Get(int(name)) 114 except: 115 if ignoreNotFound: 116 return None 117 AsyncMessage('No such character', 'Character not found:<br> %s' % name) 118 raise UserError(IGNORE_TO_TOP) 119 120 121 def extract_prefix_from(prefix, original): 122 if original.startswith(prefix): 123 return original[len(prefix):] 124 raise Error("Couldn't extract the prefix {} from {}".format(prefix, original)) 125 126 127 def parse_params_for_gag_or_ban(p): 128 try: 129 channel_specifier, char, reason, durationInMinutes = p.Parse('sssi') 130 except Error: 131 channel_specifier, char, reason = p.Parse('sss') 132 durationInMinutes = 30 133 134 return (channel_specifier, 135 char, 136 reason, 137 durationInMinutes) 138 139 140 def extract_arguments_for_gag_or_ban(p): 141 channel_specifier, char, reason, durationInMinutes = parse_params_for_gag_or_ban(p) 142 durationInSecs = durationInMinutes * 60 143 channelName = extract_prefix_from('channelName=', channel_specifier) 144 charID = GetCharacter(char).characterID 145 return (channelName, 146 charID, 147 reason, 148 durationInSecs) 149 150 151 def extract_arguments_for_ungag_or_unban(p): 152 channel_specifier, char = p.Parse('ss') 153 channelName = extract_prefix_from('channelName=', channel_specifier) 154 charID = GetCharacter(char).characterID 155 return (channelName, charID) 156 157 158 class SlashService(Service): 159 __guid__ = 'svc.slash' 160 __notifyevents__ = ['ProcessRestartUI', 'ProcessUIRefresh'] 161 __slashhook__ = True 162 __startupdependencies__ = ['publicGatewaySvc'] 163 164 def __init__(self): 165 Service.__init__(self) 166 self.patched = False 167 self.aliases = {} 168 self.macros = {} 169 self.typeIDsByName = None 170 self._slashEventPublisher = None 171 172 def Run(self, _memStream = None): 173 self.state = SERVICE_START_PENDING 174 try: 175 self.wnd = None 176 self.history = [] 177 self.historyPtr = -1 178 self.lastslash = '' 179 self.busy = self.aborted = False 180 self.jobs = [] 181 self.LoadMacrosAndAliases() 182 self.Clear() 183 except: 184 log.LogException() 185 sys.exc_clear() 186 187 self._slashEventPublisher = SlashEventPublisher(self.publicGatewaySvc) 188 self.state = SERVICE_RUNNING 189 190 def GetMacros(self): 191 self.LoadMacrosAndAliases() 192 return self.macros.items() 193 194 def LoadMacrosAndAliases(self): 195 defaultMacros = {'GMH: Unload All': '/unload me all', 196 'WM: Remove All Drones': '/unspawn range=500000 only=categoryDrone', 197 'WM: Remove All Fighters': '/unspawn range=500000 only=categoryFighter', 198 'WM: Remove All Wrecks': '/unspawn range=500000 only=groupWreck', 199 'WM: Remove CargoContainers': '/unspawn range=500000 only=groupCargoContainer,groupFreightContainer', 200 'WM: Remove SecureContainers': '/unspawn range=500000 only=groupSecureCargoContainer,groupAuditLogSecureContainer', 201 'HEALSELF: Repair My Ship': '/heal', 202 'HEALSELF: Repair My Modules': '/repairmodules', 203 'GMH: Online My Modules': '/online me', 204 'GML: Session Change 5sec': '/sessionchange 5'} 205 self.aliases = self.LoadStuff(aliasFile) 206 if len(self.aliases) == 0: 207 self.aliases = {} 208 self.macros = self.LoadStuff(macroFile) 209 self.macros.update(defaultMacros) 210 211 def LoadStuff(self, fileName): 212 targetFile = os.path.join(sm.StartService('insider').GetInsiderDir(), fileName) 213 if not os.path.exists(targetFile): 214 return {} 215 d = {} 216 lines = blue.AtomicFileRead(targetFile).replace('\r', '').replace('\x00', '').split('\n') 217 for line in lines: 218 aliasName, comseq = line.split('=', 1) 219 d[aliasName.strip()] = comseq.strip() 220 221 return d 222 223 def SaveStuff(self, thisDict, fileName): 224 text = '\r\n'.join([ '%s=%s' % (aliasName, comseq) for aliasName, comseq in thisDict.iteritems() ]) 225 targetFile = os.path.join(sm.StartService('insider').GetInsiderDir(), fileName) 226 blue.AtomicFileWrite(targetFile, text) 227 228 def Stop(self, memStream = None): 229 if self.wnd and not self.wnd.destroyed: 230 self.Hide() 231 Service.Stop(self, memStream) 232 233 def ConstructLayout(self): 234 self.wnd = wnd = Window.GetIfOpen(windowID='slashcon') 235 if wnd: 236 self.wnd.Maximize() 237 return 238 self.Layout() 239 240 def Layout(self): 241 self.wnd = wnd = Window.Open(windowID='slashcon') 242 wnd.DoClose = self.Hide 243 wnd.SetCaption('Slash') 244 wnd.OnUIRefresh = None 245 self.main = Container(name='con', parent=wnd.GetChild('main')) 246 self.input_container = Container(name='input', parent=self.main, align=uiconst.TOBOTTOM, height=20) 247 self.control_container = ContainerAutoSize(name='control', parent=self.main, align=uiconst.TOBOTTOM, padBottom=8, callback=self.ApplyWindowMinSize, only_use_callback_when_size_changes=True) 248 self.output_container = Container(name='output', parent=self.main, align=uiconst.TOALL) 249 self.ConstructCommandInput() 250 self.ConstructButtonGroup() 251 self.ConstructOutput() 252 self.ApplyWindowMinSize() 253 uicore.registry.SetFocus(self.input) 254 255 def ConstructOutput(self): 256 output = self.wnd.sr.output = eveEdit.Edit(setvalue=self.outputcontents, parent=self.output_container, readonly=1) 257 output.autoScrollToBottom = 1 258 259 def ConstructCommandInput(self): 260 eveLabel.Label(text='Command: ', parent=self.input_container, align=uiconst.TOLEFT, color=None, state=uiconst.UI_DISABLED, singleline=1) 261 self.input = self.wnd.sr.input = SingleLineEditText(name='slashCmd', parent=self.input_container, left=0, width=0, align=uiconst.TOALL) 262 self.input.OnKeyDown = (self.InputKey, self.input) 263 self.input.OnReturn = self.InputEnter 264 265 def ConstructButtonGroup(self): 266 buttons = ButtonGroup(parent=self.control_container, align=uiconst.CENTER) 267 buttons.AddButton('Clear', self.Clear) 268 buttons.AddButton('Exec Last', self.ExLast) 269 buttons.AddButton('Exec Once', self.ExOnce) 270 buttons.AddButton('Exec Loop', self.ExLoop) 271 buttons.AddButton('Abort', self.ExAbort) 272 273 def ApplyWindowMinSize(self): 274 width, height = self.wnd.GetWindowSizeForContentSize(height=self.control_container.height, width=self.control_container.width) 275 self.wnd.SetMinSize([width, 224]) 276 277 def Hide(self, *args): 278 if self.wnd: 279 self.slashcontents = self.wnd.sr.input.GetValue() 280 self.wnd.Close() 281 self.wnd = None 282 283 def ProcessRestartUI(self): 284 if self.wnd: 285 self.Hide() 286 self.ConstructLayout() 287 288 def ProcessUIRefresh(self): 289 if self.wnd: 290 self.wnd.Close() 291 self.ConstructLayout() 292 293 def Clear(self, *args): 294 cmds = [] 295 import svc 296 for sname in svc.__dict__: 297 s = getattr(svc, sname) 298 if getattr(s, '__slashhook__', False): 299 for m in dir(s): 300 if m.startswith('cmd_'): 301 cmds.append(m[4:]) 302 303 cmds.sort() 304 self.outputcontents = 'Commands: <font color="#ffc000">%s</font><br>' % (', '.join(cmds) or 'None') 305 if self.aliases: 306 cmds = self.aliases.keys() 307 cmds.sort() 308 self.outputcontents += 'Aliases: <font color="#00ffc0">%s</font><br>' % ', '.join(cmds) 309 self.outputcontents += 'Note: Slash commands, extended commands and user-defined aliases all work both in chat and in console. Commands that require a chat channel cannot be run in the console.<br>' 310 if self.wnd: 311 self.wnd.sr.output.SetText(self.outputcontents) 312 313 def Echo(self, text): 314 self.outputcontents = '%s%s' % (self.outputcontents, text) 315 if self.wnd: 316 self.wnd.sr.output.SetText(self.outputcontents) 317 318 def InputKey(self, otherself, key, flag): 319 CTRL = uicore.uilib.Key(uiconst.VK_CONTROL) 320 if CTRL and key == uiconst.VK_UP: 321 self.InputHistory(-1) 322 elif CTRL and key == uiconst.VK_DOWN: 323 self.InputHistory(1) 324 else: 325 SingleLineEditText.OnKeyDown(otherself, key, flag) 326 327 def InputHistory(self, offset): 328 if self.history: 329 self.historyPtr += offset 330 if self.historyPtr < -len(self.history): 331 self.historyPtr = -len(self.history) 332 return 333 if self.historyPtr >= 0: 334 self.historyPtr = 0 335 self.wnd.sr.input.SetValue('') 336 return 337 self.wnd.sr.input.SetValue(self.history[self.historyPtr]) 338 339 def InputEnter(self, *_args): 340 try: 341 self.lastslash = self.wnd.sr.input.GetValue() 342 except: 343 return 344 345 self.history.append(self.lastslash) 346 self.historyPtr = 0 347 self.wnd.sr.input.SetValue('') 348 self.Ex(self.lastslash) 349 350 def ExLoop(self, *_args): 351 try: 352 cmd = self.wnd.sr.input.GetValue().strip() 353 except: 354 return 355 356 if len(cmd) > 1: 357 result = uix.QtyPopup(maxvalue=50, minvalue=1, caption='Looped Execution', label='', hint='Specify number of times to execute:<br><br> %s<br><br>Note:<br>- Max. 50 iterations<br>- USE WITH CARE!' % cmd) 358 if result: 359 amount = result['qty'] 360 self.lastslash = cmd 361 self.wnd.sr.input.SetValue('') 362 self.Ex(cmd, amount) 363 364 def ExLast(self, *_args): 365 if self.lastslash: 366 self.Ex(self.lastslash) 367 368 def ExOnce(self, *_args): 369 try: 370 self.lastslash = self.wnd.sr.input.GetValue() 371 except: 372 return 373 374 self.Ex(self.lastslash) 375 376 def ExAbort(self, *_args): 377 if self.busy and not self.aborted: 378 self.Echo('<font color="#ffff00">*** Aborting...</font><br>') 379 self.aborted = True 380 self.busy = False 381 382 def Ex(self, this, count = 1): 383 if not this: 384 return 385 if this[0] != '/': 386 this = '/' + this 387 self.jobs.append((this, count)) 388 if self.busy: 389 if count > 0: 390 self.Echo('<font color="#ffff00">*** Queued(%d): %s</font><br>' % (count, this)) 391 else: 392 self.Echo('<font color="#ffff00">*** Queued: %s</font><br>' % this) 393 return 394 self.JobHandler() 395 396 def JobHandler(self): 397 try: 398 self.aborted = False 399 while self.jobs and not self.aborted: 400 this, count = self.jobs.pop(0) 401 isLoop = count > 1 402 try: 403 self.busy = True 404 self.aborted = False 405 if isLoop: 406 self.Echo('<font color="#ffff00">*** Loop started (%d iterations)</font><br>' % count) 407 while count and not self.aborted: 408 self.Echo('<font color="#00ffff">slash: %s</font><br>' % this) 409 try: 410 res = sm.GetService('slash').SlashCmd(this) 411 if res and len(str(res)) > 5000: 412 res = str(res)[:5000] + '...' 413 self.Echo('<font color="#00ff55">slash result: %s</font><br>' % res) 414 except UserError as e: 415 if e.args[0] in ('SlashError',): 416 self.Echo('<font color="#ff5500">slash error: %s</font><br>' % e.dict['reason']) 417 break 418 else: 419 self.Echo('<font color="#00ff55">slash result: None</font><br>') 420 raise_(UserError, e) 421 422 count -= 1 423 blue.pyos.synchro.SleepWallclock(100) 424 425 if isLoop: 426 if self.aborted: 427 reason = 'Aborted by user' 428 elif count != 0: 429 reason = 'Error condition' 430 else: 431 reason = 'Batch completed' 432 self.Echo('<font color="#ffff00">*** Loop terminated (%s)</font><br>' % reason) 433 finally: 434 self.busy = False 435 436 else: 437 if self.jobs: 438 self.Echo('<font color="#ffff00">*** Slash command queue flushed</font><br>') 439 self.jobs = [] 440 441 finally: 442 self.aborted = False 443 444 def FetchRemoteCommandList(self): 445 if hasattr(self, 'remoteCommandList'): 446 return 447 try: 448 sm.RemoteSvc('slash').SlashCmd('/') 449 except UserError as e: 450 try: 451 msg = e.args[1]['reason'] 452 cmds = eval(msg.split(': ')[1]) 453 cmds.sort() 454 except: 455 cmds = [] 456 log.LogException() 457 Message('Hmmm', "Unable to acquire server slash command list. Not particularly bad, just means command autocompletion won't work") 458 sys.exc_clear() 459 460 sys.exc_clear() 461 462 self.remoteCommandList = cmds 463 464 def MatchCmd(self, command): 465 ret = [] 466 localMatch = False 467 for cmd in self.aliases: 468 if cmd.startswith(command): 469 if cmd == command: 470 return ([cmd], True) 471 if cmd not in ret: 472 ret.append(cmd) 473 localMatch = True 474 475 for cmd in self.remoteCommandList: 476 if cmd.startswith(command): 477 if cmd == command: 478 return ([cmd], False) 479 ret.append(cmd) 480 481 import svc 482 for sname in svc.__dict__: 483 s = getattr(svc, sname) 484 if getattr(s, '__slashhook__', False): 485 for f in s.__dict__: 486 if f.startswith('cmd_' + command): 487 cmd = f[4:] 488 if cmd == command: 489 return ([cmd], True) 490 if cmd not in ret: 491 ret.append(cmd) 492 localMatch = True 493 494 return (ret, localMatch) 495 496 def SlashCmd(self, command, fallThrough = True, isMacro = False): 497 if command.startswith('//'): 498 return sm.RemoteSvc('slash').SlashCmd(command[1:]) 499 return self._SlashCmd(command, fallThrough, isMacro) 500 501 def _SlashCmd(self, txt, fallThrough, isMacro): 502 if isMacro: 503 self.FetchRemoteCommandList() 504 command = None 505 else: 506 parts = txt.split(' ', 1) 507 command = parts[0].strip().lower() 508 if len(parts) == 2: 509 args = parts[1].strip() 510 else: 511 args = '' 512 if command[0] == '/': 513 command = command[1:] 514 self.FetchRemoteCommandList() 515 if self.remoteCommandList is not None: 516 matches, hasLocal = self.MatchCmd(command) 517 if hasLocal: 518 if len(matches) == 1: 519 command = matches[0] 520 else: 521 raise Error('%s is ambiguous. It resolves to multiple commands or aliases: %s' % (command, matches)) 522 if command in self.aliases or isMacro: 523 if isMacro: 524 sequence = txt 525 else: 526 sequence = self.aliases[command] 527 sequence = sequence.split(';') 528 for line in sequence: 529 line = line.strip() 530 if line: 531 newline = [] 532 p = param.ParamObject(txt) 533 for part in line.split(TOKEN): 534 if newline: 535 if len(part) >= 1: 536 if part[0] in '0123456789': 537 try: 538 if len(part) >= 2 and part[1] == '-': 539 part = p[int(part[0]):] + part[2:] 540 else: 541 part = p[int(part[0])] + part[1:] 542 except param.Error: 543 raise Error('Alias expected additional parameter(s)') 544 545 else: 546 part = TOKEN + part 547 newline.append(part) 548 549 newline = ''.join(newline) % InlineFunctionResolver() 550 res = self.SlashCmd(newline) 551 552 if len(sequence) == 1: 553 return res 554 return 'Ok' 555 try: 556 args = args % InlineFunctionResolver() 557 commandLine = '/' + command + ' ' + args 558 except Error: 559 raise 560 except: 561 log.LogException() 562 raise Error('unexpected error resolving inline function') 563 564 import svc 565 for raw_service_name in svc.__dict__: 566 service_classobj = getattr(svc, raw_service_name) 567 if getattr(service_classobj, '__slashhook__', False): 568 command_name = 'cmd_' + command 569 slash_func = getattr(service_classobj, command_name, None) 570 if slash_func: 571 try: 572 service_name = service_classobj.__guid__[4:] 573 service_instance = sm.GetService(service_name) 574 function_to_call = getattr(service_instance, command_name) 575 ret = function_to_call(param.ParamObject(args)) 576 if ret: 577 return ret 578 break 579 except param.Error as e: 580 if slash_func.__doc__: 581 raise Error('usage: /%s %s' % (command, slash_func.__doc__.replace('%s', command))) 582 else: 583 raise Error('/%s called with crap args and doesnt handle it properly' % command) 584 585 if fallThrough: 586 return sm.RemoteSvc('slash').SlashCmd(commandLine) 587 588 def cmd_sethackingdifficulty(self, p): 589 sm.GetService('hackingUI').SetDifficulty(p.Parse('i')[0]) 590 return 'Ok' 591 592 def cmd_sethackingvirusstats(self, p): 593 integers = p.Parse('iii') 594 sm.GetService('hackingUI').SetVirusStats(integers[0], integers[1], integers[2]) 595 return 'Ok' 596 597 def cmd_openhacking(self, p): 598 sm.GetService('hackingUI').TriggerNewGame() 599 600 def cmd_run(self, p): 601 filename, = p.Parse('s') 602 if not os.path.exists(filename): 603 filename += '.txt' 604 if not os.path.exists(filename): 605 raise Error('file not found') 606 for line in open(filename, 'r'): 607 line = line.strip() 608 if line.startswith('/'): 609 self.SlashCmd(line) 610 611 return 'Ok' 612 613 def cmd_macromenu(self, p): 614 return self.cmd_alias(p, True) 615 616 def cmd_alias(self, p, isMacro = False): 617 what, rest = p.Parse('s?r') 618 what = what.lower() 619 if isMacro: 620 thing = 'Macro' 621 catalog = self.macros 622 file = macroFile 623 else: 624 thing = 'Alias' 625 catalog = self.aliases 626 file = aliasFile 627 if what == 'add': 628 what, aliasName, rest = p.Parse('ssr') 629 for key in catalog.keys(): 630 if key.lower() == aliasName.lower(): 631 action = 'modified' 632 break 633 else: 634 action = 'added' 635 636 catalog[aliasName] = rest 637 self.SaveStuff(catalog, file) 638 return '%s %s %s' % (thing, aliasName, action) 639 if what == 'del': 640 if not rest: 641 raise param.Error 642 aliasName = rest.lower().strip('"') 643 for key in catalog.keys(): 644 if key.lower() == aliasName: 645 del catalog[aliasName] 646 self.SaveStuff(catalog, file) 647 return '%s %s deleted' % (thing, aliasName) 648 else: 649 raise Error('No such %s: %s' % (thing, aliasName)) 650 651 elif what == 'list': 652 cmds = catalog.keys() 653 cmds.sort() 654 return '%s: <font color="#00ffc0">%s</font><br>' % (thing, ', '.join(cmds)) 655 for key, item in catalog.iteritems(): 656 if key.lower() == what.lower(): 657 return '%s %s is defined as: %s' % (thing, what, item) 658 659 raise param.Error 660 661 def cmd_loop(self, p): 662 count, rest = p.Parse('ir') 663 if count >= 10: 664 if count > 50: 665 Message('Looped Execution', 'The number of iterations must be less than 50') 666 return 667 result = prompt_player(title='Looped Execution', text='You have specified %d iterations.<br>Slash commands looped this way cannot be aborted. Depending on the slash command, it can take a long time to complete or cause a high server load.<br>Continue?' % count, options=uiconst.OKCANCEL, icon=uiconst.WARNING) 668 if result in (uiconst.ID_CANCEL, uiconst.ID_CLOSE): 669 return 670 for i in xrange(count): 671 self.SlashCmd(rest) 672 673 return 'Ok' 674 675 def cmd_chtgag(self, p): 676 channelName, charID, reason, durationInSecs = extract_arguments_for_gag_or_ban(p) 677 GetChatService().MuteUser(channelName, charID, reason, durationInSecs) 678 return 'Ok' 679 680 def cmd_chtungag(self, p): 681 channelName, charID = extract_arguments_for_ungag_or_unban(p) 682 GetChatService().UnmuteUser(channelName, charID) 683 return 'Ok' 684 685 def cmd_chtban(self, p): 686 channelName, charID, reason, durationInSecs = extract_arguments_for_gag_or_ban(p) 687 GetChatService().BanUserFromChannel(channelName, charID, reason, durationInSecs) 688 return 'Ok' 689 690 def cmd_chtunban(self, p): 691 channelName, charID = extract_arguments_for_ungag_or_unban(p) 692 GetChatService().UnbanUserFromChannel(channelName, charID) 693 return 'Ok' 694 695 def cmd_whoami(self, p): 696 roles = [] 697 for k, v in globals().iteritems(): 698 if k.startswith('ROLE_'): 699 if type(v) in (int, long): 700 if session.role & v and v not in (ROLE_ANY, ROLE_PLAYER, ROLE_LOGIN): 701 roles.append(k[5:]) 702 703 text = ['character: %s (%s)' % (session.charid, cfg.eveowners.Get(session.charid).name), 'user: %s (type: %s)' % (session.userid, session.userType), 'role: 0x%08X (%s)' % (session.role, ', '.join(roles))] 704 AsyncMessage('Account Information', '<br>'.join(text)) 705 return 'Ok' 706 707 def cmd_hop(self, p): 708 if session.role & ROLE_WORLDMOD: 709 return 710 dist, = p.Parse('i') 711 if session.stationid: 712 raise Error("This obviously won't work in a station :)") 713 bp = sm.GetService('michelle').GetBallpark() 714 me = bp.GetBall(bp.ego) 715 v = trinity.TriVector(me.vx, me.vy, me.vz) 716 v.Normalize() 717 v.Scale(dist) 718 sm.RemoteSvc('slash').SlashCmd('/tr me me offset=%d,%d,%d' % (int(v.x), int(v.y), int(v.z))) 719 GetMenuService().ClearAlignTargets() 720 return 'Ok' 721 722 def cmd_online(self, p): 723 target, = p.Parse('s') 724 activeShipID = eveCfg.GetActiveShip() 725 if session.stationid is not None and (target == 'me' or int(target) == activeShipID): 726 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 727 for module in dogmaLocation.dogmaItems[activeShipID].GetFittedItems().itervalues(): 728 if const.effectOnline in (row.effectID for row in dogma.data.get_type_effects(module.typeID)): 729 try: 730 dogmaLocation.OnlineModule(module.itemID) 731 except UserError as e: 732 if e.msg.startswith('EffectAlreadyActive'): 733 continue 734 raise 735 736 else: 737 sm.RemoteSvc('slash').SlashCmd('/online %s' % target) 738 return 'Ok' 739 740 def cmd_super(self, p): 741 target, = p.Parse('s') 742 if target.lower() == 'me': 743 victim = 'you' 744 target = 'me' 745 else: 746 char = GetCharacter(target) 747 victim = '"' + char.characterName + '"' 748 target = char.characterID 749 Progress('Making %s Leet' % victim, 'Please wait...', 0, 1) 750 try: 751 sm.RemoteSvc('slash').SlashCmd('/giveskill %s super 5' % target) 752 finally: 753 Progress('Making %s Leet' % victim, 'Done!', 1, 1) 754 755 return 'Ok' 756 757 def cmd_noob(self, p): 758 target, = p.Parse('s') 759 if target.lower() == 'me': 760 victim = 'you' 761 target = 'me' 762 else: 763 char = GetCharacter(target) 764 victim = '"' + char.characterName + '"' 765 target = char.characterID 766 Progress('Making %s n00b' % victim, 'Please wait...', 0, 1) 767 try: 768 sm.RemoteSvc('slash').SlashCmd('/removeskill %s all' % target) 769 sm.GetService('skillqueue').ReInitialize() 770 finally: 771 Progress('Making %s n00b' % victim, 'Done!', 1, 1) 772 773 return 'Ok' 774 775 def cmd_givestarterskills(self, p): 776 try: 777 target, = p.Parse('s') 778 if target.lower() == 'me': 779 victim = 'you' 780 target = session.charid 781 else: 782 char = GetCharacter(target) 783 victim = '"' + char.characterName + '"' 784 target = char.characterID 785 except param.Error: 786 victim = 'you' 787 target = session.charid 788 789 Progress('Giving %s starter skills' % victim, 'Please wait...', 0, 1) 790 try: 791 sm.RemoteSvc('slash').SlashCmd('/givestarterskills %s' % target) 792 finally: 793 Progress('Giving %s starter skills' % victim, 'Done!', 1, 1) 794 795 return 'Ok' 796 797 def cmd_randomizeskills(self, p): 798 Progress('Randomizing your skills,', 'Please wait...', 0, 1) 799 try: 800 sm.RemoteSvc('slash').SlashCmd('/randomizeskills') 801 finally: 802 Progress('Randomizing your skills,', 'Done!', 1, 1) 803 804 return 'Ok' 805 806 def cmd_bp(self, p): 807 try: 808 name, rest = p.Parse('s?r') 809 if rest is None: 810 rest = '' 811 except param.Error: 812 rest = '' 813 try: 814 name, = p.Parse('r') 815 except param.Error: 816 return 817 818 typeID = self.AutoComplete(name, allowedCategories=[const.categoryBlueprint]) 819 if typeID: 820 return sm.RemoteSvc('slash').SlashCmd('/bp %s %s' % (typeID, rest)) 821 else: 822 return 823 824 def cmd_createitem(self, p): 825 qty = 1 826 try: 827 name, = p.Parse('s') 828 except param.Error: 829 try: 830 name, qty = p.Parse('ss') 831 except param.Error: 832 try: 833 name, = p.Parse('r') 834 except param.Error: 835 return 836 837 typeID = self.AutoComplete(name) 838 if typeID: 839 return sm.RemoteSvc('slash').SlashCmd('/createitem %s %s' % (typeID, qty)) 840 else: 841 return 842 843 def cmd_unload(self, p): 844 try: 845 target, rest = p.Parse('s?r') 846 if rest is None: 847 rest = '' 848 else: 849 rest = rest.lower().strip('"') 850 except param.Error: 851 return 852 853 if target.lower() != 'me' or rest == 'all' or rest.isdigit(): 854 return 855 matches = {} 856 for rec in sm.GetService('invCache').GetInventoryFromId(session.shipid).List(): 857 if rec.categoryID != const.categoryOwner: 858 typeName = evetypes.GetName(rec.typeID) 859 if rest in typeName.lower(): 860 matches[typeName] = rec.typeID 861 862 if not matches: 863 return 864 matches = matches.items() 865 matches.sort() 866 if len(matches) > 1: 867 ret = uix.ListWnd(matches, listtype='generic', caption='AutoComplete: %d types found' % len(matches)) 868 else: 869 ret = matches[0] 870 if ret: 871 return sm.RemoteSvc('slash').SlashCmd('/unload me %s' % ret[1].typeID) or 'Ok' 872 else: 873 return 874 875 def cmd_dogmaupdate(self, p): 876 sm.RemoteSvc('slash').SlashCmd('/dogmaupdate') 877 sm.GetService('clientEffectCompiler').effects.clear() 878 prompt_player_fsd_dialog('CustomNotify', {'notify': 'Server has regenerated the expressions and yours have been cleared'}) 879 return 'Ok' 880 881 def cmd_loadcontainer(self, p): 882 return self.cmd_fit(p, cmd='load', categories=None) 883 884 def cmd_fit(self, p, cmd = 'fit', categories = -1): 885 if categories == -1: 886 categories = [const.categoryModule, const.categoryDrone, const.categoryCharge] 887 qty = '' 888 try: 889 target, name, qty = p.Parse('sss') 890 except param.Error: 891 try: 892 target, name = p.Parse('ss') 893 except param.Error: 894 try: 895 target, name = p.Parse('sr') 896 except param.Error: 897 return 898 899 typeID = self.AutoComplete(name, allowedCategories=categories) 900 if typeID: 901 return sm.RemoteSvc('slash').SlashCmd('/%s "%s" %s %s' % (cmd, 902 target, 903 typeID, 904 qty)) 905 else: 906 return 907 908 def cmd_entity(self, p): 909 qty = 1 910 try: 911 action, qty, name = p.Parse('sir') 912 except param.Error: 913 try: 914 action, name = p.Parse('sr') 915 except param.Error: 916 return 917 918 if action.lower() != 'deploy': 919 return 920 else: 921 typeID = self.AutoComplete(name, allowedCategories=[const.categoryEntity]) 922 if typeID: 923 return sm.RemoteSvc('slash').SlashCmd('/entity deploy %s %s' % (qty, typeID)) or 'Ok' 924 return 925 926 def cmd_spawn(self, p): 927 try: 928 name, rest = p.Parse('sr') 929 except param.Error: 930 try: 931 name, = p.Parse('r') 932 rest = '' 933 except param.Error: 934 return 935 936 typeID = self.AutoComplete(name, allowedCategories=[const.categoryShip, const.categoryAsteroid, const.categoryDrone], allowedGroups=[const.groupLargeCollidableObject, 937 const.groupCargoContainer, 938 const.groupBiomass, 939 const.groupComet, 940 const.groupCloud, 941 const.groupSentryGun, 942 const.groupInvisibleBeacon]) 943 if typeID: 944 return sm.RemoteSvc('slash').SlashCmd('/spawn %s %s' % (typeID, rest)) 945 else: 946 return 947 948 def cmd_spawnn(self, p): 949 try: 950 qty, deviation, name = p.Parse('ifr') 951 except param.Error: 952 return 953 954 typeID = self.AutoComplete(name, allowedCategories=[const.categoryShip, const.categoryAsteroid, const.categoryDrone], allowedGroups=[const.groupLargeCollidableObject, 955 const.groupCargoContainer, 956 const.groupBiomass, 957 const.groupComet, 958 const.groupCloud, 959 const.groupInvisibleBeacon, 960 const.groupSentryGun]) 961 if typeID: 962 return sm.RemoteSvc('slash').SlashCmd('/spawnn %s %s %s' % (qty, deviation, typeID)) or 'Ok' 963 else: 964 return 965 966 def cmd_giveskills(self, p): 967 try: 968 target, skillname, level = p.Parse('ssi') 969 except param.Error: 970 try: 971 level = None 972 target, skillname = p.Parse('sr') 973 except param.Error: 974 return 975 976 skillname = skillname.strip('"') 977 if skillname.lower() in ('all', 'super'): 978 return 979 else: 980 typeID = self.AutoComplete(skillname, allowedCategories=[const.categorySkill]) 981 if typeID: 982 if level is None: 983 level = 5 984 return sm.RemoteSvc('slash').SlashCmd('/giveskill "%s" %s %s' % (target, typeID, level)) or 'Ok' 985 return 986 987 def cmd_removeskills(self, p): 988 try: 989 level = None 990 target, skillname = p.Parse('sr') 991 except param.Error: 992 return 993 994 skillname = skillname.strip('"') 995 if skillname.lower() == 'all': 996 return 997 else: 998 typeID = self.AutoComplete(skillname, allowedCategories=[const.categorySkill]) 999 if typeID: 1000 return sm.RemoteSvc('slash').SlashCmd('/removeskill "%s" %s' % (target, typeID)) or 'Ok' 1001 return 1002 1003 def cmd_skillscopy(self, p): 1004 try: 1005 fromCharacter, toCharacter = p.Parse('sr') 1006 except param.Error: 1007 return 1008 1009 Progress('Preparing Copy', 'Please wait...', 0, 1) 1010 try: 1011 sm.RemoteSvc('slash').SlashCmd('/skillscopy "%s" "%s"' % (fromCharacter, toCharacter)) 1012 finally: 1013 Progress('Copying Skills', 'Done!', 1, 1) 1014 1015 return 'Ok' 1016 1017 def _extract_windowName_from_params(self, p): 1018 extracted_param = p.Parse('s')[0] 1019 prefix = 'windowID=chatchannel_' 1020 if extracted_param.startswith(prefix): 1021 windowName = extracted_param[len(prefix):] 1022 else: 1023 raise Error("Couldn't extract a windowName from the params") 1024 return windowName 1025 1026 def cmd_massfleetinvite(self, p): 1027 fleetSvc = sm.StartService('fleet') 1028 fleetSvc.CheckIsInFleet() 1029 windowName = self._extract_windowName_from_params(p) 1030 candidates = sm.GetService('XmppChat').GetMemberIDsForNamedWindow(windowName) 1031 if session.charid in candidates: 1032 candidates.remove(session.charid) 1033 t = len(candidates) 1034 c = 0 1035 for charID in candidates: 1036 c += 1 1037 Progress('Inviting...', '[%d/%d] %s' % (c, t, cfg.eveowners.Get(charID).ownerName), c, t) 1038 try: 1039 fleetSvc.fleet.Invite(charID, None, None, None, True) 1040 except: 1041 pass 1042 1043 Progress('Inviting...', 'Done!', 1, 1) 1044 return 'Ok' 1045 1046 def cmd_masstransport(self, p): 1047 windowName = self._extract_windowName_from_params(p) 1048 memberIDs = sm.GetService('XmppChat').GetMemberIDsForNamedWindow(windowName) 1049 local_memberIDs = sm.GetService('XmppChat').GetMemberIDsForNamedWindow('local') 1050 candidates = [ charID for charID in memberIDs if charID not in local_memberIDs ] 1051 if session.charid in candidates: 1052 candidates.remove(session.charid) 1053 t = len(candidates) 1054 c = 0 1055 for charID in candidates: 1056 c += 1 1057 Progress('Transfering...', '[%d/%d] %s' % (c, t, cfg.eveowners.Get(charID).ownerName), c, t) 1058 sm.RemoteSvc('slash').SlashCmd('/tr %d me noblock' % charID) 1059 1060 Progress('Transfering...', 'All commands sent to the server', 1, 1) 1061 return 'Ok' 1062 1063 def cmd_massstanding(self, p): 1064 try: 1065 fromID, newStanding = p.Parse('sr') 1066 except: 1067 raise UserError('SlashError', {'reason': 'Provide from and the new standing value.'}) 1068 sys.exc_clear() 1069 return 1070 1071 local = (('solarsystemid2', session.solarsystemid2),) 1072 c = self.GetChannel() 1073 if not c or c.channelID == local: 1074 return 1075 candidates = [ charID for charID in self.GetChannelUsers() ] 1076 if session.charid in candidates: 1077 candidates.remove(session.charid) 1078 t = len(candidates) 1079 c = 0 1080 reason = 'Mass standing change by %s' % cfg.eveowners.Get(session.charid).name 1081 corps = sm.RemoteSvc('lookupSvc').LookupCorporations(fromID) 1082 corpIDs = [ each.corporationID for each in corps ] 1083 factions = sm.RemoteSvc('lookupSvc').LookupFactions(fromID) 1084 factionIDs = [ each.factionID for each in factions ] 1085 resultIDs = corpIDs + factionIDs 1086 resultList = [ (cfg.eveowners.Get(each).name, cfg.eveowners.Get(each).id, cfg.eveowners.Get(each).typeID) for each in resultIDs ] 1087 if not resultList: 1088 raise UserError('SlashError', {'reason': 'Unable to resolve corporation or faction name'}) 1089 sys.exc_clear() 1090 return 1091 ret = uix.ListWnd(resultList, caption='AutoComplete: %d types found' % len(resultList), ordered=1) 1092 if ret: 1093 if prompt_player_fsd_dialog('CustomQuestion', {'header': 'Change standings?', 1094 'question': 'Do you really want to change the standings towards %s for the characters in this channel?' % ret[0]}, uiconst.YESNO) == uiconst.ID_YES: 1095 for charID in candidates: 1096 c += 1 1097 Progress('Setting standings...', '[%d/%d] %s' % (c, t, cfg.eveowners.Get(charID).ownerName), c, t) 1098 sm.RemoteSvc('slash').SlashCmd('/setstanding "%s" %d %s "%s"' % (ret[1], 1099 charID, 1100 newStanding, 1101 reason)) 1102 1103 txt = 'Standings to %s set to %s for %d characters' % (ret[0], newStanding, c) 1104 else: 1105 txt = 'Standings to %s left unmodified' % ret[0] 1106 else: 1107 txt = 'Standings left unmodified' 1108 Progress('Setting standings...', 'Done!', 1, 1) 1109 prompt_player_fsd_dialog('CustomNotify', {'notify': txt}) 1110 return 'Ok' 1111 1112 def cmd_avatar(self, p): 1113 b = u'' 1114 try: 1115 a, b = p.Parse('sr') 1116 except param.Error: 1117 a = p.Parse('s')[0] 1118 1119 if a.isdigit(): 1120 if not b: 1121 ad.DisplayCharacter(a) 1122 else: 1123 b_params = b.split() 1124 dna_file = None 1125 anim_file = None 1126 audio_msg = None 1127 for par in b_params: 1128 if '.prs' in par: 1129 dna_file = par 1130 elif '.gr2' in par or '.gsf' in par: 1131 anim_file = par 1132 else: 1133 audio_msg = par 1134 1135 ad.DisplayCharacter(a, dna_str=dna_file, anim_str=anim_file, audio_str=audio_msg) 1136 else: 1137 a_params = a.split() 1138 dna_file = None 1139 anim_file = None 1140 audio_msg = None 1141 for par in a_params: 1142 if '.prs' in par: 1143 dna_file = par 1144 elif '.gr2' in par or '.gsf' in par: 1145 anim_file = par 1146 else: 1147 audio_msg = par 1148 1149 if b: 1150 b_params = b.split() 1151 for par in b_params: 1152 if '.prs' in par: 1153 dna_file = par 1154 elif '.gr2' in par or '.gsf' in par: 1155 anim_file = par 1156 else: 1157 audio_msg = par 1158 1159 ad.DisplayCharacter(0, dna_str=dna_file, anim_str=anim_file, audio_str=audio_msg) 1160 return 'Ok' 1161 1162 def cmd_avatarscene(self, p): 1163 b = u'' 1164 anim_strs = [] 1165 audio_strs = [] 1166 b = p.Parse('r') 1167 b_params = b[0].split() 1168 a = b_params.pop(0) 1169 n = None 1170 if b_params: 1171 for par in b_params: 1172 try: 1173 n = int(par) 1174 except ValueError(): 1175 n = None 1176 except Exception as e: 1177 raise e 1178 1179 if '.gr2' in par or '.gsf' in par or par == 'no_anim': 1180 anim_strs.append(par) 1181 else: 1182 audio_strs.append(par) 1183 1184 ad.DisplayPreparedScene(a, anim_strs=anim_strs, audio_strs=audio_strs, sub_char=n) 1185 return 'Ok' 1186 1187 def cmd_avatarcommand(self, p): 1188 b = p.Parse('r') 1189 b_params = b[0].split() 1190 command = b_params.pop(0) 1191 if b_params: 1192 sm.ScatterEvent('OnAvatarCommand', command, *b_params) 1193 else: 1194 sm.ScatterEvent('OnAvatarCommand', command) 1195 return 'Ok' 1196 1197 def cmd_pos(self, p): 1198 try: 1199 action, id = p.Parse('sr') 1200 except param.Error: 1201 try: 1202 action = p.Parse('s') 1203 bp = sm.GetService('michelle').GetBallpark() 1204 for ballID in bp.balls.keys(): 1205 try: 1206 item = bp.GetInvItem(ballID) 1207 if item.groupID in (const.groupControlTower,): 1208 id = item.itemID 1209 action = action[0] 1210 except: 1211 pass 1212 1213 except: 1214 pass 1215 1216 if not id: 1217 return 1218 elif action.lower() != 'fuel': 1219 return 1220 else: 1221 try: 1222 id = int(id) 1223 except ValueError: 1224 prompt_player_fsd_dialog('CustomInfo', {'info': "This must be called as either '/pos fuel' or '/pos fuel itemID'"}) 1225 return 'ok' 1226 1227 resourcesPerHour = [] 1228 reinforcedResourcesPerHour = [] 1229 totalFuelVolumePerCycle = float() 1230 starbaseCharters = [] 1231 invCache = sm.GetService('invCache') 1232 chosenTower = invCache.GetInventoryFromId(id) 1233 secStatus = sm.GetService('map').GetSecurityStatus(session.locationid) 1234 for typeID in evetypes.GetTypeIDsByGroup(const.groupLease): 1235 starbaseCharters.append(typeID) 1236 1237 resources = get_control_tower_resources(chosenTower.typeID) 1238 for resource in resources: 1239 if resource.resourceTypeID == const.typeStrontiumClathrates: 1240 reinforcedResourcesPerHour.append((resource.resourceTypeID, resource.quantity, evetypes.GetVolume(resource.resourceTypeID))) 1241 elif secStatus < 0.4: 1242 if resource.resourceTypeID not in starbaseCharters: 1243 resourcesPerHour.append((resource.resourceTypeID, resource.quantity, evetypes.GetVolume(resource.resourceTypeID))) 1244 else: 1245 resourcesPerHour.append((resource.resourceTypeID, resource.quantity, evetypes.GetVolume(resource.resourceTypeID))) 1246 1247 for resourceTypeID, amountPerCycle, resourceVolume in resourcesPerHour: 1248 totalFuelVolumePerCycle += int(amountPerCycle * resourceVolume) 1249 1250 totalFuelVolumePerCycle += 1 1251 strontVolume = reinforcedResourcesPerHour[0][2] 1252 fuelBay = chosenTower.GetCapacity() 1253 strontBay = chosenTower.GetCapacity(flag=const.flagSecondaryStorage) 1254 fuelCycles = int(fuelBay.capacity / totalFuelVolumePerCycle) 1255 strontCycles = int(strontBay.capacity / strontVolume) 1256 if session.role & ROLE_WORLDMOD: 1257 addList = [] 1258 for commodity, amountPerCycle, resourceVolume in reinforcedResourcesPerHour: 1259 sm.GetService('slash').SlashCmd('crea %d %s' % (commodity, strontCycles)) 1260 for cargo in invCache.GetInventoryFromId(session.shipid).ListCargo(): 1261 if cargo.typeID == commodity: 1262 addList.append(cargo.itemID) 1263 1264 invCache.GetInventoryFromId(id).MultiAdd(addList, session.shipid, flag=const.flagSecondaryStorage) 1265 addList = [] 1266 for fuel, amountPerCycle, resourceVolume in resourcesPerHour: 1267 sm.GetService('slash').SlashCmd('crea %d %s' % (fuel, int(fuelCycles * amountPerCycle))) 1268 for cargo in invCache.GetInventoryFromId(session.shipid).ListCargo(): 1269 if cargo.typeID == fuel and cargo.stacksize == fuelCycles * amountPerCycle: 1270 addList.append(cargo.itemID) 1271 1272 invCache.GetInventoryFromId(id).MultiAdd(addList, session.shipid, flag=const.flagNone) 1273 return 'Ok' 1274 shipType = const.typeBHMegaCargoShip 1275 oldShipItemID = session.shipid 1276 newShipItemID = int() 1277 if invCache.GetInventoryFromId(int(session.shipid)).typeID != shipType: 1278 newShipItemID = sm.RemoteSvc('slash').SlashCmd('/spawn %d' % shipType) 1279 ship = sm.StartService('gameui').GetShipAccess() 1280 if ship: 1281 sm.StartService('sessionMgr').PerformSessionChange('board', ship.Board, newShipItemID, oldShipItemID) 1282 blue.pyos.synchro.SleepSim(5000) 1283 addList = [] 1284 for commodity, amountPerCycle, resourceVolume in reinforcedResourcesPerHour: 1285 sm.GetService('slash').SlashCmd('load me %d %s' % (commodity, strontCycles)) 1286 for cargo in invCache.GetInventoryFromId(session.shipid).ListCargo(): 1287 if cargo.typeID == commodity: 1288 addList.append(cargo.itemID) 1289 1290 invCache.GetInventoryFromId(id).MultiAdd(addList, session.shipid, flag=const.flagSecondaryStorage) 1291 addList = [] 1292 for fuel, amountPerCycle, resourceVolume in resourcesPerHour: 1293 sm.GetService('slash').SlashCmd('load me %d %s' % (fuel, int(fuelCycles * amountPerCycle))) 1294 for cargo in invCache.GetInventoryFromId(session.shipid).ListCargo(): 1295 if cargo.typeID == fuel and cargo.stacksize == fuelCycles * amountPerCycle: 1296 addList.append(cargo.itemID) 1297 1298 invCache.GetInventoryFromId(id).MultiAdd(addList, session.shipid, flag=const.flagNone) 1299 if blue.os.GetSimTime() <= session.nextSessionChange: 1300 ms = 1000 + 1000 * (session.nextSessionChange - blue.os.GetSimTime()) / 10000000 1301 blue.pyos.synchro.SleepSim(ms) 1302 if newShipItemID: 1303 ship = sm.StartService('gameui').GetShipAccess() 1304 if ship: 1305 sm.StartService('sessionMgr').PerformSessionChange('board', ship.Board, oldShipItemID, newShipItemID) 1306 sm.GetService('slash').SlashCmd('heal %d 0' % newShipItemID) 1307 blue.pyos.synchro.SleepSim(5000) 1308 sm.GetService('insider').HealRemove(const.groupWreck) 1309 return 'Ok' 1310 1311 def GetAmmoTypesForWeapon(self, itemID): 1312 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 1313 dogmaItem = dogmaLocation.dogmaItems[itemID] 1314 ammoInfoByTypeID = defaultdict(lambda : utillib.KeyVal(singletons=[], nonSingletons=[])) 1315 validGroupIDs = dogmaLocation.dogmaStaticMgr.GetValidChargeGroupsForType(dogmaItem.typeID) 1316 GetTypeAttribute = dogmaLocation.dogmaStaticMgr.GetTypeAttribute 1317 preferredChargeSize = GetTypeAttribute(dogmaItem.typeID, const.attributeChargeSize) 1318 legalTypes = set() 1319 for typeID in evetypes.GetTypeIDsByGroups(validGroupIDs): 1320 if preferredChargeSize is not None and GetTypeAttribute(typeID, const.attributeChargeSize) != preferredChargeSize: 1321 continue 1322 legalTypes.add(typeID) 1323 1324 return legalTypes 1325 1326 def IsLegalAmmo(self, weaponItemID, chargeTypeID): 1327 if not chargeTypeID: 1328 return True 1329 for typeID in self.GetAmmoTypesForWeapon(weaponItemID): 1330 if typeID == chargeTypeID: 1331 return True 1332 1333 return False 1334 1335 def GetRandomAmmoForWeapon(self, weaponItemID): 1336 for typeID in self.GetAmmoTypesForWeapon(weaponItemID): 1337 return typeID 1338 1339 def cmd_ammo(self, p): 1340 try: 1341 typeID = p.Parse('s')[0] 1342 except: 1343 raise UserError('SlashError', {'reason': 'Usage: /ammo [typeID]|random<br>Loads ammo of the specified type into all turrets or launchers that support this type.<br>If random is specified then all weapons are loaded with the first matching ammo found.'}) 1344 1345 if typeID == 'random': 1346 typeID = 0 1347 shipInv = sm.GetService('invCache').GetInventoryFromId(session.shipid) 1348 for row in shipInv.ListHardwareModules(): 1349 if self.IsLegalAmmo(row.itemID, typeID): 1350 shipInv.ClearCharges(row.flagID) 1351 1352 if typeID == 'clear': 1353 return 'Ok' 1354 typeID = int(typeID) 1355 blue.pyos.synchro.SleepSim(1000) 1356 cmds = [] 1357 stateMgr = sm.GetService('godma').GetStateManager() 1358 for row in shipInv.ListHardwareModules(): 1359 thisTypeID = typeID 1360 if not self.IsLegalAmmo(row.itemID, typeID): 1361 continue 1362 if not thisTypeID: 1363 thisTypeID = self.GetRandomAmmoForWeapon(row.itemID) 1364 if not thisTypeID: 1365 continue 1366 self.LogNotice('/ammo: Putting %s into %s' % (thisTypeID, row.itemID)) 1367 ma = stateMgr.GetType(row.typeID) 1368 num = int(ma.capacity / evetypes.GetVolume(thisTypeID)) 1369 if num > 0: 1370 cmds.append('/fit me %d %d flag=%d' % (thisTypeID, num, row.flagID)) 1371 1372 uthread.parallel([ (sm.GetService('slash').SlashCmd, (cmd,)) for cmd in cmds ]) 1373 return 'Ok' 1374 1375 def cmd_sessionchangetimer(self, p): 1376 oldVal = sessions.sessionChangeDelay 1377 try: 1378 secs = p.Parse('i')[0] 1379 sessions.sessionChangeDelay = min(max(5, secs), 60) * const.SEC 1380 session.nextSessionChange = None 1381 except: 1382 pass 1383 1384 prompt_player_fsd_dialog('CustomNotify', {'notify': 'Session-Change Timer was changed from %ss to <b>%ss</b>.<br>This value will be reset next time you log in' % (oldVal / const.SEC, sessions.sessionChangeDelay / const.SEC)}) 1385 return 'Ok' 1386 1387 def cmd_recustomize(self, p): 1388 if sm.GetService('cc').NoExistingCustomization(): 1389 return 1 1390 sm.GetService('gameui').GoCharacterCreationCurrentCharacter() 1391 return 1 1392 1393 def cmd_buyorders(self, p): 1394 if session.stationid is None: 1395 raise UserError('SlashError', {'reason': 'You must be in a station to execute this command.'}) 1396 qty = 1 1397 orderRange = 32767 1398 try: 1399 name, = p.Parse('s') 1400 except param.Error: 1401 try: 1402 name, qty = p.Parse('si') 1403 except param.Error: 1404 try: 1405 name, qty, orderRange = p.Parse('sii') 1406 except param.Error: 1407 return 1408 1409 typeID = self.AutoComplete(name) 1410 typeName = evetypes.GetName(typeID) 1411 minVolume = 1 1412 duration = 0 1413 useCorp = False 1414 qtyDone = 0 1415 Progress('Buying %s %s' % (qty, typeName), 'Please wait...', 0, 1) 1416 try: 1417 while qty > qtyDone: 1418 order = sm.GetService('marketQuote').GetBestAskInRange(typeID, session.stationid, orderRange) 1419 if order is None: 1420 break 1421 if order.volRemaining + qtyDone > qty: 1422 buyQty = qty - qtyDone 1423 else: 1424 buyQty = order.volRemaining 1425 sm.GetService('marketQuote').BuyStuff(session.stationid, typeID, order.price, buyQty, orderRange, minVolume, duration, useCorp) 1426 blue.pyos.synchro.SleepSim(800) 1427 qtyDone += buyQty 1428 1429 finally: 1430 if qtyDone == qty: 1431 Progress('Done buying all the %s you asked me to.' % typeName, '', 1, 1) 1432 else: 1433 Progress('Done. Did not find as many %s as you asked for.' % typeName, '', 1, 1) 1434 1435 return 'Ok' 1436 1437 def cmd_sellorders(self, p): 1438 if session.stationid is None: 1439 raise UserError('SlashError', {'reason': 'You must be in a station to execute this command.'}) 1440 qty = 1 1441 orderCount = 1 1442 priceFluct = 0 1443 try: 1444 theType, price = p.Parse('sf') 1445 except param.Error: 1446 try: 1447 theType, price, qty = p.Parse('sfi') 1448 except param.Error: 1449 try: 1450 theType, price, qty, orderCount = p.Parse('sfii') 1451 except param.Error: 1452 try: 1453 theType, price, qty, orderCount, priceFluct = p.Parse('sfiif') 1454 except param.Error: 1455 raise UserError('SlashError', {'reason': 'Syntax error: should be /sellorders type price [qty] [ordercount] [price fluctuation in %]'}) 1456 1457 duration = 14 1458 useCorp = False 1459 officeID = None 1460 expectedBrokersFee = None 1461 if priceFluct != 0: 1462 p = priceFluct / 100.0 1463 minPriceCents = int(max(price - price * p, 1) * 100) 1464 maxPriceCents = int((price + price * p) * 100) 1465 Progress('Creating %s Market order(s)' % orderCount, 'Please wait...', 0, 1) 1466 try: 1467 validatedItems = [] 1468 itemID = self.cmd_createitem(param.ParamObject(str(theType) + ' ' + unicode(orderCount * qty))) 1469 blue.pyos.synchro.SleepSim(1200) 1470 typeID = sm.GetService('invCache').FetchItem(itemID, session.stationid).typeID 1471 for x in xrange(orderCount): 1472 if priceFluct == 0: 1473 orderPrice = price 1474 else: 1475 orderPrice = random.randint(minPriceCents, maxPriceCents) / 100.0 1476 validatedItem = utillib.KeyVal(stationID=int(session.stationid), typeID=int(typeID), itemID=itemID, price=orderPrice, quantity=int(qty), officeID=officeID) 1477 sm.GetService('marketQuote').SellMulti([validatedItem], useCorp, duration, expectedBrokersFee) 1478 1479 finally: 1480 Progress('Done creating market orders.', '', 1, 1) 1481 1482 return 'Ok' 1483 1484 def cmd_cancelallorders(self, p): 1485 orders = sm.GetService('marketQuote').GetMyOrders() 1486 if not orders: 1487 raise UserError('SlashError', {'reason': 'No market orders found.'}) 1488 for order in orders: 1489 sm.GetService('marketQuote').CancelOrder(order.orderID, order.regionID) 1490 1491 return 'Ok' 1492 1493 def cmd_reimbursebounties(self, p): 1494 sm.GetService('bountySvc').GMReimburseBounties() 1495 return 'Ok' 1496 1497 def cmd_clearbountycache(self, p): 1498 sm.GetService('bountySvc').GMClearBountyCache() 1499 return 'Ok' 1500 1501 def cmd_killright(self, p): 1502 sm.RemoteSvc('slash').SlashCmd('/killright %s' % p.line) 1503 sm.GetService('bountySvc').ClearAllKillRightData() 1504 return 'Ok' 1505 1506 def cmd_newscanner(self, p): 1507 cmd = p.Parse('s') 1508 if 'start' in cmd: 1509 sm.GetService('sensorSuite') 1510 elif 'stop' in cmd: 1511 sm.StopService('sensorSuite') 1512 elif 'show' in cmd: 1513 if session.solarsystemid is not None: 1514 sensorSuite = sm.GetService('sensorSuite') 1515 sensorSuite.EnableSensorOverlay() 1516 elif 'hide' in cmd: 1517 if session.solarsystemid is not None: 1518 sensorSuite = sm.GetService('sensorSuite') 1519 sensorSuite.EnableSensorOverlay() 1520 elif 'register' in cmd: 1521 if session.solarsystemid is not None: 1522 sensorSuite = sm.GetService('sensorSuite') 1523 sm.RemoteSvc('scanMgr').SignalTrackerRegister() 1524 elif 'scan' in cmd: 1525 if session.solarsystemid is not None: 1526 sensorSuite = sm.GetService('sensorSuite') 1527 sensorSuite.DisableSensorOverlay() 1528 sensorSuite.systemReadyTime = blue.os.GetSimTime() - const.SEC * 2 1529 sensorSuite.StartSensorSweep() 1530 return 'Ok' 1531 1532 def cmd_dplay(self, p): 1533 coords = None 1534 try: 1535 dungeonID, godmode, x, y, z = p.Parse('i?i?f?f?f') 1536 coords = (x, y, z) 1537 if None in coords: 1538 coords = None 1539 except param.Error: 1540 raise Error('Use /dplay DUNGEONID [godmode:0|1]\n(godmode defaults to 1)') 1541 1542 dungeonID = int(dungeonID) 1543 if godmode is None: 1544 godmode = 1 1545 self.leveleditor = player = eveMoniker.Moniker('keeper', session.userid) 1546 player.PlayDungeon(dungeonID, godmode=godmode, coords=coords) 1547 return 'Ok' 1548 1549 def cmd_dgoto(self, p): 1550 roomID = int(p.Parse('i')[0]) 1551 self.leveleditor = player = eveMoniker.Moniker('keeper', session.userid) 1552 player.GotoRoom(roomID) 1553 return 'Ok' 1554 1555 def cmd_highlight(self, p): 1556 try: 1557 cmd_option, _ = p.Parse('s?r') 1558 except: 1559 self._cmd_highlightError() 1560 1561 if cmd_option == 'ui': 1562 return self._cmd_highlightui(p) 1563 if cmd_option == 'menu': 1564 return self._cmd_highlightmenu(p) 1565 if cmd_option == 'object': 1566 return self._cmd_highlightobject(p) 1567 if cmd_option == 'item': 1568 return self._cmd_highlightitem(p) 1569 if cmd_option == 'entitygroup': 1570 return self._cmd_highlightentitygroup(p) 1571 if cmd_option == 'type': 1572 return self._cmd_highlighttype(p) 1573 if cmd_option == 'group': 1574 return self._cmd_highlightgroup(p) 1575 if cmd_option == 'spaceobject': 1576 return self._cmd_highlightspaceobject(p) 1577 if cmd_option == 'clear': 1578 return self._cmd_highlightclear(p) 1579 self._cmd_highlightError() 1580 1581 def _cmd_highlightError(self): 1582 raise UserError('SlashError', {'reason': 'Available options:\n/highlight ui\n/highlight menu\n/highlight object\n/highlight item\n/highlight entitygroup\n/highlight type\n/highlight group\n/highlight spaceobject\n/highlight clear ui\n/highlight clear menu\n/highlight clear space\n/highlight clear all'}) 1583 1584 def _cmd_highlightui(self, p): 1585 relativePositionString = None 1586 style = None 1587 try: 1588 _, uiElementName, title, message, secondsTilFadeout, relativePositionString, style = p.Parse('ssssiss') 1589 except: 1590 try: 1591 _, uiElementName, title, message, secondsTilFadeout, relativePositionString = p.Parse('ssssis') 1592 except: 1593 try: 1594 _, uiElementName, title, message, secondsTilFadeout = p.Parse('ssssi') 1595 relativePositionString = None 1596 except: 1597 try: 1598 _, uiElementName, title, message, relativePositionString = p.Parse('sssss') 1599 secondsTilFadeout = None 1600 except: 1601 try: 1602 _, uiElementName, title, message = p.Parse('ssss') 1603 relativePositionString = None 1604 secondsTilFadeout = None 1605 except: 1606 raise UserError('SlashError', {'reason': 'Usage: /highlight ui uiElementName title message [secondsTilFadeout] [relativePosition] [style]'}) 1607 1608 if relativePositionString and relativePositionString not in DIRECTION_STRING_TO_ID: 1609 raise UserError('SlashError', {'reason': 'Available relative positions for UI highlight: left, up, right, down'}) 1610 if style and style not in UI_CLASS_BY_NAME: 1611 raise UserError('SlashError', {'reason': 'Available styles for UI highlight: AuraBlue, RetroBlack'}) 1612 sm.GetService('uiHighlightingService').highlight_ui_element_by_name(ui_element_name=uiElementName, message=message, fadeout_seconds=secondsTilFadeout, title=title, default_direction=DIRECTION_STRING_TO_ID[relativePositionString] if relativePositionString else None, ui_class=style) 1613 return 'Ok' 1614 1615 def _cmd_highlightmenu(self, p): 1616 try: 1617 _, menu_name, type_id = p.Parse('ssi') 1618 except: 1619 try: 1620 _, menu_name = p.Parse('ss') 1621 type_id = None 1622 except: 1623 raise UserError('SlashError', {'reason': 'Usage: /highlight menu menuName'}) 1624 1625 type_ids = [type_id] if type_id else [] 1626 sm.GetService('uiHighlightingService').highlight_menu_by_name(menu_name, type_ids) 1627 return 'Ok' 1628 1629 def _cmd_highlightobject(self, p): 1630 try: 1631 __, objectID, message, hint, secondsTilFadeout = p.Parse('sissi') 1632 sm.GetService('uiHighlightingService').highlight_space_object_by_dungeon_object_id(objectID, message, hint, secondsTilFadeout) 1633 except: 1634 try: 1635 _, objectID, message, hint = p.Parse('siss') 1636 sm.GetService('uiHighlightingService').highlight_space_object_by_dungeon_object_id(objectID, message, hint) 1637 except: 1638 raise UserError('SlashError', {'reason': 'Usage: /highlight object objectID message, hint, [secondsTilFadeout]'}) 1639 1640 return 'Ok' 1641 1642 def _cmd_highlightitem(self, p): 1643 try: 1644 __, itemID, message, hint, secondsTilFadeout = p.Parse('sissi') 1645 sm.GetService('uiHighlightingService').highlight_space_object_by_item_id(itemID, message, hint, secondsTilFadeout) 1646 except: 1647 try: 1648 _, itemID, message, hint = p.Parse('siss') 1649 sm.GetService('uiHighlightingService').highlight_space_object_by_item_id(itemID, message, hint) 1650 except: 1651 raise UserError('SlashError', {'reason': 'Usage: /highlight item itemID message, hint, [secondsTilFadeout]'}) 1652 1653 return 'Ok' 1654 1655 def _cmd_highlightentitygroup(self, p): 1656 try: 1657 __, entityGroupID, message, hint, secondsTilFadeout = p.Parse('sissi') 1658 sm.GetService('uiHighlightingService').highlight_space_object_by_dungeon_entity_group_id(entityGroupID, message, hint, secondsTilFadeout) 1659 except: 1660 try: 1661 _, entityGroupID, message, hint = p.Parse('siss') 1662 sm.GetService('uiHighlightingService').highlight_space_object_by_dungeon_entity_group_id(entityGroupID, message, hint) 1663 except: 1664 raise UserError('SlashError', {'reason': 'Usage: /highlight entitygroup entityGroupID message, hint, [secondsTilFadeout]'}) 1665 1666 return 'Ok' 1667 1668 def _cmd_highlighttype(self, p): 1669 try: 1670 __, typeID, message, hint, secondsTilFadeout = p.Parse('sissi') 1671 sm.GetService('uiHighlightingService').highlight_space_object_by_type(typeID, message, hint, secondsTilFadeout) 1672 except: 1673 try: 1674 _, typeID, message, hint = p.Parse('siss') 1675 sm.GetService('uiHighlightingService').highlight_space_object_by_type(typeID, message, hint) 1676 except: 1677 raise UserError('SlashError', {'reason': 'Usage: /highlight type typeID message, hint, [secondsTilFadeout]'}) 1678 1679 return 'Ok' 1680 1681 def _cmd_highlightgroup(self, p): 1682 try: 1683 _, groupID, message, hint, secondsTilFadeout = p.Parse('sissi') 1684 sm.GetService('uiHighlightingService').highlight_space_object_by_group(groupID, message, hint, secondsTilFadeout) 1685 except: 1686 try: 1687 _, groupID, message, hint = p.Parse('siss') 1688 sm.GetService('uiHighlightingService').highlight_space_object_by_group(groupID, message, hint) 1689 except: 1690 raise UserError('SlashError', {'reason': 'Usage: /highlight group groupID message, hint, [secondsTilFadeout]'}) 1691 1692 return 'Ok' 1693 1694 def _cmd_highlightspaceobject(self, p): 1695 try: 1696 _, highlight_id = p.Parse('si') 1697 except: 1698 raise UserError('SlashError', {'reason': 'Usage: /highlight spaceobject highlight_id'}) 1699 1700 sm.GetService('uiHighlightingService').highlight_space_object(highlight_id) 1701 return 'Ok' 1702 1703 def _cmd_highlightclear(self, p): 1704 cmd_option, clear_option = p.Parse('ss') 1705 if clear_option == 'ui': 1706 return self._cmd_highlightclearui(p) 1707 if clear_option == 'menu': 1708 return self._cmd_highlightclearmenu(p) 1709 if clear_option == 'space': 1710 return self._cmd_highlightclearspace(p) 1711 if clear_option == 'all': 1712 return self._cmd_highlightclearall(p) 1713 self._cmd_highlightError() 1714 1715 def _cmd_highlightclearui(self, p): 1716 sm.GetService('uiHighlightingService').clear_ui_element_highlighting() 1717 return 'Ok' 1718 1719 def _cmd_highlightclearspace(self, p): 1720 sm.GetService('uiHighlightingService').clear_space_object_highlighting() 1721 return 'Ok' 1722 1723 def _cmd_highlightclearmenu(self, p): 1724 sm.GetService('uiHighlightingService').clear_menu_highlighting() 1725 return 'Ok' 1726 1727 def _cmd_highlightclearall(self, p): 1728 sm.GetService('uiHighlightingService').clear_all_highlighting() 1729 return 'Ok' 1730 1731 def cmd_uiblink(self, p): 1732 try: 1733 cmd_option, _ = p.Parse('s?r') 1734 except: 1735 self._cmd_uiBlinkError() 1736 1737 if cmd_option == 'start': 1738 return self._cmd_uiblinkBlink(p) 1739 if cmd_option == 'stop': 1740 return self._cmd_uiblinkClear(p) 1741 self._cmd_uiBlinkError() 1742 1743 def _cmd_uiBlinkError(self): 1744 raise UserError('SlashError', {'reason': 'Available options:\n/uiblink start {path}\n/uiblink stop {path}\n/uiblink stop all\n'}) 1745 1746 def _cmd_uiblinkBlink(self, p): 1747 try: 1748 cmd_option, ui_element_path = p.Parse('ss') 1749 except Exception: 1750 self._cmd_uiBlinkError() 1751 else: 1752 uiblinker.get_service().start_blinker_by_path(ui_element_path) 1753 return 'OK' 1754 1755 def _cmd_uiblinkClear(self, p): 1756 try: 1757 cmd_option, ui_element_path = p.Parse('ss') 1758 except Exception: 1759 self._cmd_uiBlinkError() 1760 else: 1761 if 'all' == ui_element_path: 1762 uiblinker.get_service().stop_all_blinkers() 1763 else: 1764 uiblinker.get_service().stop_blinker_by_path(ui_element_path) 1765 1766 return 'OK' 1767 1768 def cmd_networth(self, p): 1769 try: 1770 cmd_option, _ = p.Parse('s?r') 1771 except: 1772 self._cmd_networthError() 1773 1774 resultString = None 1775 if cmd_option == 'total': 1776 resultString = self._cmd_networthtotal() 1777 elif cmd_option == 'wallet': 1778 resultString = self._cmd_networthwallet() 1779 elif cmd_option == 'assets': 1780 resultString = self._cmd_networthassets() 1781 elif cmd_option == 'contract': 1782 resultString = self._cmd_networthcontract() 1783 elif cmd_option == 'market': 1784 resultString = self._cmd_networthmarket() 1785 elif cmd_option == 'plex': 1786 resultString = self._cmd_networthplex() 1787 if resultString: 1788 self._cmd_networthResults(resultString) 1789 return 'Ok' 1790 self._cmd_networthError() 1791 1792 def _cmd_networthError(self): 1793 raise UserError('SlashError', {'reason': 'Available options:\n/networth total\n/networth wallet\n/networth assets\n/networth plex\n/networth contract\n/networth market\n'}) 1794 1795 def _cmd_networthResults(self, string): 1796 Message('Net Worth Results', string) 1797 1798 def _cmd_networthtotal(self): 1799 wallet = self._GetNetWorthWallet() 1800 iskInContractEscrow, itemsInContractEscrow = self._GetNetWorthContracts() 1801 iskInMarketEscrow, itemsInMarketEscrow = self._GetNetWorthMarket() 1802 assets, assetsPlex = self._GetNetWorthAssets() 1803 accountPlex = self._GetNetWorthAccountPlex() 1804 combinedAssets = itemsInContractEscrow + itemsInMarketEscrow + assets 1805 totalPlex = assetsPlex + accountPlex 1806 total = wallet + iskInMarketEscrow + iskInContractEscrow + combinedAssets + totalPlex 1807 return '<b>Total Net Worth:</b> {:0,.0f} ISK:<br/><b> - Wallet:</b> {:0,.0f} ISK<br/><b> - Combined assets:</b> {:0,.0f} ISK<br/><b> - PLEX:</b> {:0,.0f} ISK<br/><b> - Contracts:</b> {:0,.0f} ISK<br/><b> - Market orders:</b> {:0,.0f} ISK'.format(total, wallet, combinedAssets, totalPlex, iskInContractEscrow, iskInMarketEscrow) 1808 1809 def _cmd_networthwallet(self): 1810 wallet = self._GetNetWorthWallet() 1811 return '<b>Wallet Balance:</b> {:0,.0f} ISK'.format(wallet) 1812 1813 def _cmd_networthassets(self): 1814 _, itemsInContractEscrow = self._GetNetWorthContracts() 1815 _, itemsInMarketEscrow = self._GetNetWorthMarket() 1816 assets, _ = self._GetNetWorthAssets() 1817 total = itemsInContractEscrow + itemsInMarketEscrow + assets 1818 return '<b>Combined Asset Net Worth:</b> {:0,.0f} ISK:<br/><b> - Assets:</b> {:0,.0f} ISK<br/><b> - Contracts:</b> {:0,.0f} ISK<br/><b> - Market orders:</b> {:0,.0f} ISK'.format(total, assets, itemsInContractEscrow, itemsInMarketEscrow) 1819 1820 def _cmd_networthcontract(self): 1821 iskInContractEscrow, _ = self._GetNetWorthContracts() 1822 return '<b>Contract Escrow:</b> {:0,.0f} ISK'.format(iskInContractEscrow) 1823 1824 def _cmd_networthmarket(self): 1825 iskInMarketEscrow, _ = self._GetNetWorthMarket() 1826 return '<b>Market Escrow:</b> {:0,.0f} ISK'.format(iskInMarketEscrow) 1827 1828 def _cmd_networthplex(self): 1829 _, assetsPlex = self._GetNetWorthAssets() 1830 accountPlex = self._GetNetWorthAccountPlex() 1831 totalPlex = assetsPlex + accountPlex 1832 return '<b>PLEX Estimated Value:</b> {:0,.0f} ISK<br/><b>- PLEX in assets:</b> {:0,.0f} ISK<br/><b>- PLEX in Plex Vault:</b> {:0,.0f} ISK'.format(totalPlex, assetsPlex, accountPlex) 1833 1834 def _GetNetWorthWallet(self): 1835 return sm.GetService('wallet').GetWealth() 1836 1837 def _GetNetWorthAssets(self): 1838 invContainer = sm.GetService('invCache').GetInventory(const.containerGlobal) 1839 assets, assetsPlex = invContainer.GetAssetWorth() 1840 return (assets, assetsPlex) 1841 1842 def _GetNetWorthMarket(self): 1843 iskInMarketEscrow, itemsInMarketEscrow = sm.GetService('marketQuote').GetMyMarketEscrow() 1844 return (iskInMarketEscrow, itemsInMarketEscrow) 1845 1846 def _GetNetWorthContracts(self): 1847 iskInContractEscrow, itemsInContractEscrow = sm.GetService('contracts').GetMyContractEscrow() 1848 return (iskInContractEscrow, itemsInContractEscrow) 1849 1850 def _GetNetWorthAccountPlex(self): 1851 plex_amount = plex_api.get_repository().get_balance() or 0.0 1852 plex_price = GetAveragePrice(typePlex) or 0.0 1853 plex_worth = plex_amount * plex_price 1854 return plex_worth 1855 1856 def cmd_asteroid(self, p): 1857 try: 1858 cmd_option, _ = p.Parse('s?r') 1859 except: 1860 self._cmd_asteroidError() 1861 1862 if cmd_option == 'highlight': 1863 return self._cmd_asteroid_highlight(p) 1864 if cmd_option == 'clear': 1865 return self._cmd_asteroid_clear_highlight(p) 1866 if cmd_option == 'rewards': 1867 return self._cmd_asteroid_list_rewards() 1868 self._cmd_asteroidError() 1869 1870 def _cmd_asteroidError(self): 1871 raise UserError('SlashError', {'reason': 'Available options:\n/asteroid rewards\n/asteroid highlight {asteroidID}\n/asteroid clear {asteroidID}'}) 1872 1873 def _cmd_asteroid_list_rewards(self): 1874 sm.RemoteSvc('slash').SlashCmd('/asteroid rewards') 1875 return 'Ok' 1876 1877 def _cmd_asteroid_highlight(self, p): 1878 try: 1879 __, asteroidID = p.Parse('si') 1880 sm.GetService('michelle').OnAsteroidRevealed(asteroidID) 1881 except: 1882 raise UserError('SlashError', {'reason': 'Usage: /asteroid highlight {asteroidID}'}) 1883 1884 return 'Ok' 1885 1886 def _cmd_asteroid_clear_highlight(self, p): 1887 try: 1888 __, asteroidID = p.Parse('si') 1889 sm.GetService('michelle').OnAsteroidTerminated(asteroidID) 1890 except: 1891 raise UserError('SlashError', {'reason': 'Usage: /asteroid clear {asteroidID}'}) 1892 1893 return 'Ok' 1894 1895 def cmd_intro(self, p): 1896 try: 1897 cmd_option, _ = p.Parse('s?r') 1898 except: 1899 self._cmd_introError() 1900 return 1901 1902 if cmd_option in ('start', 'stop', 'terminate'): 1903 return 1904 self._cmd_introError() 1905 1906 def _cmd_introError(self): 1907 raise UserError('SlashError', {'reason': 'Available options:\n/intro start\n/intro stop\n/intro terminate\n/intro free'}) 1908 1909 def MatchTypes(self, name, allowedCategories = None, allowedGroups = None, smart = True): 1910 name = name.strip('"') 1911 self._PopulateTypeDict() 1912 1913 def _filter(typeID): 1914 if allowedCategories: 1915 if evetypes.GetCategoryID(typeID) in allowedCategories: 1916 return True 1917 if allowedGroups: 1918 if evetypes.GetGroupID(typeID) in allowedGroups: 1919 return True 1920 elif allowedGroups: 1921 if evetypes.GetGroupID(typeID) in allowedGroups: 1922 return True 1923 else: 1924 return True 1925 return False 1926 1927 if smart and name.lower() in self.typeIDsByName: 1928 typeIDs = self.typeIDsByName[name.lower()] 1929 return [ (evetypes.GetName(typeID), typeID) for typeID in typeIDs ] 1930 if name.isdigit(): 1931 typeName = evetypes.GetNameOrNone(int(name)) 1932 if typeName: 1933 return [(typeName, int(name))] 1934 else: 1935 name = name.lower().strip('"') 1936 if len(name) < 3: 1937 raise UserError('SlashError', {'reason': 'Autocompletion requires 3 or more characters'}) 1938 matches = [] 1939 for typeName, typeIDs in self.typeIDsByName.iteritems(): 1940 if name in typeName: 1941 for typeID in typeIDs: 1942 if _filter(typeID): 1943 matches.append((evetypes.GetName(typeID), typeID)) 1944 1945 return matches 1946 1947 def _PopulateTypeDict(self): 1948 if self.typeIDsByName is not None: 1949 return 1950 d = defaultdict(list) 1951 noOfExceptions = 0 1952 optic_locale = localization.const.LOCALE_SHORT_CHINESE 1953 for typeID in evetypes.Iterate(): 1954 blue.pyos.BeNice() 1955 try: 1956 if boot.region == 'optic': 1957 if evetypes.GetNameID(typeID) is not None: 1958 d[evetypes.GetName(typeID, optic_locale).lower()].append(typeID) 1959 else: 1960 englishName = evetypes.GetEnglishName(typeID) 1961 if englishName is not None: 1962 d[englishName.lower()].append(typeID) 1963 except Exception: 1964 if noOfExceptions == 0: 1965 log.LogException('Unexpected Exception in _PopulateTypeDict') 1966 noOfExceptions += 1 1967 sys.exc_clear() 1968 1969 if noOfExceptions > 0: 1970 self.LogError('_PopulateTypeDict failed', noOfExceptions, 'times getting the typeName') 1971 self.typeIDsByName = d 1972 1973 def AutoComplete(self, name, allowedCategories = None, allowedGroups = None): 1974 matches = self.MatchTypes(name, allowedCategories, allowedGroups) 1975 if not matches: 1976 return None 1977 if len(matches) == 1: 1978 ret = matches[0] 1979 else: 1980 matches.sort() 1981 ret = uix.ListWnd(matches, listtype='generic', caption='AutoComplete: %d types found' % len(matches)) 1982 if not ret: 1983 raise Error('Cancelled') 1984 return ret[1] 1985 1986 def GetChannel(self): 1987 log.LogTraceback('PAT: SlashService.GetChannel called') 1988 f = sys._getframe().f_back 1989 while f: 1990 logger.debug('PAT: f=%s', f) 1991 loc = f.f_locals 1992 logger.debug('PAT: loc=%s', loc) 1993 if 'self' in loc: 1994 target = loc['self'] 1995 logger.debug('PAT: target=%s', target) 1996 from packages.xmppchatclient.xmppchatwindow import XmppChatWindow 1997 if isinstance(target, XmppChatWindow): 1998 logger.debug('PAT: Found XmppChatWindow target instance: %s', target) 1999 return target 2000 f = f.f_back 2001 2002 raise Error('This function can only be used in a chat channel') 2003 2004 def GetChannelUsers(self): 2005 c = self.GetChannel() 2006 return [ each.charID for each in c.userlist.sr.nodes ] 2007 2008 def ReportSlashCommandUsage(self, text): 2009 splitText = text.split(' ', 1) 2010 commandText = splitText[0].lower() 2011 argumentText = splitText[1] if len(splitText) > 1 else '' 2012 self._slashEventPublisher.command_used(commandText, argumentText) 2013 2014 2015 exports = {'slash.Error': Error}