Skip to content

Pokemon Pinball: Fix Coordinate System interpretaion #387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions pyboy/plugins/game_wrapper_pokemon_pinball.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 19 additions & 6 deletions pyboy/plugins/game_wrapper_pokemon_pinball.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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]

Expand Down
32 changes: 32 additions & 0 deletions pyboy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))