from .game_objects import GameObject
import sys
"""
RAM extraction for the game Atlantis. Supported modes: ram.
"""
MAX_NB_OBJECTS = {'Sentry': 2, 'AcropolisCommandPost': 1, 'Generator': 3, 'DomedPalace': 1,
'BridgedBazaar': 1, 'AquaPlane': 1, 'Projectile': 2, 'GorgonShip': 4, 'Deathray': 1, 'BanditBomber': 2}
MAX_NB_OBJECTS_HUD = {'Sentry': 2, 'AcropolisCommandPost': 1, 'Generator': 3, 'DomedPalace': 1,
'BridgedBazaar': 1, 'AquaPlane': 1, 'Projectile': 2, 'GorgonShip': 4, 'Deathray': 1, 'Score': 1, 'BanditBomber': 3}
[docs]
class Sentry(GameObject):
"""
The left and right sentry posts.
"""
def __init__(self):
super(Sentry, self).__init__()
self._xy = 0, 124
self.wh = 8, 8
self.rgb = 111, 210, 111
self.hud = False
# No clue how the projectiles work
[docs]
class Projectile(GameObject):
"""
The projectiles shot from the sentry posts or the Acropolis Command Post.
"""
def __init__(self):
super().__init__()
self._xy = 0, 0
self.wh = 1, 1
self.rgb = 184, 70, 162
self.hud = False
[docs]
class AquaPlane(GameObject):
"""
The Aqua Plain district of the city.
"""
def __init__(self):
super(AquaPlane, self).__init__()
self._xy = 16, 171
self.wh = 16, 7
self.rgb = 252, 144, 144
self.hud = False
[docs]
class DomedPalace(GameObject):
"""
The Doomed Palace district of the city.
"""
def __init__(self):
super(DomedPalace, self).__init__()
self._xy = 38, 148
self.wh = 16, 8
self.rgb = 240, 170, 103
self.hud = False
[docs]
class Generator(GameObject):
"""
The three Generator Stations.
"""
def __init__(self):
super(Generator, self).__init__()
self._xy = 62, 137
self.wh = 4, 8
self.rgb = 117, 231, 194
self.hud = False
[docs]
class BridgedBazaar(GameObject):
"""
The Bridged Bazaar district of the city.
"""
def __init__(self):
super(BridgedBazaar, self).__init__()
self._xy = 96, 159
self.wh = 16, 8
self.rgb = 214, 214, 214
self.hud = False
[docs]
class AcropolisCommandPost(GameObject):
"""
The Acropolis Command Post that defends the centre of Atlantis.
"""
def __init__(self):
super(AcropolisCommandPost, self).__init__()
self._xy = 72, 112
self.wh = 8, 8
self.rgb = 227, 151, 89
self.hud = False
[docs]
class BanditBomber(GameObject):
"""
The fast Gorgon Bandit Bombers.
"""
def __init__(self):
super(BanditBomber, self).__init__()
self._xy = 0, 0
self.wh = 9, 7
self.rgb = 125, 48, 173
self.hud = False
[docs]
class GorgonShip(GameObject):
"""
The Large Gorgon Vessels.
"""
def __init__(self):
super(GorgonShip, self).__init__()
self._xy = 0, 0
self.wh = 15, 8
self.rgb = 187, 187, 53
self.hud = False
[docs]
class Deathray(GameObject):
"""
The deathray fired by close Gorgon units.
"""
def __init__(self):
super(Deathray, self).__init__()
self._xy = 0, 92
self.wh = 2, 88
self.rgb = 101, 209, 174
self.hud = False
[docs]
class Score(GameObject):
"""
The player's score display.
"""
def __init__(self):
super(Score, self).__init__()
self._xy = 96, 188
self.wh = 7, 10
self.rgb = 252, 188, 116
self.hud = False
def _init_objects_ram(hud=True):
"""
(Re)Initialize the objects
"""
objects = [Sentry(), Sentry()]
objects[1].xy = 152, 112
objects.extend([None] * 14)
if hud:
objects.extend([None] * 1)
global ray_available
ray_available = True
global buildings_amount
buildings_amount = 7
global prev_x_p1
global prev_x_p2
prev_x_p1 = 0
prev_x_p2 = 0
global vert_proj
vert_proj = None
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)
# Determines whether the deathray can be used by the ships or not
global ray_available
# Saves the previous amount of buildings that are still standing
global buildings_amount
global prev_x_p1
global prev_x_p2
def missile_pos(rs):
if 182 <= rs:
return 201 - rs
elif 164 <= rs:
return 202 - rs
elif 145 <= rs:
return 203 - rs
elif 126 <= rs:
return 204 - rs
elif 114 <= rs:
return 205 - rs
elif 106 <= rs:
return 206 - rs
elif 104 <= rs:
return 207 - rs
else:
return 208 - rs
def _detect_objects_ram(objects, ram_state, hud=True):
for i in range(13):
objects[2+i] = None
buildings_count = 0
global prev_x_p1
global prev_x_p2
if ram_state[58] != 0 and ram_state[60] != 0:
proj = Projectile()
if prev_x_p1 < ram_state[60]:
proj.xy = ram_state[60]-3, missile_pos(ram_state[58])-1
elif prev_x_p1 == ram_state[60]:
proj.xy = ram_state[60], missile_pos(ram_state[58])
else:
proj.xy = ram_state[60]+3, missile_pos(ram_state[58])-1
proj.rgb = (200, 200, 200)
objects[14] = proj
prev_x_p1 = ram_state[60]
if ram_state[59] != 0 and ram_state[61] != 0:
proj = Projectile()
if prev_x_p2 < ram_state[61]:
proj.xy = ram_state[61]-3, missile_pos(ram_state[59])-1
elif prev_x_p2 == ram_state[61]:
# proj.xy = ram_state[61], int(214 - 1.0775 * ram_state[59])
proj.xy = ram_state[61], missile_pos(ram_state[59])
# if 204 - ram_state[59] <= 22:
# proj.xy = ram_state[61], 210 - ram_state[59] - 9
# elif 204 - ram_state[59] <= 32:
# proj.xy = ram_state[61], 210 - ram_state[59] - 8
# elif 204 - ram_state[59] <= 59:
# proj.xy = ram_state[61], 210 - ram_state[59] - 7
# elif 204 - ram_state[59] <= 78:
# proj.xy = ram_state[61], 204 - ram_state[59]
# elif 204 - ram_state[59] < 90:
# proj.xy = ram_state[61], 210 - ram_state[59] - 5
# else:
# proj.xy = ram_state[61], 210 - ram_state[59] - 4
else:
proj.xy = ram_state[61]+3, missile_pos(ram_state[59])-1
objects[15] = proj
prev_x_p2 = ram_state[61]
global ray_available
global buildings_amount
for i in range(4):
if ram_state[36+i]:
ship = _get_ship_type(ram_state, 0+i, 128+i)
g_s = None
if ship is None:
continue
# calc speed and orientation offset
if not ram_state[75+ship]&128:
offset = ram_state[75+ship]
if ram_state[79+ship] == 64:
g_s = GorgonShip()
g_s.xy = ram_state[36+i] - 7 - offset, 82 - 21*i
elif ram_state[79+ship] == 32 or ram_state[79+ship] == 48:
g_s = GorgonShip()
g_s.wh = 15, 7
g_s.xy = ram_state[36+i] - 7 - offset, 83 - 21*i
elif ram_state[79+ship] == 80:
g_s = BanditBomber()
g_s.xy = ram_state[36+i] - 5 - offset, 83 - 21*i
else:
offset = 255 - ram_state[75+ship]
if ram_state[79+ship] == 64:
g_s = GorgonShip()
g_s.xy = ram_state[36+i] - 7 + offset, 82 - 21*i
elif ram_state[79+ship] == 32 or ram_state[79+ship] == 48:
g_s = GorgonShip()
g_s.wh = 15, 7
g_s.xy = ram_state[36+i] - 7 + offset, 83 - 21*i
elif ram_state[79+ship] == 80:
g_s = BanditBomber()
g_s.xy = ram_state[36+i] - 3 + offset, 83 - 21*i
if g_s:
objects[2+i] = g_s
# Deathray can only be shot by ships on lane 4
if not i and ram_state[30] < 152 and ray_available:
ray = Deathray()
if not ram_state[75+ship]&128:
ray.xy = ram_state[36] - 1, 92
else:
ray.xy = ram_state[36] + 1, 92
objects[13] = ray
# Command-Post center building with gun
if ram_state[84] == 0:
objects[6] = AcropolisCommandPost()
buildings_count += 1
# Generator left
if ram_state[22] < 152:
gen = Generator()
gen.xy = 82, 124
gen.rgb = 111, 210, 111
objects[7] = gen
buildings_count += 1
# Generator Command-Post
if ram_state[23] < 152:
objects[8] = Generator()
buildings_count += 1
# Generator right
if ram_state[24] < 152:
gen = Generator()
gen.xy = 142, 137
gen.rgb = 188, 144, 252
objects[9] = gen
buildings_count += 1
# Domed-Palace building with dome
if ram_state[25] < 152:
objects[10] = DomedPalace()
buildings_count += 1
# Bridged-Bazaar rightmost building
if ram_state[26] < 152:
objects[11] = BridgedBazaar()
buildings_count += 1
# Aqua-Plane leftmost building
if ram_state[27] < 152:
objects[12] = AquaPlane()
buildings_count += 1
# Determines if the deathray is usable
if ram_state[30] == 152:
ray_available = True
elif buildings_count < buildings_amount:
ray_available = False
buildings_amount = buildings_count
# global vert_proj
# if ram_state[106]:
# if not vert_proj:
# vert_proj = Projectile()
# vert_proj.rgb = (20, 200, 20)
# objects.append(vert_proj)
# vert_proj._xy = 73, 3 * ram_state[106] + 21
# elif vert_proj:
# if vert_proj in objects:
# objects.remove(vert_proj)
# vert_proj = None
# for oj in objects:
# if isinstance(oj, Projectile):
# xy = oj.xy
# oj.xy = xy[0]-4, xy[1]-8
if hud:
# Score
if ram_state[33] or ram_state[34] or ram_state[35]:
score = Score()
if ram_state[33] >= 16:
score.wh = 15, 10
score.xy = 88, 188
if ram_state[34] > 0:
score.wh = 23, 10
score.xy = 80, 188
if ram_state[34] >= 16:
score.wh = 31, 10
score.xy = 72, 188
if ram_state[35] > 0:
score.wh = 39, 10
score.xy = 64, 188
if ram_state[35] >= 16:
score.wh = 47, 10
score.xy = 56, 188
objects[16] = score
return objects
def _get_ship_type(ram_state, height1, height2):
"""
Determines the type of ship by its sprite index
"""
for i in range(4):
if ram_state[71+i] == height1 or ram_state[71+i] == height2:
return i
return None
def _detect_objects_atlantis_raw(info, ram_state):
"""
Raw ram-slice for playing the game with minimum requirements
"""
enemy_x = ram_state[36:40]
player_projectile = ram_state[58:62]
# score ram_state[33:36]
info["ram_slice"] = enemy_x + player_projectile