Example #1
0
class Scene_Base(QGraphicsScene):
	def __init__(self, window):
		super().__init__()
		self.setSceneRect(0, 0, window.game_width, window.game_height)
		self.window = window
		self.init_fields()
		self.create_fade()
		self.dialog_box = None
		self.setup()

	def init_fields(self):
		self.actions = []
		self.current_action = -1
		self.dialog_box = None
		self.target_text = None
		self.current_dialog_text = None
		self.current_dialog_text_offset = 0
		self.background = None
		self.fading_box = None
		self.fade_dir = 0
		self.next_scene = None
		self.buttons = []
		self.current_id = 1
		self.texts = {}
		self.images = {}
		self.moving_images = []
		self.updatable_images = []
		self.vaxx = None
		self.entry = None
		self.pathogen = None
		self.tempPic = None

	def create_fade(self, opc=1):
		self.fading_box = QGraphicsRectItem(0, 0, self.width(), self.height())
		self.fading_box.setBrush(QColor(0, 0, 0))
		self.fading_box.setOpacity(opc)
		self.fading_box.setZValue(100)
		self.addItem(self.fading_box)

	# ==============================================
	# * Setup
	#
	# Overwrite with child classes to add actions.
	# ==============================================

	def setup(self):
		pass

	# ==============================================
	# * Update
	#
	# Updates the scene. Handles input, waiting, etc.
	# ==============================================

	def update(self):
		self.update_fade()
		self.update_dialog()
		self.update_dialog_text()
		self.update_moving_images()
		self.update_animated_images()

	def update_fade(self):
		if self.fading_box is not None:
			if self.fade_dir == 0 and self.fading_box.opacity() > 0:
				self.fading_box.setOpacity(self.fading_box.opacity() - 0.02)
				if self.fading_box.opacity() <= 0:
					self.removeItem(self.fading_box)
					self.fading_box = None
			elif self.fade_dir == 1 and self.fading_box.opacity() < 1:
				self.fading_box.setOpacity(self.fading_box.opacity() + 0.02)
				if self.fading_box.opacity() >= 1:
					if self.next_scene is not None:
						self.window.goto_scene(self.next_scene)
					else:
						self.actually_close_game()

	def update_dialog(self):
		if self.dialog_box is not None:
			if self.dialog_box.opacity() < 0.5:
				self.dialog_box.setOpacity(self.dialog_box.opacity() + 0.04)
				if self.dialog_box.opacity() >= 0.5:
					self.dialog_box.setOpacity(0.5)
					if self.actions[0][0] == 0:
						self.actually_show_dialog(self.actions[0])

	def update_dialog_text(self):
		if self.current_dialog_text is not None:
			curr_text = self.current_dialog_text.toPlainText()
			if curr_text != self.target_text:
				if self.current_dialog_text_offset < 3:
					self.current_dialog_text_offset += 1
				else:
					self.current_dialog_text_offset = 0
					self.current_dialog_text.setPlainText(self.target_text[:len(curr_text) + 1])

	def update_moving_images(self):
		if len(self.moving_images) > 0:
			index = 0
			new_data = []
			for image in self.moving_images:
				pic_id = image[0]
				item = self.images[pic_id]
				item.setX(item.x() + image[1])
				item.setY(item.y() + image[2])
				image[3] -= 1
				if image[3] > 0:
					new_data.append(image)
				elif image[4] is not None:
					image[4]()
				index += 1

			self.moving_images = new_data

	def update_animated_images(self):
		if len(self.updatable_images) > 0:
			index = 0
			for image in self.updatable_images:
				image[2] += 1
				if image[2] > image[4]:
					image[2] = 0
					image[3] += 1
					if image[3] >= len(image[1]):
						image[3] = 0
					image[0].setPixmap(QPixmap(image[1][image[3]]))


	# ==============================================
	# * Mouse Events
	#
	# Handle mouse input.
	# ==============================================

	def mouseMoveEvent(self, mouseEvent):
		pass

	def mousePressEvent(self, mouseEvent):
		self.when_mouse_pressed(mouseEvent)

	def mouseDoubleClickEvent(self, mouseEvent):
		self.when_mouse_pressed(mouseEvent)

	def when_mouse_pressed(self, mouseEvent):
		if self.current_action == 0 and mouseEvent.button() == 1:
			if self.current_dialog_text is not None:
				if self.current_dialog_text.toPlainText() != self.target_text:
					self.current_dialog_text.setPlainText(self.target_text)
				else:
					self.removeItem(self.current_dialog_text)
					self.call_next_action()
		else:
			super(Scene_Base, self).mousePressEvent(mouseEvent)

	# ==============================================
	# * Action Management
	# ==============================================

	def finish_action(self):
		if len(self.actions) > 0:
			self.actions.pop(0)
		else:
			self.wait_for_button_press()

	def check_if_first(self):
		if len(self.actions) == 1:
			self.perform_next_action()

	def perform_next_action(self):
		if len(self.actions) > 0:
			action = self.actions[0]
			self.current_action = action_type = action[0]

			if action_type is -1:
				self.actually_hide_dialog_box()
			elif action_type is 0:
				self.actually_show_dialog(action)
			elif action_type is 1:
				self.actually_show_button(action)
			elif action_type is 2:
				self.actually_set_background(action)
			elif action_type is 3:
				self.actually_goto_scene(action)
			elif action_type is 4:
				self.actually_close_game()
			elif action_type is 5:
				self.actually_play_song(action)
			elif action_type is 6:
				self.actually_wait_for_button_press()
			elif action_type is 7:
				self.actually_remove_all_buttons()
			elif action_type is 8:
				self.actually_show_text(action)
			elif action_type is 9:
				self.actually_hide_text(action)
			elif action_type is 10:
				self.actually_show_image(action)
			elif action_type is 11:
				self.actually_hide_image(action)
			elif action_type is 12:
				self.actually_move_image(action)
			elif action_type is 50:
				self.actually_play_sound(action)

	def call_next_action(self):
		self.finish_action()
		self.perform_next_action()

	# ==============================================
	# * Actual Implementations
	# ==============================================

	def actually_show_dialog(self, data):
		if self.dialog_box is None:
			self.create_dialog_box()
		else:
			self.current_dialog_text = QGraphicsTextItem()
			self.current_dialog_text.setZValue(20)
			self.current_dialog_text.setDefaultTextColor(QColor(255, 255, 255))

			temp_font = self.current_dialog_text.font()
			temp_font.setPointSize(data[2])
			self.current_dialog_text.setFont(temp_font)

			self.addItem(self.current_dialog_text)
			self.current_dialog_text.setX(self.dialog_box.x() + 10)
			self.current_dialog_text.setY(self.dialog_box.y() + 10)
			self.current_dialog_text.setTextWidth(self.dialog_box.boundingRect().width() - 20)

			self.target_text = data[1]
			self.current_dialog_text_offset = 0

	def create_dialog_box(self):
		self.dialog_box = QGraphicsRectItem(0, 0, self.width() - 20, self.height() / 4)
		self.dialog_box.setBrush(QColor(0, 0, 0))
		self.dialog_box.setX(10)
		self.dialog_box.setY(self.height() - self.dialog_box.boundingRect().height() - 10)
		self.dialog_box.setZValue(15);
		self.dialog_box.setOpacity(0)
		self.addItem(self.dialog_box)

	def actually_hide_dialog_box(self):
		if self.dialog_box is not None:
			self.removeItem(self.dialog_box)
			self.dialog_box = None

	def actually_show_button(self, data):
		button = Button(self, data[3], data[4], data[5], data[6], data[7], data[8], data[9])
		button.setX(data[1])
		button.setY(data[2])
		self.buttons.append(button)
		self.addItem(button)
		self.call_next_action()

	def actually_set_background(self, data):
		if self.background is not None:
			self.removeItem(self.background)
			self.background = None

		self.background = QGraphicsPixmapItem(QPixmap(data[1]).scaled(self.window.game_width, self.window.game_height))
		self.background.setZValue(-10)
		self.addItem(self.background)
		self.call_next_action()

	def actually_goto_scene(self, data):
		self.next_scene = data[1]
		self.fade_dir = 1
		self.create_fade(0)

	def actually_close_game(self):
		self.window.close_game()

	def actually_play_song(self, data):
		AudioPlayer.play_song(data[1])
		self.call_next_action()

	def actually_wait_for_button_press(self):
		self.current_action = -1

	def actually_remove_all_buttons(self):
		for b in self.buttons:
			self.removeItem(b)
		self.buttons = []
		self.call_next_action()

	def actually_show_text(self, data):
		text_item = QGraphicsTextItem()
		text_item.setZValue(5)
		if len(data) >= 8 and data[7] != None:
			text_item.setDefaultTextColor(QColor(data[7]))
		else:
			text_item.setDefaultTextColor(QColor("#FFFFFF"))

		text_item.setX(data[2])
		text_item.setY(data[3])
		text_item.setTextWidth(data[4])
		text_item.setPlainText(data[5])

		temp_font = text_item.font()
		temp_font.setPointSize(data[6])
		text_item.setFont(temp_font)

		self.addItem(text_item)
		self.texts[data[1]] = text_item
		self.call_next_action()

	def actually_hide_text(self, data):
		self.removeItem(self.texts[data[1]])
		self.texts[data[1]] = None
		self.call_next_action()

	def actually_show_image(self, data):
		image = None
		if isinstance(data[2], list):
			image = QGraphicsPixmapItem(QPixmap(data[2][0]))
			self.updatable_images.append([image, data[2], 0, 0, data[5]])
		else:
			image = QGraphicsPixmapItem(QPixmap(data[2]))
		image.setX(data[3])
		image.setY(data[4])
		image.setZValue(0)
		self.addItem(image)
		self.images[data[1]] = image
		self.call_next_action()

	def actually_hide_image(self, data):
		self.removeItem(self.images[data[1]])
		self.images[data[1]] = None
		self.call_next_action()

	def actually_move_image(self, data):
		image_id = data[1]
		image = self.images[image_id]
		duration = data[4]
		x_speed = (data[2] - image.x()) / duration
		y_speed = (data[3] - image.y()) / duration
		callback = self.call_next_action if data[5] else None
		image_data = [image_id, x_speed, y_speed, duration, callback]
		self.moving_images.append(image_data)
		if not data[5]:
			self.call_next_action()

	def actually_play_sound(self, data):
		AudioPlayer.play_sound_effect(data[1])
		self.call_next_action()

	# ==============================================
	# * Setup Calls
	# ==============================================

	def add_call(self, data):
		self.actions.append(data)
		self.check_if_first()

	# ==============================================
	# * Extended Calls
	# ==============================================

	# ==============================================
	# Adds a dialog to the game.
	#
	# Ex:
	#     self.add_dialog("Hello World!")
	# ==============================================
	def add_dialog(self, msg, fontSize=20):
		self.add_call([0, msg, fontSize])

	# ==============================================
	# Hides the dialog box
	#
	# Ex:
	#     self.hide_dialog_box()
	# ==============================================
	def hide_dialog_box(self):
		self.add_call([-1])

	# ==============================================
	# Adds a button to the game.
	# After adding all buttons, be sure to call "self.wait_for_button_press".
	# Check scenes/scene_titlescreen.py for example of "font" and "buttonColors"
	#
	# Ex:
	#     self.add_button(30, 30, 200, 200, "My Button!", self.another_function)
	# ==============================================
	def add_button(self, x, y, w, h, name, action, font=None, buttonColors=None, textColors=None):
		self.add_call([1, x, y, w, h, name, font, buttonColors, textColors, action])

	# ==============================================
	# Sets the current background.
	#
	# Ex:
	#     self.set_background("images/Background1.png")
	# ==============================================
	def set_background(self, path):
		self.add_call([2, path])

	# ==============================================
	# Changes the game to the provided scene.
	#
	# Ex:
	#     self.goto_scene(scenes.my_other_scene.My_Other_Scene)
	# ==============================================
	def goto_scene(self, scene):
		self.add_call([3, scene])

	# ==============================================
	# Closes the game.
	#
	# Ex:
	#     self.close_game()
	# ==============================================
	def close_game(self):
		self.add_call([4])

	# ==============================================
	# Plays a song.
	#
	# Ex:
	#     self.play_song("audio/testmusic2.mp3")
	# ==============================================
	def play_song(self, path):
		self.add_call([5, path])

	# ==============================================
	# Plays a sound effect once.
	#
	# Ex:
	#     self.play_sound("audio/testmusic2.mp3")
	# ==============================================
	def play_sound(self, path):
		self.add_call([50, path])

	# ==============================================
	# Once all buttons are created, this will wait for the player to press one.
	#
	# Ex:
	#     self.wait_for_button_press()
	# ==============================================
	def wait_for_button_press(self):
		self.add_call([6])

	# ==============================================
	# Removes all buttons from the screen.
	#
	# Ex:
	#     self.remove_all_buttons()
	# ==============================================
	def remove_all_buttons(self):
		self.add_call([7])

	# ==============================================
	# Based on the value provided, there is a chance it will return True.
	#
	# Ex:
	#     if self.generate_random_chance(30):
	#		  # there is a 30% chance of this happening
	# 	  else:
	#		  # there is a 70% chance of this happening
	# ==============================================
	def generate_random_chance(self, val):
		return random.randint(0, 100) <= val

	# ==============================================
	# Shows text on the screen (not in dialog).
	# This function returns an ID that can be used in self.hide_text.
	#
	# Ex:
	#     text_id = self.show_text(10, 10, 200, "Hello Screen!", 40, "#FF44CC")
	# ==============================================
	def show_text(self, x, y, w, text, size=30, color=None):
		new_id = self.current_id
		self.current_id += 1
		self.add_call([8, new_id, x, y, w, text, size, color])
		return new_id

	# ==============================================
	# Hides the text connected to the ID.
	#
	# Ex:
	#     self.hide_text(text_id)
	# ==============================================
	def hide_text(self, text_id):
		self.add_call([9, text_id])

	# ==============================================
	# Shows a picture on the screen.
	# This function returns an ID that can be used in other functions.
	#
	# Ex:
	#     pic_id = self.show_picture("images/TestImage1.png", 30, 30)
	#
	# ----------------------------------------------
	#
	# Using an array of strings will create an animation.
	# In that case, the last argument is the frame-change frequency of the animation.
	#
	# Ex:
	#     pic_id = self.show_picture(["images/p1_frame_0.png", "images/p1_frame_1.png"], 100, 100, 30)
	# ==============================================
	def show_picture(self, path, x, y, animation_speed=20):
		new_id = self.current_id
		self.current_id += 1
		self.add_call([10, new_id, path, x, y, animation_speed])
		return new_id

	# ==============================================
	# Removes the picture connected to the provided ID.
	#
	# Ex:
	#     self.hide_picture(pic_id)
	# ==============================================
	def hide_picture(self, image_id):
		self.add_call([11, image_id])

	# ==============================================
	# Moves the picture to new coordinates over a duration of time.
	#
	# Ex:
	#     self.move_picture(pic_id, 90, 30, 120)
	# ==============================================
	def move_picture(self, image_id, x, y, duration, wait_until_finished=True):
		self.add_call([12, image_id, x, y, duration, wait_until_finished])

	#===============================================
	# Sets the vaccination status
	# True/False, 50% chance
	#===============================================
	def set_vaxx(self):
		if self.generate_random_chance(50):
			Scene_Base.vaxx = True
		else:
			Scene_Base.vaxx = False

	#===============================================
	# Sets the entry point
	# 0 is for blood (cut)
	# 1 is for stomach (mouth)
	#===============================================	
	def set_entry(self):
		if self.generate_random_chance(50):
			Scene_Base.entry = 0
		else:
			Scene_Base.entry = 1

	# ==============================================
	# Gets and sets global values
	#
	# Ex:
	#     self.set_value("Health", 100)
	#
	#     self.add_value("Health", -1)
	#
	#     if self.get_value("Health") <= 30:
	#         self.add_dialog("Player is less than 30 health!")
	# ==============================================
			
	def set_value(self, name, value):
		Scene_Base.GLOBAL_VARS[name] = value

	def add_value(self, name, value):
		Scene_Base.GLOBAL_VARS[name] += value

	def get_value(self, name):
		return Scene_Base.GLOBAL_VARS[name]