Source code for ocatari.ram.assault

from ._helper_methods import _convert_number
from .game_objects import GameObject, ValueObject
import sys

"""
RAM extraction for the game ASSAULT. Supported modes: ram.
"""

MAX_NB_OBJECTS = {'Player': 1, 'PlayerMissileVertical': 1, 'PlayerMissileHorizontal': 1, 'MotherShip': 1,
                  'Enemy': 9, 'EnemyMissile': 1}
MAX_NB_OBJECTS_HUD = {'PlayerScore': 6, 'Lives': 3, 'Health': 1}


[docs] class Player(GameObject): """ The player figure i.e., the cannon. """ def __init__(self): super().__init__() self.visible = True self._xy = 0, 0 self.wh = 8, 8 self.rgb = 214, 214, 214 self.hud = False
[docs] class PlayerMissileVertical(GameObject): """ The projectile shot in the vertical direction from the cannon. """ def __init__(self): super().__init__() self.visible = True self._xy = 0, 0 self.wh = 1, 8 self.rgb = 236, 236, 236 self.hud = False
[docs] class PlayerMissileHorizontal(GameObject): """ The projectiles shot in the horizontal direction from the cannon. """ def __init__(self): super().__init__() self.visible = True self._xy = 0, 0 self._prev_xy = None self.wh = 4, 2 self.rgb = 214, 214, 214 self.hud = False
[docs] class MotherShip(GameObject): """ The mother ship at the top, that continually deploys the smaller drones. """ def __init__(self): super().__init__() self.visible = True self._xy = 0, 0 self.wh = 32, 16 self.rgb = 72, 160, 72 self.hud = False
[docs] class Enemy(GameObject): """ The enemy drones deployed by the mother ship. """ def __init__(self): super().__init__() self.visible = True self._xy = 0, 0 self.wh = 16, 8 self.rgb = 167, 26, 26 self.hud = False
[docs] class EnemyMissile(GameObject): """ The projectiles shot at the player by the enemy drones. """ def __init__(self): super().__init__() self.visible = True self._xy = 0, 0 self.wh = 1, 6 self.rgb = 255, 255, 255 self.hud = False
[docs] class PlayerScore(ValueObject): """ The player's score display (HUD). """ def __init__(self): super().__init__() self.visible = True self._xy = 0, 0 self.rgb = 195, 144, 61 self.wh = 6, 8 self.hud = True self.score = 0 def __eq__(self, o): return isinstance(o, PlayerScore) and self.xy == o.xy
[docs] class Lives(GameObject): """ The indicator for the remaining lives of the player (HUD). """ def __init__(self): super().__init__() self.visible = True self._xy = 0, 0 self.rgb = 170, 170, 170 self.wh = 8, 8 self.hud = True
[docs] class Health(GameObject): """ The temperature meter of the cannon (HUD). """ def __init__(self): super().__init__() self.visible = True self._xy = 96, 192 self.rgb = 72, 160, 72 self.wh = 8, 8 self.hud = True
def _init_objects_ram(hud=False): """ (Re)Initialize the objects """ objects = [] #Player(), PlayerMissileVertical(), Enemy(), EnemyMissile(), MotherShip() objects.extend([None] * 8) if hud: objects.extend([None] * 15) #[PlayerScore(), Health(), Lives()] return objects # parses MAX_NB* dicts, returns default init list of objects def _get_max_objects(hud=False): def fromdict(max_obj_dict): objects = [] mod = sys.modules[__name__] for k, v in max_obj_dict.items(): for _ in range(0, v): objects.append(getattr(mod, k)()) return objects if hud: return fromdict(MAX_NB_OBJECTS_HUD) return fromdict(MAX_NB_OBJECTS) # position of objects if value 0 to 16. 17 to 32 uses these values but -1 and so on. player_x_pos = [3, 3, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 3, 3, 3, 3] player_x_pos_128 = [11, 11, 23, 38, 53, 68, 83, 98, 113, 128, 143, 158, 11, 11, 11, 11] # after value 128 it differs horizontal_pos = 0 enemy_missile_x = 0 def _detect_objects_ram(objects, ram_state, hud=False): """ For all objects: (x, y, w, h, r, g, b) """ # player player = Player() objects[0] = player x_mod = ram_state[16] x_diff = (x_mod // 16) % 8 if ram_state[16] < 128: x = player_x_pos[ram_state[16] % 16] - x_diff # formula for position if x < 0: x = 160 + x player.xy = x, 178 else: player.xy = player_x_pos_128[ram_state[16] % 16] - x_diff, 178 # player missile missile = PlayerMissileVertical() if 7 < ram_state[67] < 119: val = ram_state[39] x_diff = (val // 16) % 8 if ram_state[39] < 128: x = player_x_pos[ram_state[39] % 16] - x_diff if x < 0: x = 160 + x if ram_state[67] < 25: y = ram_state[67] + 36 elif ram_state[67] < 32: y = ram_state[67] + 45 elif ram_state[67] < 50: y = ram_state[67] + 53 else: y = ram_state[67] + 64 if ram_state[67] == 47: missile.wh = 1, 3 elif ram_state[67] == 55: missile.wh = 1, 23 y = y - 15 elif ram_state[67] == 39: missile.wh = 1, 18 y = y - 10 elif ram_state[67] == 31: missile.wh = 1, 6 elif ram_state[67] == 23: missile.wh = 1, 16 y = y - 9 missile.xy = x - 1, y else: x = player_x_pos_128[ram_state[39] % 16] - x_diff if ram_state[67] < 23: y = ram_state[67] + 36 elif ram_state[67] < 32: y = ram_state[67] + 45 elif ram_state[67] < 50: y = ram_state[67] + 53 else: y = ram_state[67] + 64 if ram_state[67] == 47: missile.wh = 1, 3 elif ram_state[67] == 55: missile.wh = 1, 23 y = y - 15 elif ram_state[67] == 39: missile.wh = 1, 18 y = y - 10 elif ram_state[67] == 31: missile.wh = 1, 6 elif ram_state[67] == 23: missile.wh = 1, 16 y = y - 9 missile.xy = x - 1, y objects[1] = missile else: objects[1] = None global horizontal_pos global horizontal_pos_right global horizontal_pos_left # player missile horizontal if ram_state[24] == 88: mis = PlayerMissileHorizontal() mis_offset = 2 #if horizontal_pos == 0 or horizontal_pos > 130 or horizontal_pos < 20: # horizontal_pos = player.x if horizontal_pos == 0: horizontal_pos_right = player.x + player.w + mis_offset horizontal_pos_left = player.x if ram_state[26] == 128: # shot to the right horizontal_pos_right = horizontal_pos_right + 8 horizontal_pos = horizontal_pos_right mis.xy = horizontal_pos_right, 181 elif ram_state[26] == 64: # shot to the left horizontal_pos_left = horizontal_pos_left - 8 horizontal_pos = horizontal_pos_left mis.xy = horizontal_pos_left, 181 objects[2] = mis else: objects[2] = None horizontal_pos = 0 # mother ship mother_ship = MotherShip() x_mother = ram_state[69] x_mother_diff = (x_mother // 16) % 8 if ram_state[69] < 128: x_val = player_x_pos[(ram_state[69] - 1) % 16] - x_mother_diff if x_val < 0: x_val = 160 + x_val mother_ship.xy = x_val, 18 else: mother_ship.xy = player_x_pos_128[(ram_state[69] - 1) % 16] - x_mother_diff, 18 if ram_state[11] == 112: # mother ship changes color mother_ship.rgb = 184, 70, 162 objects[3] = mother_ship # enemy global enemy_missile_x for en in range(3): enemy_appearance = ram_state[54 + en] if enemy_appearance == 0: # enemy not visible in this case continue if enemy_appearance != 96: enemy = Enemy() x_enemy = ram_state[33 + en] x_enemy_diff = (x_enemy // 16) % 8 if ram_state[33 + en] < 128: x_val = player_x_pos[(ram_state[33 + en]) % 16] - x_enemy_diff if x_val < 0: x_val = 160 + x_val if ram_state[43] == 25: enemy.xy = x_val, 103 - 25 * en elif ram_state[43] == 145: enemy.xy = x_val, 93 - 25 * en else: # take pos_128 x_val = player_x_pos_128[(ram_state[33 + en]) % 16] - x_enemy_diff if x_val < 0: x_val = 160 + x_val if ram_state[43] == 25: enemy.xy = x_val, 103 - 25 * en elif ram_state[43] == 145: enemy.xy = x_val, 93 - 25 * en if enemy_appearance == 160: enemy.wh = 8, 8 if ram_state[40] == 196: # set enemy color enemy.rgb = 72, 160, 72 elif ram_state[40] == 204: # set enemy color enemy.rgb = 84, 138, 210 elif ram_state[40] == 212: # set enemy color enemy.rgb = 105, 77, 20 if enemy_appearance == 224 or enemy_appearance == 96: # 96 only right part shown if enemy_appearance == 224: # 224 means two enemies are shown enemy.wh = 8, 8 enemy2 = Enemy() x_enemy2 = ram_state[36 + en] x_enemy_diff2 = (x_enemy2 // 16) % 8 if ram_state[36 + en] < 128: x_val2 = player_x_pos[(ram_state[36 + en]) % 16] - x_enemy_diff2 if x_val2 < 0: x_val2 = 160 + x_val2 if ram_state[43] == 25: enemy2.xy = x_val2, 103 - 25 * en elif ram_state[43] == 145: enemy2.xy = x_val2, 93 - 25 * en else: # take pos_128 x_val2 = player_x_pos_128[(ram_state[36 + en]) % 16] - x_enemy_diff2 if x_val2 < 0: x_val2 = 160 + x_val2 if ram_state[43] == 25: enemy2.xy = x_val2, 103 - 25 * en elif ram_state[43] == 145: enemy2.xy = x_val2, 93 - 25 * en enemy2.wh = 8, 8 if ram_state[40] == 196: # set enemy color enemy2.rgb = 72, 160, 72 elif ram_state[40] == 204: # set enemy color enemy2.rgb = 84, 138, 210 elif ram_state[40] == 212: # set enemy color enemy2.rgb = 105, 77, 20 objects[4+en] = enemy2 if enemy_appearance != 96: objects[4+en] = enemy if en == 0 and enemy_missile_x == 0 and ram_state[75] == 128\ and (enemy_appearance == 192 or enemy_appearance == 160 or enemy_appearance == 224): enemy_missile_x = enemy.x elif en == 0 and enemy_missile_x == 0 and ram_state[75] == 128 and enemy_appearance == 96: enemy_missile_x = enemy2.x # enemy missile if ram_state[75] == 128: missile = EnemyMissile() if ram_state[40] == 212: # brown enemy, with red missile missile.xy = enemy_missile_x + 8, 30 + ram_state[73] missile.wh = 8, 7 missile.rgb = 214, 92, 92 elif ram_state[40] == 204: missile.xy = enemy_missile_x + 8, 102 + ram_state[73] missile.rgb = 92, 186, 92 missile.wh = 9, 16 elif ram_state[40] == 196: if 55 + ram_state[110] > 166: missile.xy = enemy_missile_x + 8, 166 else: missile.xy = enemy_missile_x + 7, 55 + ram_state[110] missile.rgb = 84, 138, 210 if missile.y + 30 > 186: missile.wh = 1, 20 else: missile.wh = 1, 30 else: missile.xy = enemy_missile_x, 60 + ram_state[110] missile.rgb = 187, 187, 53 objects[7] = missile else: enemy_missile_x = 0 if hud: # score for i in range(6): sc = PlayerScore() sc.xy = 96 - 8 * i, 2 objects[8+i] = sc # lives for i in range(ram_state[101] - 1): liv = Lives() liv.xy = 15 + 16 * i, 192 objects[14+i] = liv # health health = Health() if ram_state[28] == 192 and ram_state[29] == 0: health.wh = 8, 8 elif ram_state[28] == 224 and ram_state[29] == 0: health.wh = 12, 8 elif ram_state[28] == 240 and ram_state[29] == 0: health.wh = 16, 8 elif ram_state[28] == 248 and ram_state[29] == 0: health.wh = 20, 8 elif ram_state[28] == 252 and ram_state[29] == 0: health.wh = 24, 8 elif ram_state[28] == 254 and ram_state[29] == 0: health.wh = 28, 8 elif ram_state[28] == 255 and ram_state[29] == 0: health.wh = 32, 8 elif ram_state[28] == 255 and ram_state[29] == 1: health.wh = 36, 8 elif ram_state[28] == 255 and ram_state[29] == 3: health.wh = 40, 8 elif ram_state[28] == 255 and ram_state[29] == 7: health.wh = 44, 8 elif ram_state[28] == 255 and ram_state[29] == 15: health.wh = 48, 8 elif ram_state[28] == 255 and ram_state[29] == 31: health.wh = 52, 8 elif ram_state[28] == 255 and ram_state[29] == 63: health.wh = 56, 8 elif ram_state[28] == 255 and ram_state[29] == 127: health.wh = 60, 8 elif ram_state[28] == 255 and ram_state[29] == 255: health.wh = 64, 8 if ram_state[21] == 70: health.rgb = 200, 72, 72 objects[14+ram_state[101]] = health def _detect_objects_assault_raw(info, ram_state): """ O: NOP 1: 2: shoot 3: move right 4: move left 5: shoot to the right 6: shoot to the left """ info["score"] = _convert_number(ram_state[0]) * 10000 + _convert_number(ram_state[1]) * 100 + _convert_number(ram_state[2]) # noqa info["player_x"] = ram_state[16] # start at x = 134 info["player_missile_x"] = ram_state[39] # start at x = 182 info["player_missile_y"] = ram_state[67] info["vertic_missile"] = ram_state[24:27] info["maybe_enemy_missile_visible"] = ram_state[75] # enemy missile visible at 128 info["enemy_x_part_1"] = ram_state[33:36] # 33 most downwards enemy info["enemy_x_part_2"] = ram_state[36:39] info["enemy_appearance"] = ram_state[54:57] # 192 = normal, 224 = split in two, 160 and 96 only one smaller part info["enemy_type"] = ram_state[40] info["mother_ship_color"] = ram_state[11:13] info["mother_ship_x"] = ram_state[69] info["health_color"] = ram_state[21] # 198 = green, 70 = red info["health"] = ram_state[28:30] info["player_sprite"] = ram_state[30] info["lives"] = ram_state[101]