Well, I just made a simulation in pygame (python 2). No idea why. Because it's fun, I guess. I feel like I have something pretty close to the original now.
Code: Select all
import pygame
import math
pygame.init()
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 600
FPS = 30
GRID_SIZE = 40
all_rooms = []
all_doors = []
GRID_WIDTH = 20
GRID_HEIGHT = 13
WALL_THICKNESS = 2
gameDisplay = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
pygame.display.set_caption("Oxygen")
gameState = "playing"
oxygenPower = 1
class Door(object):
def __init__(self, roomA, roomB=None, position=(0,0,0,1), startOpen=False):
global all_doors
super(Door, self).__init__()
all_doors.append(self)
self.roomA = roomA
self.roomB = roomB
self.position = position #(x, y, w, h) in relation to roomA x, y, dimensions
self.open = startOpen
def getRenderCoords(self):
shape = (8, 30)
if self.position[2] == 0: #vertical
w, h = shape
x = (self.roomA.x+self.position[0])*GRID_SIZE - w/2.0
y = (self.roomA.y+self.position[1])*GRID_SIZE + (GRID_SIZE - h)/2.0
else: #horizontal
w, h = reversed(shape)
x = (self.roomA.x+self.position[0])*GRID_SIZE + (GRID_SIZE - w)/2.0
y = (self.roomA.y+self.position[1])*GRID_SIZE - h/2.0
return (x, y, w, h)
def getColour(self):
if self.open:
return (255, 200, 150)
else:
return (255, 100, 0)
def tick(self):
if self.open:
if self.roomB != None:
oxygenB = self.roomB.oxygen
else:
oxygenB = -500
self.roomA.oxygen, oxygenB = distributeOxygen(self.roomA.oxygen, oxygenB)
if self.roomB != None:
self.roomB.oxygen = oxygenB
class Room(object):
def __init__(self, x, y, dimensions=(1,1)):
global all_rooms
super(Room, self).__init__()
all_rooms.append(self)
self.x = x #coords on the grid, not screen
self.y = y
self.dimensions = dimensions
self.oxygen = 100.0
self.breaches = 0
def getSize(self, dimension):
return self.dimensions[dimension]
def getColour(self):
return (255,round(2.55*self.oxygen),round(2.55*self.oxygen))
def getTileCount(self):
return self.dimensions[0] * self.dimensions[1]
def getBreachPos(self, n):
return (n%self.getSize(0), n/self.getSize(1))
def tick(self):
self.oxygen -= 0.05
for i in range(self.breaches):
self.oxygen, _ = distributeOxygen(self.oxygen, 0.0)
self.oxygen += (160 - self.oxygen) * oxygenPower / 700
self.oxygen = max(min(self.oxygen, 100.0), 0.0)
def distributeOxygen(oxygenA, oxygenB):
rate = 40.0
minChange = 0.1
minOxygen = 0.0
difference = abs(oxygenA - oxygenB)
if oxygenA < oxygenB:
sign = -1
else:
sign = 1
change = min(max(difference / rate, minChange), difference/2.0)
oxygenA -= sign*change
oxygenB += sign*change
if oxygenA < minOxygen:
oxygenA = minOxygen
if oxygenB < minOxygen:
oxygenB = minOxygen
return oxygenA, oxygenB
def averageOxygen():
totalOxygen = 0.0
for room in all_rooms:
totalOxygen += room.oxygen
return totalOxygen / len(all_rooms)
def addBreach(x, y, amount):
global all_rooms
for i in xrange(len(all_rooms)):
room = all_rooms[i]
if x < room.x+room.getSize(0) and x >= room.x and y < room.y+room.getSize(1) and y >= room.y:
all_rooms[i].breaches = max(min(all_rooms[i].breaches+amount, room.getTileCount()), 0)
def toggleDoor(x, y, newState=None):
for door in all_doors:
doorX, doorY, doorW, doorH = door.getRenderCoords()
if x < doorX+doorW and x >= doorX and y < doorY+doorH and y >= doorY:
if newState == None:
door.open = not door.open
else:
door.open = newState
return True
return False
def toggleAllDoors(newState):
if newState == True:
openAirlocks = True
for door in all_doors:
if door.open == False and door.roomB != None:
openAirlocks = False
break
for door in all_doors:
if door.roomB != None or openAirlocks == True:
door.open = True
else:
for door in all_doors:
door.open = False
def canPlace(x, y, dimensions=(1,1)):
w = dimensions[0]
h = dimensions[1]
if x+w > GRID_WIDTH or y+h > GRID_HEIGHT:
print "Outside border"
return False
for room in all_rooms:
if room.x+room.getSize(0) > x and x+w > room.x and room.y+room.getSize(1) > y and y+h > room.y:
return False
return True
def addOxygen(amount):
global oxygenPower
oxygenPower = max(oxygenPower + amount, 0)
def newGame():
for room in ((4,4), (4,6), (4,8), (6,4), (6,6), (6,8)):
new_room = Room(room[0],room[1], (2,2))
Door(all_rooms[0])
Door(all_rooms[1], all_rooms[0], (0,0,1,0))
Door(all_rooms[1], all_rooms[0], (1,0,1,0))
Door(all_rooms[2], all_rooms[1], (1,0,1,0))
Door(all_rooms[3], all_rooms[0], (0,1,0,1))
Door(all_rooms[3], all_rooms[0], (0,0,0,1))
Door(all_rooms[4], all_rooms[3], (1,0,1,0))
Door(all_rooms[4], all_rooms[1], (0,0,0,1))
Door(all_rooms[5], all_rooms[2], (0,0,0,1))
Door(all_rooms[5], all_rooms[4], (0,0,1,0))
Door(all_rooms[5], all_rooms[4], (1,0,1,0))
Door(all_rooms[4], position=(2,0,0,1))
Door(all_rooms[4], position=(2,1,0,1))
Door(all_rooms[5], position=(2,0,0,1))
Door(all_rooms[3], position=(2,0,0,1))
Door(all_rooms[2], position=(1,2,1,0))
playGame()
def playGame():
global gameState
clock = pygame.time.Clock()
iteration = 0
while not gameState=="quitting":
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameState = "quitting"
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_z:
toggleAllDoors(True)
elif event.key == pygame.K_x:
toggleAllDoors(False)
elif event.key == pygame.K_a:
addOxygen(-1)
elif event.key == pygame.K_s:
addOxygen(1)
elif event.key == pygame.K_SPACE:
if gameState == "playing":
gameState = "paused"
else:
gameState = "playing"
elif event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
if event.button == 3: #rightclick
if x < GRID_SIZE*GRID_WIDTH and y < GRID_SIZE*GRID_HEIGHT:
x = x/GRID_SIZE
y = y/GRID_SIZE
if canPlace(x, y, (2,2)):
Room(x, y, (2,2))
else:
addBreach(x, y, 1)
if event.button == 1: #leftclick
if x < GRID_SIZE*GRID_WIDTH and y < GRID_SIZE*GRID_HEIGHT:
if not toggleDoor(x, y):
x = x/GRID_SIZE
y = y/GRID_SIZE
addBreach(x, y, -1)
if gameState == "playing":
for room in all_rooms:
room.tick()
for door in all_doors:
door.tick()
renderGame()
clock.tick(FPS)
def renderGame():
gameDisplay.fill((55,55,55))
gameDisplay.fill((0,0,0), rect=[0, DISPLAY_HEIGHT-80, DISPLAY_WIDTH, 80])
for room in all_rooms:
gameDisplay.fill((0,0,0), rect=[room.x*GRID_SIZE, room.y*GRID_SIZE, room.getSize(0)*GRID_SIZE, room.getSize(1)*GRID_SIZE])
gameDisplay.fill(room.getColour(), rect=[room.x*GRID_SIZE+WALL_THICKNESS, room.y*GRID_SIZE+WALL_THICKNESS, room.getSize(0)*GRID_SIZE-2*WALL_THICKNESS, room.getSize(1)*GRID_SIZE-2*WALL_THICKNESS])
for breach in range(room.breaches):
(breach_x, breach_y) = room.getBreachPos(breach)
gameDisplay.fill((25,35,55), rect=[(room.x+0.25+breach_x)*GRID_SIZE, (room.y+0.25+breach_y)*GRID_SIZE, 0.5*GRID_SIZE, 0.5*GRID_SIZE])
for door in all_doors:
gameDisplay.fill(door.getColour(), rect=door.getRenderCoords())
text(DISPLAY_WIDTH/2, DISPLAY_HEIGHT-40, "Oxygen Power: %i Average Oxygen: %f"%(oxygenPower,averageOxygen()), colour=(0,255,0))
if gameState == "paused":
text(DISPLAY_WIDTH/2, DISPLAY_HEIGHT-60, "PAUSED", colour=(255,255,255))
pygame.display.update()
def text(x, y, text, colour=(255,255,255), size=25, w=0, h=0):
textSurface = get_msg(text, colour, size)
textRect = textSurface.get_rect()
textRect.center = x, y+h/4
gameDisplay.blit(textSurface, textRect)
cache = {}
def get_msg(msg, colour, size):
if not size in cache:
cache[size] = {}
if not colour in cache[size]:
cache[size][colour] = {}
if not msg in cache[size][colour]:
fontobj = pygame.font.Font("arial.ttf", size)
cache[size][colour][msg] = fontobj.render(msg, False , colour)
return cache[size][colour][msg]
newGame()
pygame.quit()
quit()