diff --git a/pyboy/plugins/game_wrapper_pokemon_pinball.pxd b/pyboy/plugins/game_wrapper_pokemon_pinball.pxd index 75991a3b9..78d02d5af 100644 --- a/pyboy/plugins/game_wrapper_pokemon_pinball.pxd +++ b/pyboy/plugins/game_wrapper_pokemon_pinball.pxd @@ -10,10 +10,10 @@ cdef class GameWrapperPokemonPinball(PyBoyGameWrapper): cdef readonly int ball_saver_seconds_left cdef readonly int ball_size cdef readonly int ball_type - cdef readonly int ball_x - cdef readonly int ball_x_velocity - cdef readonly int ball_y - cdef readonly int ball_y_velocity + cdef readonly float ball_x + cdef readonly float ball_x_velocity + cdef readonly float ball_y + cdef readonly float ball_y_velocity cdef readonly int balls_left cdef readonly int current_map cdef readonly int current_stage diff --git a/pyboy/plugins/game_wrapper_pokemon_pinball.py b/pyboy/plugins/game_wrapper_pokemon_pinball.py index 8208ad88c..1d7390271 100644 --- a/pyboy/plugins/game_wrapper_pokemon_pinball.py +++ b/pyboy/plugins/game_wrapper_pokemon_pinball.py @@ -12,7 +12,7 @@ import logging from enum import Enum -from pyboy.utils import PyBoyException, WindowEvent, bcd_to_dec +from pyboy.utils import PyBoyException, WindowEvent, bcd_to_dec, fixed_point_to_value from .base_plugin import PyBoyGameWrapper @@ -695,11 +695,24 @@ def post_tick(self): self.multiplier = self.pyboy.memory[ADDR_MULTIPLIER] self.ball_size = self.pyboy.memory[ADDR_BALL_SIZE] - - self.ball_x = self.pyboy.memory[ADDR_BALL_X] - self.ball_y = self.pyboy.memory[ADDR_BALL_Y] - self.ball_x_velocity = self.pyboy.memory[ADDR_BALL_X_VELOCITY] - self.ball_y_velocity = self.pyboy.memory[ADDR_BALL_Y_VELOCITY] + self.ball_x = fixed_point_to_value( + self.pyboy.memory[ADDR_BALL_X:ADDR_BALL_X+2], + is_signed=True + ) + self.ball_y = fixed_point_to_value( + self.pyboy.memory[ADDR_BALL_Y:ADDR_BALL_Y+2], + is_signed=True + ) + + # Velocity values (likely signed since they can be negative) + self.ball_x_velocity = fixed_point_to_value( + self.pyboy.memory[ADDR_BALL_X_VELOCITY:ADDR_BALL_X_VELOCITY+2], + is_signed=True + ) + self.ball_y_velocity = fixed_point_to_value( + self.pyboy.memory[ADDR_BALL_Y_VELOCITY:ADDR_BALL_Y_VELOCITY+2], + is_signed=True + ) self.pikachu_saver_charge = self.pyboy.memory[ADDR_PIKACHU_SAVER_CHARGE] diff --git a/pyboy/utils.py b/pyboy/utils.py index a1313a1a0..78b5d8d7e 100644 --- a/pyboy/utils.py +++ b/pyboy/utils.py @@ -488,3 +488,35 @@ def bcd_to_dec(value, byte_width=1, byteorder="little"): multiplier *= 100 return decimal_value + +def fixed_point_to_value(raw_bytes, is_signed=False, fractional_bits=8): + """ + Convert fixed-point bytes to appropriate value + + Args: + raw_bytes: Byte array containing the fixed-point value + is_signed: Whether to interpret as signed (two's complement) + fractional_bits: Number of bits used for the fractional part + + Returns: + A float value representing the fixed-point number + """ + value = int.from_bytes(raw_bytes, "little") + + total_bits = len(raw_bytes) * 8 + + # Calculate integer and fractional parts + integer_part = value >> fractional_bits + fractional_part = value & ((1 << fractional_bits) - 1) + + # Handle two's complement for signed values + if is_signed and (value & (1 << (total_bits - 1))): + # It's a negative value in two's complement + # Calculate the negative value properly + integer_value = value + if integer_value & (1 << (total_bits - 1)): + integer_value = -((~integer_value + 1) & ((1 << total_bits) - 1)) + return integer_value / (1 << fractional_bits) + + # Return the full fixed-point value + return integer_part + (fractional_part / (1 << fractional_bits)) \ No newline at end of file