Advertisement
Guest User

Star Ocean 4 colosseum battle automation with GIMX

a guest
Aug 3rd, 2023
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.75 KB | Source Code | 0 0
  1. import socket
  2. from enum import IntEnum
  3. from time import sleep, time
  4. from typing import List
  5. import struct
  6. import sys
  7.  
  8. IP = "127.0.0.1"
  9. PORT = 51914
  10.  
  11. # How long a button is pressed down for a normal "press and release" button press
  12. PRESS_DURATION = 0.05
  13. # For a "default" button press, how long to wait afterwards before moving on
  14. DEFAULT_WAIT = 0.7
  15.  
  16. class Ps3Controls(IntEnum):
  17.     LEFT_STICK_X = 0
  18.     LEFT_STICK_Y = 1
  19.     RIGHT_STICK_X = 2
  20.     RIGHT_STICK_Y = 3
  21.     FINGER1_X = 4
  22.     FINGER1_Y = 5
  23.     FINGER2_X = 6
  24.     FINGER2_Y = 7
  25.     SELECT = 128
  26.     START = 129
  27.     PS = 130
  28.     UP = 131
  29.     RIGHT = 132
  30.     DOWN = 133
  31.     LEFT = 134
  32.     TRIANGLE = 135
  33.     CIRCLE = 136
  34.     CROSS = 137
  35.     SQUARE = 138
  36.     L1 = 139
  37.     R1 = 140
  38.     L2 = 141
  39.     R2 = 142
  40.     L3 = 143
  41.     R3 = 144
  42.  
  43. # Convenience shorthand
  44. CROSS = Ps3Controls.CROSS
  45. CIRCLE = Ps3Controls.CIRCLE
  46. TRIANGLE = Ps3Controls.TRIANGLE
  47. SQUARE = Ps3Controls.SQUARE
  48. LEFT = Ps3Controls.LEFT
  49. DOWN = Ps3Controls.DOWN
  50. UP = Ps3Controls.UP
  51. R2 = Ps3Controls.R2
  52. R3 = Ps3Controls.R3
  53.  
  54.  
  55. class ButtonState(IntEnum):
  56.     RELEASED = 0
  57.     PRESSED = 255
  58.  
  59. # Initial state of everything being released.  This global state will be modified and sent with each button press.
  60. state = {
  61.     Ps3Controls.LEFT_STICK_X : 0,
  62.     Ps3Controls.LEFT_STICK_Y : 0,
  63.     Ps3Controls.RIGHT_STICK_X : 0,
  64.     Ps3Controls.RIGHT_STICK_Y : 0,
  65.     Ps3Controls.FINGER1_X : 0,
  66.     Ps3Controls.FINGER1_Y : 0,
  67.     Ps3Controls.FINGER2_X : 0,
  68.     Ps3Controls.FINGER2_Y : 0,
  69.     Ps3Controls.SELECT : ButtonState.RELEASED,
  70.     Ps3Controls.START : ButtonState.RELEASED,
  71.     Ps3Controls.PS : ButtonState.RELEASED,
  72.     Ps3Controls.UP : ButtonState.RELEASED,
  73.     Ps3Controls.RIGHT : ButtonState.RELEASED,
  74.     Ps3Controls.DOWN : ButtonState.RELEASED,
  75.     Ps3Controls.LEFT : ButtonState.RELEASED,
  76.     Ps3Controls.TRIANGLE : ButtonState.RELEASED,
  77.     Ps3Controls.CIRCLE : ButtonState.RELEASED,
  78.     Ps3Controls.CROSS : ButtonState.RELEASED,
  79.     Ps3Controls.SQUARE : ButtonState.RELEASED,
  80.     Ps3Controls.L1 : ButtonState.RELEASED,
  81.     Ps3Controls.R1 : ButtonState.RELEASED,
  82.     Ps3Controls.L2 : ButtonState.RELEASED,
  83.     Ps3Controls.R2 : ButtonState.RELEASED,
  84.     Ps3Controls.L3 : ButtonState.RELEASED,
  85.     Ps3Controls.R3 : ButtonState.RELEASED,
  86. }
  87.  
  88. # Check that I can talk to the GIMX server.  Return non-zero on failure
  89. def check_status():
  90.     packet = bytearray([0x00, 0x00])
  91.     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  92.     sock.connect((IP, PORT))
  93.     sock.send(packet)
  94.     timeval = struct.pack('ll', 1, 0)  # seconds and microseconds
  95.     sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
  96.     try:
  97.         data, (address, port) = sock.recvfrom(2)
  98.         response = bytearray(data)
  99.         if (response[0] != 0x00):
  100.             print("Invalid reply code: {0}".format(response[0]))
  101.             return 1
  102.     except socket.error as err:
  103.         print(err)
  104.    
  105.     return 0
  106.  
  107. def send_message(changes):
  108.     packet = bytearray([0x01, len(changes)])  # type + axis count
  109.    
  110.     for axis, value in changes.items():
  111.         # axis + value (network byte order)
  112.         packet.extend([axis, (value & 0xff000000) >> 24, (value & 0xff0000) >> 16, (value & 0xff00) >> 8, (value & 0xff)])
  113.  
  114.     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  115.     sock.sendto(packet, (IP, PORT))
  116.  
  117. def send_key(button: Ps3Controls, button_state: ButtonState):
  118.     """ Updates the state of a single button. """
  119.     global state
  120.     state[button] = button_state
  121.     send_message(state)
  122.  
  123. # Press & release a single button at the common press interval.  Will wait for 1s after pressing by default
  124. # but this can be configured with the after_wait argument
  125. def press(button: Ps3Controls, after_wait: float = DEFAULT_WAIT, press_duration: float = PRESS_DURATION):
  126.     """ Press & release a single button at the common press interval. """
  127.     send_key(button, ButtonState.PRESSED)
  128.     sleep(press_duration)
  129.     send_key(button, ButtonState.RELEASED)
  130.     sleep(after_wait)
  131.  
  132. def press_sequence(buttons: List[Ps3Controls]):
  133.     """ Presses a sequence of buttons in order, with the default wait time between them. """
  134.     for button in buttons:
  135.         press(button)
  136.  
  137. def hold(button: Ps3Controls, hold_duration: float, after_wait: float = DEFAULT_WAIT):
  138.     """ Hold a button down for a period of time before releasing. """
  139.     press(button, after_wait, hold_duration)
  140.  
  141. def repeat_duration(button: Ps3Controls, repeat_duration: float, time_between_presses: float = 0.3):
  142.     """ Presses & releases a single button quickly & repeatedly for a period of time. """
  143.     start_time = time()
  144.     while time() - start_time < repeat_duration:
  145.         press(button, time_between_presses)
  146.  
  147. def repeat(button: Ps3Controls, repeats: int, time_between_presses: float = 0.3):
  148.     """ Presses & releases a single button quickly & repeatedly a set number of times. """
  149.     for _ in range(repeats):
  150.         press(button, time_between_presses)
  151.  
  152. def wake_controller():
  153.     """ The very first command sent will "wake" the controller but not make it through for action
  154.    If it's already awake then this will actually do something.  Therefor I am just pressing
  155.    R3 as worst case scenario it will centre the camera.
  156.    """
  157.     press(R3, 2.0)
  158.  
  159. def reset():
  160.     """Just press circle a bunch as a crude "reset" that I can slam in when necessary."""
  161.     repeat_duration(CIRCLE, 15)
  162.  
  163. def colosseum_battle(character_from_top: int, enemy_from_bottom: int):
  164.     """ Do a colosseum battle.  Requires character to be standing in front of the receptionist & battle skill on R2 button
  165.  
  166.    Args:
  167.        character_from_top (int): How many times to press 'down' during character select
  168.        enemy_from_bottom (int): How many times to press 'up' after scrolling to the bottom of the enemy list
  169.    """
  170.     # Get to character select
  171.     press_sequence([CROSS, CROSS, CROSS])
  172.     sleep(2)
  173.     # Select the character
  174.     repeat(DOWN, character_from_top)
  175.     press(CROSS)
  176.     # Select the enemy
  177.     hold(R2, 1)
  178.     repeat(UP, enemy_from_bottom)
  179.     press_sequence([CROSS, CROSS, CROSS, LEFT, CROSS])
  180.     sleep(2)
  181.     press(CROSS)
  182.     sleep(4)
  183.     # Skip through pre-match commentary
  184.     repeat(CROSS, 4)
  185.     # Perform battle
  186.     repeat_duration(R2, 20) # This is on for a long time because it will be pressed during the battle loading/intro too
  187.     # Battle victory screen to end can just spam Circle
  188.     repeat_duration(CIRCLE, 15)
  189.  
  190.  
  191. def main():
  192.     if check_status():
  193.         sys.exit(-1)
  194.  
  195.     wake_controller()
  196.     # reset()
  197.  
  198.     battles = 0
  199.     while True:
  200.         colosseum_battle(5, 0)
  201.         battles += 1
  202.         if battles % 5 == 0:
  203.             print(f"Completed {battles} battles.")
  204.  
  205.  
  206. if __name__ == "__main__":
  207.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement