Advertisement
MertcanGokgoz

Untitled

Jun 20th, 2021
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.14 KB | None | 0 0
  1. from phBot import *
  2. from threading import Timer
  3. import phBotChat
  4. import QtBind
  5. import struct
  6. import random
  7. import json
  8. import os
  9.  
  10. pName = 'xControl'
  11. pVersion = '1.8.2'
  12. pUrl = 'https://raw.githubusercontent.com/JellyBitz/phBot-xPlugins/master/xControl.py'
  13.  
  14. # ______________________________ Initializing ______________________________ #
  15.  
  16. # Globals
  17. inGame = None
  18. followActivated = False
  19. followPlayer = ''
  20. followDistance = 0
  21.  
  22. # Graphic user interface
  23. gui = QtBind.init(__name__,pName)
  24. QtBind.createLabel(gui,'Control your party using in-game chat. Leader writes commands and your character will follow it.',11,11)
  25.  
  26. QtBind.createLabel(gui,'< COMMAND (uppercased) #Variable (required) #Variable? (optional) >',11,30)
  27. QtBind.createLabel(gui,'- START : Start bot\n- STOP : Stop bot\n- TRACE #Player? : Start trace to leader or another player\n- NOTRACE : Stop trace\n- RETURN : Use some "Return Scroll" from your inventory\n- TP #A #B : Use teleport from location A to B\n- RECALL #Town : Set recall on city portal\n- ZERK : Use berserker mode if is available\n- GETOUT : Left party\n- MOVEON #Radius? : Set a random movement\n- MOUNT #PetType? : Mount horse by default\n- DISMOUNT #PetType? : Dismount horse by default\n- SETPOS #PosX? #PosY? #Region? #PosZ? : Set training position\n- SETRADIUS #Radius? : Set training radius\n- SETSCRIPT #Path? : Change script path for training area\n- SETAREA #Name : Changes training area by config name\n- PROFILE #Name? : Loads a profile by his name\n- DC : Disconnect from game',15,45)
  28. QtBind.createLabel(gui,'- INJECT #Opcode #Encrypted? #Data? : Inject packet\n- CHAT #Type #Message : Send any message type\n- FOLLOW #Player? #Distance? : Trace a party player using distance\n- NOFOLLOW : Stop following\n- JUMP : Generate knockback visual effect\n- SIT : Sit or Stand up, depends\n- CAPE #Type? : Use PVP Cape\n- EQUIP #ItemName : Equips an item from inventory\n- UNEQUIP #ItemName : Unequips item from character\n- REVERSE #Type #Name?\n- GETPOS : Gets current position',345,80)
  29.  
  30. tbxLeaders = QtBind.createLineEdit(gui,"",525,11,110,20)
  31. lstLeaders = QtBind.createList(gui,525,32,110,38)
  32. btnAddLeader = QtBind.createButton(gui,'btnAddLeader_clicked'," Add ",635,10)
  33. btnRemLeader = QtBind.createButton(gui,'btnRemLeader_clicked'," Remove ",635,32)
  34.  
  35. # ______________________________ Methods ______________________________ #
  36.  
  37. # Return xControl folder path
  38. def getPath():
  39. return get_config_dir()+pName+"\\"
  40.  
  41. # Return character configs path (JSON)
  42. def getConfig():
  43. return getPath()+inGame['server'] + "_" + inGame['name'] + ".json"
  44.  
  45. # Check if character is ingame
  46. def isJoined():
  47. global inGame
  48. inGame = get_character_data()
  49. if not (inGame and "name" in inGame and inGame["name"]):
  50. inGame = None
  51. return inGame
  52.  
  53. # Load default configs
  54. def loadDefaultConfig():
  55. # Clear data
  56. QtBind.clear(gui,lstLeaders)
  57.  
  58. # Loads all config previously saved
  59. def loadConfigs():
  60. loadDefaultConfig()
  61. if isJoined():
  62. # Check config exists to load
  63. if os.path.exists(getConfig()):
  64. data = {}
  65. with open(getConfig(),"r") as f:
  66. data = json.load(f)
  67. if "Leaders" in data:
  68. for nickname in data["Leaders"]:
  69. QtBind.append(gui,lstLeaders,nickname)
  70.  
  71. # Add leader to the list
  72. def btnAddLeader_clicked():
  73. if inGame:
  74. player = QtBind.text(gui,tbxLeaders)
  75. # Player nickname it's not empty
  76. if player and not lstLeaders_exist(player):
  77. # Init dictionary
  78. data = {}
  79. # Load config if exist
  80. if os.path.exists(getConfig()):
  81. with open(getConfig(), 'r') as f:
  82. data = json.load(f)
  83. # Add new leader
  84. if not "Leaders" in data:
  85. data['Leaders'] = []
  86. data['Leaders'].append(player)
  87. # Replace configs
  88. with open(getConfig(),"w") as f:
  89. f.write(json.dumps(data, indent=4, sort_keys=True))
  90. QtBind.append(gui,lstLeaders,player)
  91. QtBind.setText(gui, tbxLeaders,"")
  92. log('Plugin: Leader added ['+player+']')
  93.  
  94. # Remove leader selected from list
  95. def btnRemLeader_clicked():
  96. if inGame:
  97. selectedItem = QtBind.text(gui,lstLeaders)
  98. if selectedItem:
  99. if os.path.exists(getConfig()):
  100. data = {"Leaders":[]}
  101. with open(getConfig(), 'r') as f:
  102. data = json.load(f)
  103. try:
  104. # remove leader nickname from file if exists
  105. data["Leaders"].remove(selectedItem)
  106. with open(getConfig(),"w") as f:
  107. f.write(json.dumps(data, indent=4, sort_keys=True))
  108. except:
  109. pass # just ignore file if doesn't exist
  110. QtBind.remove(gui,lstLeaders,selectedItem)
  111. log('Plugin: Leader removed ['+selectedItem+']')
  112.  
  113. # Return True if nickname exist at the leader list
  114. def lstLeaders_exist(nickname):
  115. nickname = nickname.lower()
  116. players = QtBind.getItems(gui,lstLeaders)
  117. for i in range(len(players)):
  118. if players[i].lower() == nickname:
  119. return True
  120. return False
  121.  
  122. # Inject teleport packet, using the source and destination name
  123. def inject_teleport(source,destination):
  124. t = get_teleport_data(source, destination)
  125. if t:
  126. npcs = get_npcs()
  127. for key, npc in npcs.items():
  128. if npc['name'] == source or npc['servername'] == source:
  129. log("Plugin: Selecting teleporter ["+source+"]")
  130. # Teleport found, select it
  131. inject_joymax(0x7045, struct.pack('<I', key), False)
  132. # Start a timer to teleport in 2.0 seconds
  133. Timer(2.0, inject_joymax, (0x705A,struct.pack('<IBI', key, 2, t[1]),False)).start()
  134. Timer(2.0, log, ("Plugin: Teleporting to ["+destination+"]")).start()
  135. return
  136. log('Plugin: NPC not found. Wrong NPC name or servername')
  137. else:
  138. log('Plugin: Teleport data not found. Wrong teleport name or servername')
  139.  
  140. # Send message, Ex. "All Hello World!" or "private JellyBitz Hi!"
  141. def handleChatCommand(msg):
  142. # Try to split message
  143. args = msg.split(' ',1)
  144. # Check if the format is correct and is not empty
  145. if len(args) != 2 or not args[0] or not args[1]:
  146. return
  147. # Split correctly the message
  148. t = args[0].lower()
  149. if t == 'private' or t == 'note':
  150. # then check message is not empty
  151. argsExtra = args[1].split(' ',1)
  152. if len(argsExtra) != 2 or not argsExtra[0] or not argsExtra[1]:
  153. return
  154. args.pop(1)
  155. args += argsExtra
  156. # Check message type
  157. sent = False
  158. if t == "all":
  159. sent = phBotChat.All(args[1])
  160. elif t == "private":
  161. sent = phBotChat.Private(args[1],args[2])
  162. elif t == "party":
  163. sent = phBotChat.Party(args[1])
  164. elif t == "guild":
  165. sent = phBotChat.Guild(args[1])
  166. elif t == "union":
  167. sent = phBotChat.Union(args[1])
  168. elif t == "note":
  169. sent = phBotChat.Note(args[1],args[2])
  170. elif t == "stall":
  171. sent = phBotChat.Stall(args[1])
  172. elif t == "global":
  173. sent = phBotChat.Global(args[1])
  174. if sent:
  175. log('Plugin: Message "'+t+'" sent successfully!')
  176.  
  177. # Move to a random position from the actual position using a maximum radius
  178. def randomMovement(radiusMax=10):
  179. # Generating a random new point
  180. pX = random.uniform(-radiusMax,radiusMax)
  181. pY = random.uniform(-radiusMax,radiusMax)
  182. # Mixing with the actual position
  183. p = get_position()
  184. pX = pX + p["x"]
  185. pY = pY + p["y"]
  186. # Moving to new position
  187. move_to(pX,pY,p["z"])
  188. log("Plugin: Random movement to (X:%.1f,Y:%.1f)"%(pX,pY))
  189.  
  190. # Follow a player using distance. Return success
  191. def start_follow(player,distance):
  192. if party_player(player):
  193. global followActivated,followPlayer,followDistance
  194. followPlayer = player
  195. followDistance = distance
  196. followActivated = True
  197. return True
  198. return False
  199.  
  200. # Return True if the player is in the party
  201. def party_player(player):
  202. players = get_party()
  203. if players:
  204. for p in players:
  205. if players[p]['name'] == player:
  206. return True
  207. return False
  208.  
  209. # Return point [X,Y] if player is in the party and near, otherwise return None
  210. def near_party_player(player):
  211. players = get_party()
  212. if players:
  213. for p in players:
  214. if players[p]['name'] == player and players[p]['player_id'] > 0:
  215. return players[p]
  216. return None
  217.  
  218. # Calc the distance from point A to B
  219. def GetDistance(ax,ay,bx,by):
  220. return ((bx-ax)**2 + (by-ay)**2)**0.5
  221.  
  222. # Stop follow player
  223. def stop_follow():
  224. global followActivated,followPlayer,followDistance
  225. result = followActivated
  226. # stop
  227. followActivated = False
  228. followPlayer = ""
  229. followDistance = 0
  230. return result
  231.  
  232. # Try to summon a vehicle
  233. def MountHorse():
  234. items = get_inventory()['items']
  235. for slot, item in enumerate(items):
  236. if item:
  237. sn = item['servername']
  238. # Search some kind vehicle by servername
  239. if '_C_' in sn:
  240. packet = struct.pack('B',slot)
  241. packet += struct.pack('H',4588 + (1 if sn.endswith('_SCROLL') else 0)) # Silk scroll
  242. inject_joymax(0x704C,packet,True)
  243. return True
  244. log('Plugin: Horse not found at your inventory')
  245. return False
  246.  
  247. # Try to mount pet by type, return success
  248. def MountPet(petType):
  249. # just in case
  250. if petType == 'pick':
  251. return False
  252. elif petType == 'horse':
  253. return MountHorse()
  254. # get all summoned pets
  255. pets = get_pets()
  256. if pets:
  257. for uid,pet in pets.items():
  258. if pet['type'] == petType:
  259. p = b'\x01' # mount flag
  260. p += struct.pack('I',uid)
  261. inject_joymax(0x70CB,p, False)
  262. return True
  263. return False
  264.  
  265. # Try to dismount pet by type, return success
  266. def DismountPet(petType):
  267. petType = petType.lower()
  268. # just in case
  269. if petType == 'pick':
  270. return False
  271. # get all summoned pets
  272. pets = get_pets()
  273. if pets:
  274. for uid,pet in pets.items():
  275. if pet['type'] == petType:
  276. p = b'\x00'
  277. p += struct.pack('I',uid)
  278. inject_joymax(0x70CB,p, False)
  279. return True
  280. return False
  281.  
  282. # Gets the NPC unique ID if the specified name is found near
  283. def GetNPCUniqueID(name):
  284. NPCs = get_npcs()
  285. if NPCs:
  286. name = name.lower()
  287. for UniqueID, NPC in NPCs.items():
  288. NPCName = NPC['name'].lower()
  289. if name == NPCName:
  290. return UniqueID
  291. return 0
  292.  
  293. # Search an item by name or servername through lambda expression and return his information
  294. def GetItemByExpression(_lambda,start=0,end=0):
  295. inventory = get_inventory()
  296. items = inventory['items']
  297. if end == 0:
  298. end = inventory['size']
  299. # check items between intervals
  300. for slot, item in enumerate(items):
  301. if start <= slot and slot <= end:
  302. if item:
  303. # Search by lambda
  304. if _lambda(item['name'],item['servername']):
  305. # Save slot location
  306. item['slot'] = slot
  307. return item
  308. return None
  309.  
  310. # Finds an empty slot, returns -1 if inventory is full
  311. def GetEmptySlot():
  312. items = get_inventory()['items']
  313. # check the first empty
  314. for slot, item in enumerate(items):
  315. if slot >= 13:
  316. if not item:
  317. return slot
  318. return -1
  319.  
  320. # Injects item movement on inventory
  321. def Inject_InventoryMovement(movementType,slotInitial,slotFinal,logItemName,quantity=0):
  322. p = struct.pack('<B',movementType)
  323. p += struct.pack('<B',slotInitial)
  324. p += struct.pack('<B',slotFinal)
  325. p += struct.pack('<H',quantity)
  326. log('Plugin: Moving item "'+logItemName+'"...')
  327. # CLIENT_INVENTORY_ITEM_MOVEMENT
  328. inject_joymax(0x7034,p,False)
  329.  
  330. # Try to equip item
  331. def EquipItem(item):
  332. itemData = get_item(item['model'])
  333. # Check equipables only
  334. if itemData['tid1'] != 1:
  335. log('Plugin: '+item['name']+' cannot be equiped!')
  336. return
  337. # Check equipable type
  338. t = itemData['tid2']
  339. # garment, protector, armor, robe, light, heavy
  340. if t == 1 or t == 2 or t == 3 or t == 9 or t == 10 or t == 11:
  341. t = itemData['tid3']
  342. # head
  343. if t == 1:
  344. Inject_InventoryMovement(0,item['slot'],0,item['name'])
  345. # shoulders
  346. elif t == 2:
  347. Inject_InventoryMovement(0,item['slot'],2,item['name'])
  348. # chest
  349. elif t == 3:
  350. Inject_InventoryMovement(0,item['slot'],1,item['name'])
  351. # pants
  352. elif t == 4:
  353. Inject_InventoryMovement(0,item['slot'],4,item['name'])
  354. # gloves
  355. elif t == 5:
  356. Inject_InventoryMovement(0,item['slot'],3,item['name'])
  357. # boots
  358. elif t == 6:
  359. Inject_InventoryMovement(0,item['slot'],5,item['name'])
  360. # shields
  361. elif t == 4:
  362. Inject_InventoryMovement(0,item['slot'],7,item['name'])
  363. # accesories ch/eu
  364. elif t == 5 or t == 12:
  365. t = itemData['tid3']
  366. # earring
  367. if t == 1:
  368. Inject_InventoryMovement(0,item['slot'],9,item['name'])
  369. # necklace
  370. elif t == 2:
  371. Inject_InventoryMovement(0,item['slot'],10,item['name'])
  372. # ring
  373. elif t == 3:
  374. # Check if second ring slot is empty
  375. if not GetItemByExpression(lambda s,n: True,11):
  376. Inject_InventoryMovement(0,item['slot'],12,item['name'])
  377. else:
  378. Inject_InventoryMovement(0,item['slot'],11,item['name'])
  379. # weapon ch/eu
  380. elif t == 6:
  381. Inject_InventoryMovement(0,item['slot'],6,item['name'])
  382. # job
  383. elif t == 7:
  384. Inject_InventoryMovement(0,item['slot'],8,item['name'])
  385. # avatar
  386. elif t == 13:
  387. t = itemData['tid3']
  388. # hat
  389. if t == 1:
  390. Inject_InventoryMovement(36,item['slot'],0,item['name'])
  391. # dress
  392. elif t == 2:
  393. Inject_InventoryMovement(36,item['slot'],1,item['name'])
  394. # accesory
  395. elif t == 3:
  396. Inject_InventoryMovement(36,item['slot'],2,item['name'])
  397. # flag
  398. elif t == 4:
  399. Inject_InventoryMovement(36,item['slot'],3,item['name'])
  400. # devil spirit
  401. elif t == 14:
  402. Inject_InventoryMovement(36,item['slot'],4,item['name'])
  403.  
  404. # Try to unequip item
  405. def UnequipItem(item):
  406. # find an empty slot
  407. slot = GetEmptySlot()
  408. if slot != -1:
  409. Inject_InventoryMovement(0,item['slot'],slot,item['name'])
  410.  
  411. # ______________________________ Events ______________________________ #
  412.  
  413. # Called when the bot successfully connects to the game server
  414. def connected():
  415. global inGame
  416. inGame = None
  417.  
  418. # Called when the character enters the game world
  419. def joined_game():
  420. loadConfigs()
  421.  
  422. # All chat messages received are sent to this function
  423. def handle_chat(t,player,msg):
  424. # Remove guild name from union chat messages
  425. if t == 11:
  426. msg = msg.split(': ',1)[1]
  427. # Check player at leader list or a Discord message
  428. if player and lstLeaders_exist(player) or t == 100:
  429. # Parsing message command
  430. if msg == "START":
  431. start_bot()
  432. log("Plugin: Bot started")
  433. elif msg == "STOP":
  434. stop_bot()
  435. log("Plugin: Bot stopped")
  436. elif msg.startswith("TRACE"):
  437. # deletes empty spaces on right
  438. msg = msg.rstrip()
  439. if msg == "TRACE":
  440. if start_trace(player):
  441. log("Plugin: Starting trace to ["+player+"]")
  442. else:
  443. msg = msg[5:].split()[0]
  444. if start_trace(msg):
  445. log("Plugin: Starting trace to ["+msg+"]")
  446. elif msg == "NOTRACE":
  447. stop_trace()
  448. log("Plugin: Trace stopped")
  449. elif msg.startswith("SETPOS"):
  450. # deletes empty spaces on right
  451. msg = msg.rstrip()
  452. if msg == "SETPOS":
  453. p = get_position()
  454. set_training_position(p['region'], p['x'], p['y'],p['z'])
  455. log("Plugin: Training area set to current position (X:%.1f,Y:%.1f)"%(p['x'],p['y']))
  456. else:
  457. try:
  458. # check arguments
  459. p = msg[6:].split()
  460. x = float(p[0])
  461. y = float(p[1])
  462. # auto calculated if is not specified
  463. region = int(p[2]) if len(p) >= 3 else 0
  464. z = float(p[3]) if len(p) >= 4 else 0
  465. set_training_position(region,x,y,z)
  466. log("Plugin: Training area set to (X:%.1f,Y:%.1f)"%(x,y))
  467. except:
  468. log("Plugin: Wrong training area coordinates!")
  469. elif msg == 'GETPOS':
  470. # Check current position
  471. pos = get_position()
  472. phBotChat.Private(player,'My position is (X:%.1f,Y:%.1f,Z:%1f,Region:%d)'%(pos['x'],pos['y'],pos['z'],pos['region']))
  473. elif msg.startswith("SETRADIUS"):
  474. # deletes empty spaces on right
  475. msg = msg.rstrip()
  476. if msg == "SETRADIUS":
  477. # set default radius
  478. radius = 35
  479. set_training_radius(radius)
  480. log("Plugin: Training radius reseted to "+str(radius)+" m.")
  481. else:
  482. try:
  483. # split and parse movement radius
  484. radius = int(float(msg[9:].split()[0]))
  485. # to absolute
  486. radius = (radius if radius > 0 else radius*-1)
  487. set_training_radius(radius)
  488. log("Plugin: Training radius set to "+str(radius)+" m.")
  489. except:
  490. log("Plugin: Wrong training radius value!")
  491. elif msg.startswith('SETSCRIPT'):
  492. # deletes empty spaces on right
  493. msg = msg.rstrip()
  494. if msg == 'SETSCRIPT':
  495. # reset script
  496. set_training_script('')
  497. log('Plugin: Training script path has been reseted')
  498. else:
  499. # change script to the path specified
  500. set_training_script(msg[9:])
  501. log('Plugin: Training script path has been changed')
  502. elif msg.startswith('SETAREA '):
  503. # deletes empty spaces on right
  504. msg = msg[8:]
  505. if msg:
  506. # try to change to specified area name
  507. if set_training_area(msg):
  508. log('Plugin: Training area has been changed to ['+msg+']')
  509. else:
  510. log('Plugin: Training area ['+msg+'] not found in the list')
  511. elif msg == "SIT":
  512. log("Plugin: Sit/Stand")
  513. inject_joymax(0x704F,b'\x04',False)
  514. elif msg == "JUMP":
  515. # Just a funny emote lol
  516. log("Plugin: Jumping!")
  517. inject_joymax(0x3091,b'\x0c',False)
  518. elif msg.startswith("CAPE"):
  519. # deletes empty spaces on right
  520. msg = msg.rstrip()
  521. if msg == "CAPE":
  522. log("Plugin: Using PVP Cape by default (Yellow)")
  523. inject_joymax(0x7516,b'\x05',False)
  524. else:
  525. # get cape type normalized
  526. cape = msg[4:].split()[0].lower()
  527. if cape == "off":
  528. log("Plugin: Removing PVP Cape")
  529. inject_joymax(0x7516,b'\x00',False)
  530. elif cape == "red":
  531. log("Plugin: Using PVP Cape (Red)")
  532. inject_joymax(0x7516,b'\x01',False)
  533. elif cape == "gray":
  534. log("Plugin: Using PVP Cape (Gray)")
  535. inject_joymax(0x7516,b'\x02',False)
  536. elif cape == "blue":
  537. log("Plugin: Using PVP Cape (Blue)")
  538. inject_joymax(0x7516,b'\x03',False)
  539. elif cape == "white":
  540. log("Plugin: Using PVP Cape (White)")
  541. inject_joymax(0x7516,b'\x04',False)
  542. elif cape == "yellow":
  543. log("Plugin: Using PVP Cape (Yellow)")
  544. inject_joymax(0x7516,b'\x05',False)
  545. else:
  546. log("Plugin: Wrong PVP Cape color!")
  547. elif msg == "ZERK":
  548. log("Plugin: Using Berserker mode")
  549. inject_joymax(0x70A7,b'\x01',False)
  550. elif msg == "RETURN":
  551. # Quickly check if is dead
  552. character = get_character_data()
  553. if character['hp'] == 0:
  554. # RIP
  555. log('Plugin: Resurrecting at town...')
  556. inject_joymax(0x3053,b'\x01',False)
  557. else:
  558. log('Plugin: Trying to use return scroll...')
  559. # Avoid high CPU usage with too many chars at the same time
  560. Timer(random.uniform(0.5,2),use_return_scroll).start()
  561. elif msg.startswith("TP"):
  562. # deletes command header and whatever used as separator
  563. msg = msg[3:]
  564. if not msg:
  565. return
  566. # select split char
  567. split = ',' if ',' in msg else ' '
  568. # extract arguments
  569. source_dest = msg.split(split)
  570. # needs to be at least two name points to try teleporting
  571. if len(source_dest) >= 2:
  572. inject_teleport(source_dest[0].strip(),source_dest[1].strip())
  573. elif msg.startswith("INJECT "):
  574. msgPacket = msg[7:].split()
  575. msgPacketLen = len(msgPacket)
  576. if msgPacketLen == 0:
  577. log("Plugin: Incorrect structure to inject packet")
  578. return
  579. # Check packet structure
  580. opcode = int(msgPacket[0],16)
  581. data = bytearray()
  582. encrypted = False
  583. dataIndex = 1
  584. if msgPacketLen >= 2:
  585. enc = msgPacket[1].lower()
  586. if enc == 'true' or enc == 'false':
  587. encrypted = enc == "true"
  588. dataIndex +=1
  589. # Create packet data and inject it
  590. for i in range(dataIndex, msgPacketLen):
  591. data.append(int(msgPacket[i],16))
  592. inject_joymax(opcode,data,encrypted)
  593. # Log the info
  594. log("Plugin: Injecting packet...\nOpcode: 0x"+'{:02X}'.format(opcode)+" - Encrypted: "+("Yes" if encrypted else "No")+"\nData: "+(' '.join('{:02X}'.format(int(msgPacket[x],16)) for x in range(dataIndex, msgPacketLen)) if len(data) else 'None'))
  595. elif msg.startswith("CHAT "):
  596. handleChatCommand(msg[5:])
  597. elif msg.startswith("MOVEON"):
  598. if msg == "MOVEON":
  599. randomMovement()
  600. else:
  601. try:
  602. # split and parse movement radius
  603. radius = int(float(msg[6:].split()[0]))
  604. # to positive
  605. radius = (radius if radius > 0 else radius*-1)
  606. randomMovement(radius)
  607. except:
  608. log("Plugin: Movement maximum radius incorrect")
  609. elif msg.startswith("FOLLOW"):
  610. # default values
  611. charName = player
  612. distance = 10
  613. if msg != "FOLLOW":
  614. # Check params
  615. msg = msg[6:].split()
  616. try:
  617. if len(msg) >= 1:
  618. charName = msg[0]
  619. if len(msg) >= 2:
  620. distance = float(msg[1])
  621. except:
  622. log("Plugin: Follow distance incorrect")
  623. return
  624. # Start following
  625. if start_follow(charName,distance):
  626. log("Plugin: Starting to follow to ["+charName+"] using ["+str(distance)+"] as distance")
  627. elif msg == "NOFOLLOW":
  628. if stop_follow():
  629. log("Plugin: Following stopped")
  630. elif msg.startswith("PROFILE"):
  631. if msg == "PROFILE":
  632. if set_profile('Default'):
  633. log("Plugin: Setting Default profile")
  634. else:
  635. msg = msg[7:]
  636. if set_profile(msg):
  637. log("Plugin: Setting "+msg+" profile")
  638. elif msg == "DC":
  639. log("Plugin: Disconnecting...")
  640. disconnect()
  641. elif msg.startswith("MOUNT"):
  642. # default value
  643. pet = "horse"
  644. if msg != "MOUNT":
  645. msg = msg[5:].split()
  646. if msg:
  647. pet = msg[0]
  648. # Try mount pet
  649. if MountPet(pet):
  650. log("Plugin: Mounting pet ["+pet+"]")
  651. elif msg.startswith("DISMOUNT"):
  652. # default value
  653. pet = "horse"
  654. if msg != "DISMOUNT":
  655. msg = msg[8:].split()
  656. if msg:
  657. pet = msg[0]
  658. # Try dismount pet
  659. if DismountPet(pet):
  660. log("Plugin: Dismounting pet ["+pet+"]")
  661. elif msg == "GETOUT":
  662. # Check if has party
  663. if get_party():
  664. # Left it
  665. log("Plugin: Leaving the party..")
  666. inject_joymax(0x7061,b'',False)
  667. elif msg.startswith("RECALL "):
  668. msg = msg[7:]
  669. if msg:
  670. npcUID = GetNPCUniqueID(msg)
  671. if npcUID > 0:
  672. log("Plugin: Designating recall to \""+msg.title()+"\"...")
  673. inject_joymax(0x7059, struct.pack('I',npcUID), False)
  674. elif msg.startswith("EQUIP "):
  675. msg = msg[6:]
  676. if msg:
  677. # search item with similar name or exact server name
  678. item = GetItemByExpression(lambda n,s: msg in n or msg == s,13)
  679. if item:
  680. EquipItem(item)
  681. elif msg.startswith("UNEQUIP "):
  682. msg = msg[8:]
  683. if msg:
  684. # search item with similar name or exact server name
  685. item = GetItemByExpression(lambda n,s: msg in n or msg == s,0,12)
  686. if item:
  687. UnequipItem(item)
  688. elif msg.startswith("REVERSE "):
  689. # remove command
  690. msg = msg[8:]
  691. if msg:
  692. # check params
  693. msg = msg.split(' ',1)
  694. # param type
  695. if msg[0] == 'return':
  696. # try to use it
  697. if reverse_return(0,''):
  698. log('Plugin: Using reverse to the last return scroll location')
  699. elif msg[0] == 'death':
  700. # try to use it
  701. if reverse_return(1,''):
  702. log('Plugin: Using reverse to the last death location')
  703. elif msg[0] == 'player':
  704. # Check existing name
  705. if len(msg) >= 2:
  706. # try to use it
  707. if reverse_return(2,msg[1]):
  708. log('Plugin: Using reverse to player "'+msg[1]+'" location')
  709. elif msg[0] == 'zone':
  710. # Check existing zone
  711. if len(msg) >= 2:
  712. # try to use it
  713. if reverse_return(3,msg[1]):
  714. log('Plugin: Using reverse to zone "'+msg[1]+'" location')
  715.  
  716. # Called every 500ms
  717. def event_loop():
  718. if inGame and followActivated:
  719. player = near_party_player(followPlayer)
  720. # check if is near
  721. if not player:
  722. return
  723. # check distance to the player
  724. if followDistance > 0:
  725. p = get_position()
  726. playerDistance = round(GetDistance(p['x'],p['y'],player['x'],player['y']),2)
  727. # check if has to move
  728. if followDistance < playerDistance:
  729. # generate vector unit
  730. x_unit = (player['x'] - p['x']) / playerDistance
  731. y_unit = (player['y'] - p['y']) / playerDistance
  732. # distance to move
  733. movementDistance = playerDistance-followDistance
  734. log("Following "+followPlayer+"...")
  735. move_to(movementDistance * x_unit + p['x'],movementDistance * y_unit + p['y'],0)
  736. else:
  737. # Avoid negative numbers
  738. log("Following "+followPlayer+"...")
  739. move_to(player['x'],player['y'],0)
  740.  
  741. # Plugin loaded
  742. log("Plugin: "+pName+" v"+pVersion+" successfully loaded")
  743.  
  744. if os.path.exists(getPath()):
  745. # Adding RELOAD plugin support
  746. loadConfigs()
  747. else:
  748. # Creating configs folder
  749. os.makedirs(getPath())
  750. log('Plugin: '+pName+' folder has been created')
  751.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement