Added zombieData

Added zombieData

extends Node

#get_node("/root/global").enteringOS   <--This is the proper method to quit to desktop.
#get_node("/root/global").enteringMenu  <--This is the proper method to get to the main menu.
#get_node("/root/global").currentDifficulty  <--This is the proper method to get the difficulty.

#Time based variables.
#var eclipseRatio = null

#Player stuff.
var playerScore = null
var playerTime = null
var playerDifficulty = null #This has to be between 0 and 3 to match the size of xSizeArray and ySizeArray.
#var specialAbilityAmmo = null
var tombArray = []
var tombOrigen = null
var tombs = null
var tombNumberTotal = 0
var zombieData = []
var xSizeArray = [3, 3, 4, 6] #[Easy, Normal, Hard, Insane]
var ySizeArray = [1, 2, 3, 3] #[Easy, Normal, Hard, Insane]
var playerHealth = [3, 3, 3, 3] #[Easy, Normal, Hard, Insane]
var voidTombs = [0, 1, 2, 3] #[Easy, Normal, Hard, Insane] These tomb placeholders do not have any zombies coming up.
var howDiedTombCount = 3 #this is a count of the number of different flavor texts that go on tombstones.
var xTombSpacing = null
var yTombSpacing = null
var tombStyle = null
var tombList = []
var time
var zombieTime = {}

#var tombArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ",", ".", "_", "-"]

func _ready():
	get_scene().set_auto_accept_quit(false) #Enables: _notification(what) to recieve MainLoop.NOTIFICATION_WM_QUIT_REQUEST
	set_process(true) #Enables: _process(delta) to run every frame.
	playerDifficulty = get_node("/root/global").currentDifficulty

	tombs = get_node("tombs")
	xTombSpacing = 200
	yTombSpacing = 175

	#for g in range(glyphArray.size()):
	#	n = load("res://scene/getNameGlyph.xscn").instance()
	#	glyph.add_child(n)

	tombArray.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		tombArray.append([])
		for y in range(ySizeArray[playerDifficulty]):
			tombArray[x].append(load("res://scene/zombiesGoTomb.xscn").instance())
			#print("Hello World " + str(x) + ", " + str(y))
			#MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM
			tombArray[x][y].set_margin(MARGIN_LEFT, 1280/2 - xSizeArray[playerDifficulty]*xTombSpacing/2 + x * xTombSpacing + floor(rand_range( -xTombSpacing*.2, xTombSpacing*.2)))
			tombArray[x][y].set_margin(MARGIN_TOP, 720/2 - ySizeArray[playerDifficulty]*yTombSpacing/2  + y * yTombSpacing)
			tombs.add_child(tombArray[x][y])

	#Init settings for round.
	#eclipseRatio = (difficulty - 1) * 0.2
	playerScore = 0
	playerTime = 0
	#specialAbilityAmmo = 0

	#Create List
	tombList.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			tombList.append(tombArray[x][y])

			#tombStyle = floor(rand_range( 0, 3)) #If floor ever returns the high value, it will be a bug on this line.
			#tombArray[x][y].get_node("normalTomb").show()
			#tombArray[x][y].get_node("backHole").show()
			#tombArray[x][y].get_node("frontHole").show()

	for c in range(playerHealth[playerDifficulty]): #Make normal tombs for player health.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("normalTomb").show()
		tombList[i].get_node("frontHole").show()
		tombList[i].get_node("backHole").show()
		#tombList[i].get_node("rubbleHole").show()
		tombList.remove(i)

	for c in range(voidTombs[playerDifficulty]): #Make voild tombs.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("rubbleHole").show()
		tombList.remove(i)

	for i in range(tombList.size()): #Make the rest of the tombs.
		var r = floor(rand_range(0, 2))
		if r == 0:
			tombList[i].get_node("brokenTomb").show()
			tombList[i].get_node("frontHole").show()
			tombList[i].get_node("backHole").show()
			#tombList[i].get_node("rubbleHole").show()
		elif r == 1:
			tombList[i].get_node("missingTomb").show()
			tombList[i].get_node("frontHole").show()
			tombList[i].get_node("backHole").show()
			#tombList[i].get_node("rubbleHole").show()
		else:
			pass

	data.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			data.append({node:tombArray[x][y], zombieTime:2})

func _notification(what):
	if (what==MainLoop.NOTIFICATION_WM_QUIT_REQUEST):
		#Submit current game and save highArray before exiting.
		get_node("/root/global").enteringOS = true
		get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _process(delta):
	#This is ran every frame.
	#get_node("/root/global").timeString(time)
	playerTime = playerTime + delta
	get_node("displayPlayerTimeOnScreen").set_text(get_node("/root/global").timeString(playerTime))
	time = int(floor(playerTime))

	if playerDifficulty == 3:
		#isDied()= true
		pass

	for c in range(size(data{})): #Temporarily make all zombies show.
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("zombieNormal").show()
		#if time <= 2:
		#	zombieMove() = true
		#else:
		#	zombieMove() = false

func _on_backGround_pressed():
	#Submit current game and save highArray before ending round.
	#updateHighScore(score, time)
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _on_frontGround_pressed():
	#Submit current game and save highArray before ending round.
	#updateHighScore(score, time)
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func isDied():
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(playerScore, playerTime)

func zombieMove(): #Now move zombies up, then down.  Use zombieTime.
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			#MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM
			if time % 2 > 0.5:
				#This one runs second.
				tombArray[x][y].get_node("zombieNormal").set_margin(MARGIN_TOP, tombArray[x][y].get_node("zombieNormal").get_margin(MARGIN_TOP)+1)
			else:
				#This one runs first.
				tombArray[x][y].get_node("zombieNormal").set_margin(MARGIN_TOP, tombArray[x][y].get_node("zombieNormal").get_margin(MARGIN_TOP)-1)
	if time > 2:
		return

func getIndexFromNode(node):
	#Search data[] for this node.
	return i

extends Node

#get_node("/root/global").enteringOS   <--This is the proper method to quit to desktop.
#get_node("/root/global").enteringMenu  <--This is the proper method to get to the main menu.
#get_node("/root/global").currentDifficulty  <--This is the proper method to get the difficulty.

#Time based variables.
#var eclipseRatio = null

#Player stuff.
var playerScore = null
var playerTime = null
var playerDifficulty = null #This has to be between 0 and 3 to match the size of xSizeArray and ySizeArray.
#var specialAbilityAmmo = null
var tombArray = []
var tombOrigen = null
var tombs = null
var tombNumberTotal = 0
var xSizeArray = [3, 3, 4, 6] #[Easy, Normal, Hard, Insane]
var ySizeArray = [1, 2, 3, 3] #[Easy, Normal, Hard, Insane]
var playerHealth = [3, 3, 3, 3] #[Easy, Normal, Hard, Insane]
var voidTombs = [0, 1, 2, 3] #[Easy, Normal, Hard, Insane] These tomb placeholders do not have any zombies coming up.
var howDiedTombCount = 3 #this is a count of the number of different flavor texts that go on tombstones.
var xTombSpacing = null
var yTombSpacing = null
var tombStyle = null
var tombList = []
var time

#var tombArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ",", ".", "_", "-"]

func _ready():
	get_scene().set_auto_accept_quit(false) #Enables: _notification(what) to recieve MainLoop.NOTIFICATION_WM_QUIT_REQUEST
	set_process(true) #Enables: _process(delta) to run every frame.
	playerDifficulty = get_node("/root/global").currentDifficulty

	tombs = get_node("tombs")
	xTombSpacing = 200
	yTombSpacing = 175

	#for g in range(glyphArray.size()):
	#	n = load("res://scene/getNameGlyph.xscn").instance()
	#	glyph.add_child(n)

	tombArray.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		tombArray.append([])
		for y in range(ySizeArray[playerDifficulty]):
			tombArray[x].append(load("res://scene/zombiesGoTomb.xscn").instance())
			#print("Hello World " + str(x) + ", " + str(y))
			#MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM
			tombArray[x][y].set_margin(MARGIN_LEFT, 1280/2 - xSizeArray[playerDifficulty]*xTombSpacing/2 + x * xTombSpacing + floor(rand_range( -xTombSpacing*.2, xTombSpacing*.2)))
			tombArray[x][y].set_margin(MARGIN_TOP, 720/2 - ySizeArray[playerDifficulty]*yTombSpacing/2  + y * yTombSpacing)
			tombs.add_child(tombArray[x][y])

	#Init settings for round.
	#eclipseRatio = (difficulty - 1) * 0.2
	playerScore = 0
	playerTime = 0
	#specialAbilityAmmo = 0

	#Create List
	tombList.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			tombList.append(tombArray[x][y])

			#tombStyle = floor(rand_range( 0, 3)) #If floor ever returns the high value, it will be a bug on this line.
			#tombArray[x][y].get_node("normalTomb").show()
			#tombArray[x][y].get_node("backHole").show()
			#tombArray[x][y].get_node("frontHole").show()

	for c in range(playerHealth[playerDifficulty]): #Make normal tombs for player health.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("normalTomb").show()
		tombList[i].get_node("frontHole").show()
		tombList[i].get_node("backHole").show()
		#tombList[i].get_node("rubbleHole").show()
		tombList.remove(i)

	for c in range(voidTombs[playerDifficulty]): #Make voild tombs.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("rubbleHole").show()
		tombList.remove(i)

	for i in range(tombList.size()): #Make the rest of the tombs.
		var r = floor(rand_range(0, 2))
		if r == 0:
			tombList[i].get_node("brokenTomb").show()
			tombList[i].get_node("frontHole").show()
			tombList[i].get_node("backHole").show()
			#tombList[i].get_node("rubbleHole").show()
		elif r == 1:
			tombList[i].get_node("missingTomb").show()
			tombList[i].get_node("frontHole").show()
			tombList[i].get_node("backHole").show()
			#tombList[i].get_node("rubbleHole").show()
		else:
			pass

	tombList.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			tombList.append(tombArray[x][y])

func _notification(what):
	if (what==MainLoop.NOTIFICATION_WM_QUIT_REQUEST):
		#Submit current game and save highArray before exiting.
		get_node("/root/global").enteringOS = true
		get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _process(delta):
	#This is ran every frame.
	#get_node("/root/global").timeString(time)
	playerTime = playerTime + delta
	get_node("displayPlayerTimeOnScreen").set_text(get_node("/root/global").timeString(playerTime))
	if playerDifficulty == 3:
		#isDied()= true
		pass

	for c in range(playerHealth[playerDifficulty]): #Temporarily make all zombies show.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("zombieNormal").show()

	#Now move zombies.
	time = int(floor(playerTime))
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			#MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM
			if time % 2 > 0.5:
				tombArray[x][y].get_node("zombieNormal").set_margin(MARGIN_TOP, tombArray[x][y].get_node("zombieNormal").get_margin(MARGIN_TOP)+1)
			else:
				tombArray[x][y].get_node("zombieNormal").set_margin(MARGIN_TOP, tombArray[x][y].get_node("zombieNormal").get_margin(MARGIN_TOP)-1)

func _on_backGround_pressed():
	#Submit current game and save highArray before ending round.
	#updateHighScore(score, time)
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _on_frontGround_pressed():
	#Submit current game and save highArray before ending round.
	#updateHighScore(score, time)
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func isDied():
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(playerScore, playerTime)


Made notes on playerHealth and voidTombs

Change playerHealth and voidTombs to arrays like xSizeArray.

extends Node

#get_node("/root/global").enteringOS   <--This is the proper method to quit to desktop.
#get_node("/root/global").enteringMenu  <--This is the proper method to get to the main menu.
#get_node("/root/global").currentDifficulty  <--This is the proper method to get the difficulty.

#Time based variables.
#var eclipseRatio = null

#Player stuff.
var playerScore = null
var playerTime = null
var playerDifficulty = null #This has to be between 0 and 3 to match the size of xSizeArray and ySizeArray.
var playerHealth = null
#var specialAbilityAmmo = null
var tombArray = []
var tombOrigen = null
var tombs = null
var tombNumberTotal = 0
var xSizeArray = [3, 3, 4, 6] #[Easy, Normal, Hard, Insane]
var ySizeArray = [1, 2, 3, 3] #[Easy, Normal, Hard, Insane]
var howDiedTombCount = 3 #this is a count of the number of different flavor texts that go on tombstones.
var xTombSpacing = null
var yTombSpacing = null
var tombStyle = null
var tombList = []
var voidTombs = null #These tomb placeholders do not have any zombies coming up.

#var tombArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ",", ".", "_", "-"]

func _ready():
	get_scene().set_auto_accept_quit(false) #Enables: _notification(what) to recieve MainLoop.NOTIFICATION_WM_QUIT_REQUEST
	set_process(true) #Enables: _process(delta) to run every frame.
	playerDifficulty = get_node("/root/global").currentDifficulty

	tombs = get_node("tombs")
	xTombSpacing = 200
	yTombSpacing = 175

	#for g in range(glyphArray.size()):
	#	n = load("res://scene/getNameGlyph.xscn").instance()
	#	glyph.add_child(n)

	tombArray.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		tombArray.append([])
		for y in range(ySizeArray[playerDifficulty]):
			tombArray[x].append(load("res://scene/zombiesGoTomb.xscn").instance())
			#print("Hello World " + str(x) + ", " + str(y))
			#MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM
			tombArray[x][y].set_margin(MARGIN_LEFT, 1280/2 - xSizeArray[playerDifficulty]*xTombSpacing/2 + x * xTombSpacing + floor(rand_range( -xTombSpacing*.2, xTombSpacing*.2)))
			tombArray[x][y].set_margin(MARGIN_TOP, 720/2 - ySizeArray[playerDifficulty]*yTombSpacing/2  + y * yTombSpacing)
			tombs.add_child(tombArray[x][y])

	#Init settings for round.
	#eclipseRatio = (difficulty - 1) * 0.2
	playerScore = 0
	playerTime = 0
	#specialAbilityAmmo = 0
	if playerDifficulty == 0: #Convert player health to an array like xSizeArray.
		playerHealth = 3
		voidTombs = 0 #Convert void tombs to an array like xSizeArray.
	if playerDifficulty == 1:
		playerHealth = 3
		voidTombs = 1
	if playerDifficulty == 2:
		playerHealth = 3
		voidTombs = 2
	if playerDifficulty == 3:
		playerHealth = 3
		voidTombs = 3

	#Create List
	tombList.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			tombList.append(tombArray[x][y])

			#tombStyle = floor(rand_range( 0, 3)) #If floor ever returns the high value, it will be a bug on this line.
			#tombArray[x][y].get_node("normalTomb").show()
			#tombArray[x][y].get_node("backHole").show()
			#tombArray[x][y].get_node("frontHole").show()

	for c in range(playerHealth):
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("normalTomb").show()
		tombList.remove(i)

	for i in range(tombList.size()):
		var r = floor(rand_range(0, 3))
		if r == 1:
			tombList[i].get_node("brokenTomb").show()
		elif r == 2:
			tombList[i].get_node("missingTomb").show()
		else:
			pass

func _notification(what):
	if (what==MainLoop.NOTIFICATION_WM_QUIT_REQUEST):
		#Submit current game and save highArray before exiting.
		get_node("/root/global").enteringOS = true
		get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _process(delta):
	#This is ran every frame.
	#get_node("/root/global").timeString(time)
	playerTime = playerTime + delta
	get_node("displayPlayerTimeOnScreen").set_text(get_node("/root/global").timeString(playerTime))

func _on_backGround_pressed():
	#Submit current game and save highArray before ending round.
	#updateHighScore(score, time)
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _on_frontGround_pressed():
	#Submit current game and save highArray before ending round.
	#updateHighScore(score, time)
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

extends Node

#get_node("/root/global").enteringOS   <--This is the proper method to quit to desktop.
#get_node("/root/global").enteringMenu  <--This is the proper method to get to the main menu.
#get_node("/root/global").currentDifficulty  <--This is the proper method to get the difficulty.

#Time based variables.
#var eclipseRatio = null

#Player stuff.
var playerScore = null
var playerTime = null
var playerDifficulty = null #This has to be between 0 and 3 to match the size of xSizeArray and ySizeArray.
var playerHealth = null
#var specialAbilityAmmo = null
var tombArray = []
var tombOrigen = null
var tombs = null
var tombNumberTotal = 0
var xSizeArray = [3, 3, 4, 6] #[Easy, Normal, Hard, Insane]
var ySizeArray = [1, 2, 3, 3] #[Easy, Normal, Hard, Insane]
var howDiedTombCount = 3 #this is a count of the number of different flavor texts that go on tombstones.
var xTombSpacing = null
var yTombSpacing = null
var tombStyle = null
var tombList = []

#var tombArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ",", ".", "_", "-"]

func _ready():
	get_scene().set_auto_accept_quit(false) #Enables: _notification(what) to recieve MainLoop.NOTIFICATION_WM_QUIT_REQUEST
	set_process(true) #Enables: _process(delta) to run every frame.
	playerDifficulty = get_node("/root/global").currentDifficulty

	tombs = get_node("tombs")
	xTombSpacing = 200
	yTombSpacing = 175

	#for g in range(glyphArray.size()):
	#	n = load("res://scene/getNameGlyph.xscn").instance()
	#	glyph.add_child(n)

	tombArray.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		tombArray.append([])
		for y in range(ySizeArray[playerDifficulty]):
			tombArray[x].append(load("res://scene/zombiesGoTomb.xscn").instance())
			#print("Hello World " + str(x) + ", " + str(y))
			#MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM
			tombArray[x][y].set_margin(MARGIN_LEFT, 1280/2 - xSizeArray[playerDifficulty]*xTombSpacing/2 + x * xTombSpacing + floor(rand_range( -xTombSpacing*.2, xTombSpacing*.2)))
			tombArray[x][y].set_margin(MARGIN_TOP, 720/2 - ySizeArray[playerDifficulty]*yTombSpacing/2  + y * yTombSpacing)
			tombs.add_child(tombArray[x][y])

	#Init settings for round.
	#eclipseRatio = (difficulty - 1) * 0.2
	playerScore = 0
	playerTime = 0
	#specialAbilityAmmo = 0
	if playerDifficulty == 0:
		playerHealth = 3
	if playerDifficulty == 1:
		playerHealth = 3
	if playerDifficulty == 2:
		playerHealth = 3
	if playerDifficulty == 3:
		playerHealth = 3

	#Create List
	tombList.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			tombList.append(tombArray[x][y])

			#tombStyle = floor(rand_range( 0, 3)) #If floor ever returns the high value, it will be a bug on this line.
			#tombArray[x][y].get_node("normalTomb").show()
			#tombArray[x][y].get_node("backHole").show()
			#tombArray[x][y].get_node("frontHole").show()

	for c in range(playerHealth):
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("normalTomb").show()
		tombList.remove(i)

	for i in range(tombList.size()):
		var r = floor(rand_range(0, 3))
		if r == 1:
			tombList[i].get_node("brokenTomb").show()
		elif r == 2:
			tombList[i].get_node("missingTomb").show()
		else:
			pass

func _notification(what):
	if (what==MainLoop.NOTIFICATION_WM_QUIT_REQUEST):
		#Submit current game and save highArray before exiting.
		get_node("/root/global").enteringOS = true
		get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _process(delta):
	#This is ran every frame.
	#get_node("/root/global").timeString(time)
	playerTime = playerTime + delta
	get_node("displayPlayerTimeOnScreen").set_text(get_node("/root/global").timeString(playerTime))

func _on_backGround_pressed():
	#Submit current game and save highArray before ending round.
	#updateHighScore(score, time)
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _on_frontGround_pressed():
	#Submit current game and save highArray before ending round.
	#updateHighScore(score, time)
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))


small additions

small additions

const DIFF_EASY		= 0
const DIFF_MEDIUM	= 1
const DIFF_HARD		= 2

# this order is important
const BLOCK_LASER	= 0
const BLOCK_WILD	= 1
const BLOCK_PAIR	= 2
const BLOCK_GOAL	= 3
const BLOCK_BLOCK   = 4

const SOLVER_ERROR_NONE				= 0
const SOLVER_ERROR_MISSING_PAIR		= 1

const blockColors = ["Blue", "Orange", "Red", "Gray", "Purple", "Green"]

# Preload paired blocks
const blockScn = preload( "res://blocks/block.scn" )
const blockScripts = [ preload( "Blocks/LaserBlock.gd" )
			   	      , preload( "Blocks/WildBlock.gd" )
			   	      , preload( "Blocks/PairedBlock.gd" )
			   	      , preload( "Blocks/LaserBlock.gd" )
			   	      ]

var glyphOn

# Calculates the layer that a block is on.
static func calcBlockLayer( x, y, z ):
	return max( max( abs( x ), abs( y ) ), abs( z ) )
# THIS IS EVERYWHERE, ANY BETTER WAY TO HAVE FUNCTIONS BETWEEN SCRIPTS?
static func calcBlockLayerVec( pos ):
	return max( max( abs( pos.x ), abs( pos.y ) ), abs( pos.z ) )

# Stores a puzzle in a convenient class.
class Puzzle:

	var puzzleName			# The name of the puzzle.
	var puzzleLayers		# The amount of layers the puzzle has.
	var pairCount = []		# The amount of pair blocks on each layer.
	var shape = {}			# All blocks indexed by position
	var lasers = []			# Laser connections.
	var puzzleMan			# Stores the puzzle manager for making pickled blocks.

	# Converts a puzzle to a dictionary.
	func toDict():
		var blocksArray = []
		for k in shape.keys():
			if shape[k] == null:
				continue
			blocksArray.append(shape[k].toDict())

		var di = { pN = puzzleName
		 	     , pL = puzzleLayers
				 , bL = blocksArray
				 , pC = pairCount
				 , lS = lasers
			     }
		return di

	# Converts a dictionary to a puzzle.
	func fromDict( di ):
		puzzleName = di.pN
		puzzleLayers = di.pL
		pairCount = di.pC
		lasers = di.lS

		for block in di.bL:
			var nb = puzzleMan.PickledBlock.new()
			nb.fromDict( block )
			shape[nb.blockPos] = nb
		return

	# Class that stores a solution or the errors in a puzzle.
	class PuzzleSteps:
		var solveable = false
		var error = SOLVER_ERROR_NONE
		var errorBlock = null
		var solveSteps = []

	# THIS IS EVERYWHERE, ANY BETTER WAY TO HAVE FUNCTIONS BETWEEN SCRIPTS?
	# duplicate of the global definition above? Either way godot is chill and
	# doesn't complain
	func calcBlockLayerVec( pos ):
		return max( max( abs( pos.x ), abs( pos.y ) ), abs( pos.z ) )

	# Determines if a puzzle is solveable.
	func solvePuzzle():
		# Simply use the solvePuzzleSteps function and return the solveable part.
		var ps = self.solvePuzzleSteps()
		return ps.solveable

	# Determines if a puzzle is solveable and returns the steps needed to solve it.
	func solvePuzzleSteps():
		var puzzleSteps = PuzzleSteps.new()

		var pairs = []

		# Add new dictionary for each later.
		for l in range( puzzleLayers + 1 ):
			pairs.append( {} )

		# Gather paired blocks from the puzzle.
		for k in shape.keys():
			var b = shape[k]
			if b.blockClass == BLOCK_PAIR:
				b.solverFlag = false
				pairs[calcBlockLayerVec(b.blockPos)][b.name] = b

		# Make sure each pair block has a valid pair on the same layer.
		for l in pairs:
			for p in l:
				if l.has( l[p].pairName ):
					if( not l[p].solverFlag ):
						l[p].solverFlag = true
						l[l[p].pairName].solverFlag = true
						puzzleSteps.solveSteps.append( [ l[p].blockPos, l[l[p].pairName].blockPos ] )
				else:
					puzzleSteps.error = SOLVER_ERROR_MISSING_PAIR
					puzzleSteps.errorBlock = l[p]
					return puzzleSteps

		puzzleSteps.solveable = true
		return puzzleSteps

# Randomly shuffle an array.
func shuffleArray( arr ):
	for i in range( arr.size() - 1, 1, -1 ):
		var swapVal = randi() % (i + 1)
		var temp = arr[swapVal]
		arr[swapVal] = arr[i]
		arr[i] = temp

# Determines the block type based on puzzle size and difficulty.
func getBlockType( difficulty, pos ):
	# Determine if this is the goal block.
	if pos.x == 0 and pos.y == 0 and pos.z == 0:
		return BLOCK_GOAL

	# Determine the layer this block is on.
	var layer = calcBlockLayerVec( pos )

	# Determine how many blocks are on the outer part of the layer.
	var layerCount = 0
	if abs( pos.x ) == layer:
		layerCount += 1
	if abs( pos.y ) == layer:
		layerCount += 1
	if abs( pos.z ) == layer:
		layerCount += 1

	# Determine if this block is a laser.
	if difficulty == DIFF_EASY or difficulty == DIFF_MEDIUM:
		if layerCount == 3:
			return BLOCK_LASER

	if difficulty == DIFF_HARD:
		if abs( pos.x ) == abs( pos.z ) and pos.y == 0:
			return BLOCK_LASER

	# Determine if this block is a wild block.
	if difficulty == DIFF_EASY:
		if layerCount == 2:
			return BLOCK_WILD

	if difficulty == DIFF_MEDIUM:
		if layerCount == 2:
			if pos.y == layer || pos.y == -layer:
				return BLOCK_WILD

	if difficulty == DIFF_HARD:
		if layerCount == 1:
			if pos.y == 0:
				return BLOCK_WILD

	# Otherwise it's a normal block.
	return BLOCK_PAIR

# Generates a solveable puzzle.
func generatePuzzle( layers, difficulty ):
	var blockID = 0
	var puzzle = Puzzle.new()
	puzzle.puzzleName = "RANDOM PUZZLE"
	puzzle.puzzleLayers = layers

	glyphOn = []
	for g in range( blockColors.size() ):
		glyphOn.append( 0 )

	# Create all possible positions.
	var layeredblocks = []
	for l in range( 0, layers + 1 ):
		layeredblocks.append( [] )
		puzzle.pairCount.append( 0 )
	for x in range( -layers, layers + 1 ):
		for y in range( -layers, layers + 1 ):
			for z in range( -layers, layers + 1 ):
				layeredblocks[calcBlockLayer( x, y, z )].append(Vector3(x,y,z))

	# Generate laser lines.
	for l in range( 1, layers + 1 ):
		if difficulty == DIFF_MEDIUM or difficulty == DIFF_EASY:
			for lx in [ -l, l ]:
				for ly in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, ly, lx ), Vector3( lx*-1, ly, lx )] )
					puzzle.lasers.append( [Vector3( lx, ly, lx ), Vector3( lx, ly, lx*-1 )] )

		if difficulty == DIFF_EASY:
			for lx in [ -l, l ]:
				for lz in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, l, lz ), Vector3( lx, -l, lz )] )

		if difficulty == DIFF_HARD:
			for lx in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, 0, lx ), Vector3( lx*-1, 0, lx )] )
					puzzle.lasers.append( [Vector3( lx, 0, lx ), Vector3( lx, 0, lx*-1 )] )

	# Assign block types based on position.
	for l in range( 0, layers + 1 ):
		# Randomize the pairs.
		shuffleArray( layeredblocks[l] )
		# print( "NUM ", layeredblocks[l].size() )
		var prevBlock = null
		var even = false
		for pos in layeredblocks[l]:
			var x = pos.x
			var y = pos.y
			var z = pos.z

			var t = getBlockType( difficulty, pos )

			if t == BLOCK_GOAL:
				continue

			var b = PickledBlock.new()
			b.blockPos = pos
			b.name = blockID

			blockID += 1
			puzzle.shape[pos] = b

			if t == BLOCK_LASER:
				b.setBlockClass(BLOCK_LASER)\
					.setLaserExtent( Vector3( 0, 1, 0 ) )
				continue

			if t == BLOCK_WILD:
				b.setBlockClass(BLOCK_WILD) \
					.setTextureName(blockColors[randi() % blockColors.size()])
				continue

			if even:
				# Count this pair.
				puzzle.pairCount[l] += 1

				var randColor = ( randi() % blockColors.size() )
				var randMaterial = blockColors[randColor] + str( glyphOn[randColor] + 1 )
				glyphOn[randColor] += 1
				glyphOn[randColor] %= 3
				b.setBlockClass(BLOCK_PAIR) \
					.setPairName(prevBlock.name) \
					.setTextureName(randMaterial)

				prevBlock.setBlockClass(BLOCK_PAIR) \
					.setPairName(b.name) \
					.setTextureName(randMaterial)
			even = not even
			prevBlock = b

	return puzzle

# Storage class for blocks in a puzzle.
class PickledBlock:
	var name
	var blockClass = BLOCK_PAIR
	var pairName
	var textureName = "Red"
	var blockPos
	var laserExtent
	var solverFlag		# Keeps track of this block, only user for the solver.

	func setName(n):
		name = n
		return self

	func setPairName(n):
		pairName = n
		return self

	func setLaserExtent(n):
		laserExtent = n
		return self

	func setBlockPos(n):
		blockPos = n
		return self

	func setBlockClass(c):
		blockClass = c
		return self

	func setTextureName(t):
		textureName = t
		return self

	func toString():
		return str(name) + ": " + str(blockClass) + " @ " + str(blockPos)

	func toNode():
		# instantiate a block scene, assign the appropriate script to it
		var n = blockScn.instance()
		n.set_script(blockScripts[blockClass])

		n.set_translation(blockPos * 2)
		n.blockPos = blockPos

		n.setName(str(name))

		n.setBlockType( blockClass )

		if blockClass == BLOCK_PAIR:
			n.setPairName(pairName).setTexture(textureName)

		if blockClass == BLOCK_WILD:
			n.setTexture(textureName)

		if blockClass == BLOCK_LASER:
			n.setPairName(pairName).setExtent(laserExtent).setTexture()
		return n

	# test me plz
	func fromNode(n):
		blockPos = n.blockPos

		name = n.name_int

		blockClass = n.getBlockType()

		if blockClass == BLOCK_PAIR:
			pairName = n.pairName
			textureName = n.textureName

		if blockClass == BLOCK_WILD:
			textureName = n.textureName

		if blockClass == BLOCK_LASER:
			pairName = n.pairName

	# Convert this object to a dictionary.
	func toDict():
		var di = { n = name
		 	     , bC = blockClass
			     , pN = pairName
			     , tN = textureName
			     , bP = blockPos
			     , lE = laserExtent
			     }
		return di

	# Make this object from a dictionary.
	func fromDict( di ):
		name = di.n
		blockClass = di.bC
		pairName = di.pN
		textureName = di.tN
		blockPos = di.bP
		laserExtent = di.lE

const DIFF_EASY		= 0
const DIFF_MEDIUM	= 1
const DIFF_HARD		= 2

# this order is important
const BLOCK_LASER	= 0
const BLOCK_WILD	= 1
const BLOCK_PAIR	= 2
const BLOCK_GOAL	= 3
const BLOCK_BLOCK   = 4

const SOLVER_ERROR_NONE				= 0
const SOLVER_ERROR_MISSING_PAIR		= 1

const blockColors = ["Blue", "Orange", "Red", "Gray", "Purple", "Green"]

# Preload paired blocks
const blockScn = preload( "res://blocks/block.scn" )
const blockScripts = [ preload( "Blocks/LaserBlock.gd" )
			   	      , preload( "Blocks/WildBlock.gd" )
			   	      , preload( "Blocks/PairedBlock.gd" )
			   	      , preload( "Blocks/LaserBlock.gd" )
			   	      ]

# Hash map of all possible positions
var shape = {}

# Calculates the layer that a block is on.
static func calcBlockLayer( x, y, z ):
	return max( max( abs( x ), abs( y ) ), abs( z ) )
# THIS IS EVERYWHERE, ANY BETTER WAY TO HAVE FUNCTIONS BETWEEN SCRIPTS?
static func calcBlockLayerVec( pos ):
	return max( max( abs( pos.x ), abs( pos.y ) ), abs( pos.z ) )

# Stores a puzzle in a convenient class.
class Puzzle:

	var puzzleName			# The name of the puzzle.
	var puzzleLayers		# The amount of layers the puzzle has.
	var pairCount = []		# The amount of pair blocks on each layer.
	var shape = {}			# All blocks indexed by position
	var lasers = []			# Laser connections.
	var puzzleMan			# Stores the puzzle manager for making pickled blocks.

	# Converts a puzzle to a dictionary.
	func toDict():
		var blocksArray = []
		for k in shape.keys():
			if shape[k] == null:
				continue
			blocksArray.append(shape[k].toDict())

		var di = { pN = puzzleName
		 	     , pL = puzzleLayers
				 , bL = blocksArray
				 , pC = pairCount
				 , lS = lasers
			     }
		return di

	# Converts a dictionary to a puzzle.
	func fromDict( di ):
		puzzleName = di.pN
		puzzleLayers = di.pL
		pairCount = di.pC
		lasers = di.lS

		for block in di.bL:
			var nb = puzzleMan.PickledBlock.new()
			nb.fromDict( block )
			shape[nb.blockPos] = nb
		return

	# Class that stores a solution or the errors in a puzzle.
	class PuzzleSteps:
		var solveable = false
		var error = SOLVER_ERROR_NONE
		var errorBlock = null
		var solveSteps = []

	# THIS IS EVERYWHERE, ANY BETTER WAY TO HAVE FUNCTIONS BETWEEN SCRIPTS?
	# duplicate of the global definition above? Either way godot is chill and
	# doesn't complain
	func calcBlockLayerVec( pos ):
		return max( max( abs( pos.x ), abs( pos.y ) ), abs( pos.z ) )

	# Determines if a puzzle is solveable.
	func solvePuzzle():
		# Simply use the solvePuzzleSteps function and return the solveable part.
		var ps = self.solvePuzzleSteps()
		return ps.solveable

	# Determines if a puzzle is solveable and returns the steps needed to solve it.
	func solvePuzzleSteps():
		var puzzleSteps = PuzzleSteps.new()

		var pairs = []

		# Add new dictionary for each later.
		for l in range( puzzleLayers + 1 ):
			pairs.append( {} )

		# Gather paired blocks from the puzzle.
		for k in shape.keys():
			var b = shape[k]
			if b.blockClass == BLOCK_PAIR:
				b.solverFlag = false
				pairs[calcBlockLayerVec(b.blockPos)][b.name] = b

		# Make sure each pair block has a valid pair on the same layer.
		for l in pairs:
			for p in l:
				if l.has( l[p].pairName ):
					if( not l[p].solverFlag ):
						l[p].solverFlag = true
						l[l[p].pairName].solverFlag = true
						puzzleSteps.solveSteps.append( [ l[p].blockPos, l[l[p].pairName].blockPos ] )
				else:
					puzzleSteps.error = SOLVER_ERROR_MISSING_PAIR
					puzzleSteps.errorBlock = l[p]
					return puzzleSteps

		puzzleSteps.solveable = true
		return puzzleSteps

# Randomly shuffle an array.
func shuffleArray( arr ):
	for i in range( arr.size() - 1, 1, -1 ):
		var swapVal = randi() % (i + 1)
		var temp = arr[swapVal]
		arr[swapVal] = arr[i]
		arr[i] = temp

# Determines the block type based on puzzle size and difficulty.
func getBlockType( difficulty, pos ):
	# Determine if this is the goal block.
	if pos.x == 0 and pos.y == 0 and pos.z == 0:
		return BLOCK_GOAL

	# Determine the layer this block is on.
	var layer = calcBlockLayerVec( pos )

	# Determine how many blocks are on the outer part of the layer.
	var layerCount = 0
	if abs( pos.x ) == layer:
		layerCount += 1
	if abs( pos.y ) == layer:
		layerCount += 1
	if abs( pos.z ) == layer:
		layerCount += 1

	# Determine if this block is a laser.
	if difficulty == DIFF_EASY or difficulty == DIFF_MEDIUM:
		if layerCount == 3:
			return BLOCK_LASER

	if difficulty == DIFF_HARD:
		if abs( pos.x ) == abs( pos.z ) and pos.y == 0:
			return BLOCK_LASER

	# Determine if this block is a wild block.
	if difficulty == DIFF_EASY:
		if layerCount == 2:
			return BLOCK_WILD

	if difficulty == DIFF_MEDIUM:
		if layerCount == 2:
			if pos.y == layer || pos.y == -layer:
				return BLOCK_WILD

	if difficulty == DIFF_HARD:
		if layerCount == 1:
			if pos.y == 0:
				return BLOCK_WILD

	# Otherwise it's a normal block.
	return BLOCK_PAIR

# Generates a solveable puzzle.
func generatePuzzle( layers, difficulty ):
	var blockID = 0
	var puzzle = Puzzle.new()
	puzzle.puzzleName = "RANDOM PUZZLE"
	puzzle.puzzleLayers = layers

	var glyphOn = []
	for g in range( blockColors.size() ):
		glyphOn.append( 0 )

	# Create all possible positions.
	var layeredblocks = []
	for l in range( 0, layers + 1 ):
		layeredblocks.append( [] )
		puzzle.pairCount.append( 0 )
	for x in range( -layers, layers + 1 ):
		for y in range( -layers, layers + 1 ):
			for z in range( -layers, layers + 1 ):
				layeredblocks[calcBlockLayer( x, y, z )].append(Vector3(x,y,z))

	# Generate laser lines.
	for l in range( 1, layers + 1 ):
		if difficulty == DIFF_MEDIUM or difficulty == DIFF_EASY:
			for lx in [ -l, l ]:
				for ly in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, ly, lx ), Vector3( lx*-1, ly, lx )] )
					puzzle.lasers.append( [Vector3( lx, ly, lx ), Vector3( lx, ly, lx*-1 )] )

		if difficulty == DIFF_EASY:
			for lx in [ -l, l ]:
				for lz in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, l, lz ), Vector3( lx, -l, lz )] )

		if difficulty == DIFF_HARD:
			for lx in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, 0, lx ), Vector3( lx*-1, 0, lx )] )
					puzzle.lasers.append( [Vector3( lx, 0, lx ), Vector3( lx, 0, lx*-1 )] )

	# Assign block types based on position.
	for l in range( 0, layers + 1 ):
		# Randomize the pairs.
		shuffleArray( layeredblocks[l] )
		# print( "NUM ", layeredblocks[l].size() )
		var prevBlock = null
		var even = false
		for pos in layeredblocks[l]:
			var x = pos.x
			var y = pos.y
			var z = pos.z

			var t = getBlockType( difficulty, pos )

			if t == BLOCK_GOAL:
				continue

			var b = PickledBlock.new()
			b.blockPos = pos
			b.name = blockID

			blockID += 1
			puzzle.shape[pos] = b

			if t == BLOCK_LASER:
				b.setBlockClass(BLOCK_LASER)\
					.setLaserExtent( Vector3( 0, 1, 0 ) )
				continue

			if t == BLOCK_WILD:
				b.setBlockClass(BLOCK_WILD) \
					.setTextureName(blockColors[randi() % blockColors.size()])
				continue

			if even:
				# Count this pair.
				puzzle.pairCount[l] += 1

				var randColor = ( randi() % blockColors.size() )
				var randMaterial = blockColors[randColor] + str( glyphOn[randColor] + 1 )
				glyphOn[randColor] += 1
				glyphOn[randColor] %= 3
				b.setBlockClass(BLOCK_PAIR) \
					.setPairName(prevBlock.name) \
					.setTextureName(randMaterial)

				prevBlock.setBlockClass(BLOCK_PAIR) \
					.setPairName(b.name) \
					.setTextureName(randMaterial)
			even = not even
			prevBlock = b

	return puzzle

# Storage class for blocks in a puzzle.
class PickledBlock:
	var name
	var blockClass = BLOCK_PAIR
	var pairName
	var textureName = "Red"
	var blockPos
	var laserExtent
	var solverFlag		# Keeps track of this block, only user for the solver.

	func setName(n):
		name = n
		return self

	func setPairName(n):
		pairName = n
		return self

	func setLaserExtent(n):
		laserExtent = n
		return self

	func setBlockPos(n):
		blockPos = n
		return self

	func setBlockClass(c):
		blockClass = c
		return self

	func setTextureName(t):
		textureName = t
		return self

	func toString():
		return str(name) + ": " + str(blockClass) + " @ " + str(blockPos)

	func toNode():
		# instantiate a block scene, assign the appropriate script to it
		var n = blockScn.instance()
		n.set_script(blockScripts[blockClass])

		n.set_translation(blockPos * 2)
		n.blockPos = blockPos

		n.setName(str(name)).setTexture( "Red1" )

		n.setBlockType( blockClass )

		if blockClass == BLOCK_PAIR:
			n.setPairName(pairName).setTexture(textureName)

		if blockClass == BLOCK_WILD:
			n.setTexture(textureName)

		if blockClass == BLOCK_LASER:
			n.setPairName(pairName).setExtent(laserExtent)
		return n

	# test me plz
	func fromNode(n):
		blockPos = n.blockPos

		name = n.name_int

		blockClass = n.getBlockType()

		if blockClass == BLOCK_PAIR:
			pairName = n.pairName
			textureName = n.textureName

		if blockClass == BLOCK_WILD:
			textureName = n.textureName

		if blockClass == BLOCK_LASER:
			pairName = n.pairName

	# Convert this object to a dictionary.
	func toDict():
		var di = { n = name
		 	     , bC = blockClass
			     , pN = pairName
			     , tN = textureName
			     , bP = blockPos
			     , lE = laserExtent
			     }
		return di

	# Make this object from a dictionary.
	func fromDict( di ):
		name = di.n
		blockClass = di.bC
		pairName = di.pN
		textureName = di.tN
		blockPos = di.bP
		laserExtent = di.lE


Update GUIManager.gd

Update GUIManager.gd

Quick fix to splash screens. Can skip with mouse click and added a lot of comments.


GDScript test style fix

GDScript test style fix

func test():
	var null_var = null
	var true_var: bool = true
	var false_var: bool = false
	print(str(null_var))
	print(str(true_var))
	print(str(false_var))

func test():
	var null_var = null
	var true_var:bool = true
	var false_var:bool = false
	print(str(null_var))
	print(str(true_var))
	print(str(false_var))


Update main.gd

Update main.gd

extends Node

var admob = null
var isReal = true
var isTop = true
var adId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX" # [Replace with your Ad Unit ID and delete this message.]

func _ready():
	if(Globals.has_singleton("AdMob")):
		admob = Globals.get_singleton("AdMob")
		admob.init(isReal, get_instance_ID())

func loadBanner():
	if admob != null:
		admob.loadBanner(adId, isTop)
		get_tree().connect("screen_resized", self, "onResize")

func onResize():
	if admob != null:
		admob.resize()

func _on_admob_network_error():
	print("Network Error")

func _on_admob_ad_loaded():
	print("Ad loaded success")

extends Node

var admob = null
var isReal = true
var isTop = true
var ad_id = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX" # [Replace with your Ad Unit ID and delete this message.]

func _ready():
	if(Globals.has_singleton("AdMob")):
		admob = Globals.get_singleton("AdMob")
		admob.init(isReal)
		admob.loadBanner(ad_id, isTop)


Improve the example with all callbacks and new features

extends Node2D

var admob = null
var isReal = false
var isTop = true
var adBannerId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX" # [Replace with your Ad Unit ID and delete this message.]
var adInterstitialId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX" # [Replace with your Ad Unit ID and delete this message.]

func _ready():
	if(Globals.has_singleton("AdMob")):
		admob = Globals.get_singleton("AdMob")
		admob.init(isReal, get_instance_ID())
		loadBanner()
		loadInterstitial()

	get_tree().connect("screen_resized", self, "onResize")

# Loaders

func loadBanner():
	if admob != null:
		admob.loadBanner(adBannerId, isTop)

func loadInterstitial():
	if admob != null:
		admob.loadInterstitial(adInterstitialId)

# Events

func _on_BtnBanner_toggled(pressed):
	if admob != null:
		if pressed: admob.showBanner()
		else: admob.hideBanner()

func _on_BtnInterstitial_pressed():
	if admob != null:
		admob.showInterstitial()

func _on_admob_network_error():
	print("Network Error")

func _on_admob_ad_loaded():
	print("Ad loaded success")
	get_node("CanvasLayer/BtnBanner").set_disabled(false)

func _on_interstitial_not_loaded():
	print("Error: Interstitial not loaded")

func _on_interstitial_loaded():
	print("Interstitial loaded")
	get_node("CanvasLayer/BtnInterstitial").set_disabled(false)

func _on_interstitial_close():
	print("Interstitial closed")
	get_node("CanvasLayer/BtnInterstitial").set_disabled(true)

# Resize

func onResize():
	if admob != null:
		admob.resize()

extends Node

var admob = null
var isReal = true
var isTop = true
var adId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX" # [Replace with your Ad Unit ID and delete this message.]

func _ready():
	if(Globals.has_singleton("AdMob")):
		admob = Globals.get_singleton("AdMob")
		admob.init(isReal, get_instance_ID())

func loadBanner():
	if admob != null:
		admob.loadBanner(adId, isTop)
		get_tree().connect("screen_resized", self, "onResize")

func onResize():
	if admob != null:
		admob.resize()

func _on_admob_network_error():
	print("Network Error")

func _on_admob_ad_loaded():
	print("Ad loaded success")


Ulepszyłem mapę.

Ulepszyłem mapę.


commented signal stuff

commented signal stuff

extends CanvasLayer

export (NodePath) var collected_text #= get_node("hudframe/items_label/score_display")
export (NodePath) var score_text #final_score_text = get_node("hudframe/finalscore_label/final_scoredisplay")
export (NodePath) var highscore_text #= get_node("hudframe/highscore_label/highscore_display")
export (NodePath) var sound_off_button #= get_node("hudframe/sound_off")

onready var animations = get_node("animations")
#onready var yan = get_parent().find_node("Yan")
#onready var whatsmyparent = get_parent().get_name()
#onready var whatsmyowner = get_owner().get_name()

#func _on_met_yan():
#	get_node("sfx").play("card_unlock")
#	animations.play("yan_unlock_anim")

func _ready():
#	print ("My parent is: " + whatsmyparent)
#	print ("My owner is: " + whatsmyowner)

#	print (yan.get_name())
#	if yan.has_node("Yan"):
#		print("Yan is present")
	#yan.connect("met_yan", self,"_on_met_yan")
	animations.play("yan_unlock_anim")

	update_scores()
	game.connect("scores_changed", self, "update_scores")
	update_sound_hud()

# Update scores
func update_scores():
	get_node(collected_text).set_text(str(game.items_collected))
	get_node(score_text).set_text(str(game.score))
	get_node(highscore_text).set_text(str(game.high_score))

func _on_go_to_menu_pressed():
	transition.fade_to("res://src/screens/menu/menu.tscn")

# Toggles music on/off while keeping the stored volume that may have been set elsewhere
func _on_sound_off_pressed():
	# Turns off music completely, or returns it back to normal
	if(global.music.enabled):
		AudioServer.set_stream_global_volume_scale(0)
	else:
		AudioServer.set_stream_global_volume_scale(global.music.volume)

	# Toggle bool
	global.music.enabled = !global.music.enabled

	# Update sound HUD
	update_sound_hud()

# Updates sound HUD
func update_sound_hud():
	if(global.music.enabled):
		get_node(sound_off_button).set_pressed(true) # res://src/screens/hud/sound_on.png
	else:
		get_node(sound_off_button).set_pressed(false) # res://src/screens/hud/sound_off.png

extends CanvasLayer

export (NodePath) var collected_text #= get_node("hudframe/items_label/score_display")
export (NodePath) var score_text #final_score_text = get_node("hudframe/finalscore_label/final_scoredisplay")
export (NodePath) var highscore_text #= get_node("hudframe/highscore_label/highscore_display")
export (NodePath) var sound_off_button #= get_node("hudframe/sound_off")

onready var animations = get_node("animations")
onready var yan = get_parent().find_node("Yan")
onready var whatsmyparent = get_parent().get_name()
onready var whatsmyowner = get_owner().get_name()

func _on_met_yan():
	get_node("sfx").play("card_unlock")
	animations.play("yan_unlock_anim")

func _ready():
	print ("My parent is: " + whatsmyparent)
	print ("My owner is: " + whatsmyowner)

	print (yan.get_name())
	if yan.has_node("Yan"):
		print("Yan is present")
		yan.connect("met_yan", self,"_on_met_yan")
		animations.play("yan_unlock_anim")

	update_scores()
	game.connect("scores_changed", self, "update_scores")
	update_sound_hud()

# Update scores
func update_scores():
	get_node(collected_text).set_text(str(game.items_collected))
	get_node(score_text).set_text(str(game.score))
	get_node(highscore_text).set_text(str(game.high_score))

func _on_go_to_menu_pressed():
	transition.fade_to("res://src/screens/menu/menu.tscn")

# Toggles music on/off while keeping the stored volume that may have been set elsewhere
func _on_sound_off_pressed():
	# Turns off music completely, or returns it back to normal
	if(global.music.enabled):
		AudioServer.set_stream_global_volume_scale(0)
	else:
		AudioServer.set_stream_global_volume_scale(global.music.volume)

	# Toggle bool
	global.music.enabled = !global.music.enabled

	# Update sound HUD
	update_sound_hud()

# Updates sound HUD
func update_sound_hud():
	if(global.music.enabled):
		get_node(sound_off_button).set_pressed(true) # res://src/screens/hud/sound_on.png
	else:
		get_node(sound_off_button).set_pressed(false) # res://src/screens/hud/sound_off.png


Dynamic regex viewing in editor

Dynamic regex viewing in editor

extends Panel

# member variables here, example:
# var a=2
# var b="textvar"

func _ready():
	# Called every time the node is added to the scene.
	# Initialization here
	set_process_input(true)
	set_process(true)

func _process(delta):
	update()

func _input(event):
	if event.type == InputEvent.KEY:
		if event.scancode == KEY_ENTER and event.pressed == true:
			_on_FightButton_pressed()

func _on_FightButton_pressed():
	var boss = preload("res://objects/Boss.tscn").instance()
	boss.base_size = get_node("BaseSizeField").get_value()
	boss.base_health = get_node("BaseHealthField").get_value()
	boss.size_dropoff = get_node("SideDropoffField").get_value() / 100
	boss.base_rot_speed = get_node("BaseRotField").get_value()
	boss.rot_speed_inc = get_node("RotIncField").get_value()
	boss.start_color = get_node("StartColorField").get_color()
	boss.end_color = get_node("EndColorField").get_color()
	boss.regex = get_node("RegexField").get_text()

	get_node("..").add_child(boss)
	boss.set_global_pos(Vector2(360,360))

	get_node("..").last_boss = boss
	get_node("..").last_boss_wr = weakref(boss)
	get_node("..").target_bgcol = boss.start_color.linear_interpolate(Color(0,0,0), 0.8)
	get_node("..").target_fgcol = boss.end_color.linear_interpolate(Color(0,0,0), 0)
	get_node("..").playing = true
	queue_free()

var expr = RegEx.new()

func _draw():
	expr.compile(get_node("RegexField").get_text())
	draw_boss_part("")

func draw_boss_part(id):
	var find = expr.find(id)
	var alive = false
	for s in expr.get_captures():
		if(s == id):
			alive = true
			break

	if alive:
		var col = get_node("StartColorField").get_color().linear_interpolate(get_node("EndColorField").get_color(),id.length() / 4.0)
		var poly = Vector2Array()
		var s = get_node("BaseSizeField").get_value() * pow(get_node("SideDropoffField").get_value() / 100, id.length())
		var base_pos = Vector2(500,360) + get_part_pos(id)
		for i in range(3):
			var t = i / 3.0 * 2 * PI
			poly.append(base_pos + Vector2(cos(t)*s,sin(t)*s))
		draw_colored_polygon(poly, col)
	if id.length() < 4:
		for i in range(3):
			draw_boss_part(id + str(i))

func get_part_pos(id):
	#if(map.has(id)):
#		return map.id
	if(id==""):
		return Vector2(0, 0)
	var c = id[-1].to_float()
	var depth = id.length() - 1
	var parent_pos = get_part_pos(id.substr(0,depth))
	var theta = c / 3.0 * 2 * PI
	var r = get_node("BaseSizeField").get_value() * pow(get_node("SideDropoffField").get_value() / 100, depth)
	var pos = parent_pos + Vector2(r * cos(-theta), r*sin(-theta))
	#map.id = pos
	return pos

extends Panel

# member variables here, example:
# var a=2
# var b="textvar"

func _ready():
	# Called every time the node is added to the scene.
	# Initialization here
	set_process_input(true)
	set_process(true)

func _process(delta):
	update()

func _input(event):
	if event.type == InputEvent.KEY:
		if event.scancode == KEY_ENTER and event.pressed == true:
			_on_FightButton_pressed()

func _on_FightButton_pressed():
	var boss = preload("res://objects/Boss.tscn").instance()
	boss.base_size = get_node("BaseSizeField").get_value()
	boss.base_health = get_node("BaseHealthField").get_value()
	boss.size_dropoff = get_node("SideDropoffField").get_value() / 100
	boss.base_rot_speed = get_node("BaseRotField").get_value()
	boss.rot_speed_inc = get_node("RotIncField").get_value()
	boss.start_color = get_node("StartColorField").get_color()
	boss.end_color = get_node("EndColorField").get_color()
	boss.regex = get_node("RegexField").get_text()

	get_node("..").add_child(boss)
	boss.set_global_pos(Vector2(360,360))

	get_node("..").last_boss = boss
	get_node("..").last_boss_wr = weakref(boss)
	get_node("..").target_bgcol = boss.start_color.linear_interpolate(Color(0,0,0), 0.8)
	get_node("..").target_fgcol = boss.end_color.linear_interpolate(Color(0,0,0), 0)
	get_node("..").playing = true
	queue_free()

func _draw():
	draw_boss_part("")

func draw_boss_part(id):
	var col = get_node("StartColorField").get_color().linear_interpolate(get_node("EndColorField").get_color(),id.length() / 4.0)
	var poly = Vector2Array()
	var s = get_node("BaseSizeField").get_value() * pow(get_node("SideDropoffField").get_value() / 100, id.length())
	var base_pos = Vector2(500,360) + get_part_pos(id)
	for i in range(3):
		var t = i / 3.0 * 2 * PI
		poly.append(base_pos + Vector2(cos(t)*s,sin(t)*s))
	draw_colored_polygon(poly, col)
	if id.length() < 4:
		for i in range(3):
			draw_boss_part(id + str(i))

func get_part_pos(id):
	#if(map.has(id)):
#		return map.id
	if(id==""):
		return Vector2(0, 0)
	var c = id[-1].to_float()
	var depth = id.length() - 1
	var parent_pos = get_part_pos(id.substr(0,depth))
	var theta = c / 3.0 * 2 * PI
	var r = get_node("BaseSizeField").get_value() * pow(get_node("SideDropoffField").get_value() / 100, depth)
	var pos = parent_pos + Vector2(r * cos(-theta), r*sin(-theta))
	#map.id = pos
	return pos


Fixed & Refactored highScore to be understandable

extends Node

#Highscores that are saved to disk.
#  highArray[difficulty][rank][stat] = value
#  difficulty: range(SIZE_DIFFICULTY)
#  rank:       range(SIZE_RANK)
#  stat:       STAT_NAME, STAT_SCORE, STAT_TIME, STAT_NEW

var highArray
var highNode
var diffNode
var rankNode
var difficulty

func _ready():
	get_tree().set_auto_accept_quit(false) #Enables: _notification(what) to recieve MainLoop.NOTIFICATION_WM_QUIT_REQUEST
	highArray = get_node("/root/global").highArray
	highNode = get_node("highNode")

	for difficulty in range(get_node("/root/global").SIZE_DIFFICULTY):
		diffNode = highNode.get_node("difficulty " + str(difficulty + 1))
		if diffNode == null or diffNode.is_type("TextureFrame") == false:
			print(diffNode)
			continue

		var i = 0
		for rank in range(get_node("/root/global").SIZE_RANK - 1): # do not display the last row.
			rankNode = diffNode.get_child(rank)
			if highArray[difficulty][rank][get_node("/root/global").STAT_NEW]:
				rankNode.set_normal_texture(load("res://visual/atlasBloodyTomb.xatex"))

			if i == diffNode.get_child_count() - 1: # do not randomize last tombs position.
				i = (rank + 1) * (100 + 175 / 9)
			else:
				i = (rank + 1) * (100 + 175 / 9) + (rand_range(-175 / 18, 175 / 18))

			rankNode.set_margin(0, i)
			rankNode.set_size(Vector2(100, 130))
			rankNode.get_child(0).get_node("name").set_text(str(highArray[difficulty][rank][get_node("/root/global").STAT_NAME]))
			rankNode.get_child(0).get_node("score").set_text(str(highArray[difficulty][rank][get_node("/root/global").STAT_SCORE]))
			rankNode.get_child(0).get_node("time").set_text(str(highArray[difficulty][rank][get_node("/root/global").STAT_TIME]))

func _notification(what):
	if (what==MainLoop.NOTIFICATION_WM_QUIT_REQUEST): #User demanding to enterOS()
		get_node("/root/global").enteringOS = true
		get_node("/root/global").enterOS()

func _on_backGround_pressed():
	if get_node("/root/global").isInputEnabled():
		if get_node("/root/global").enteringOS:
			get_node("/root/global").enterOS()
		else:
			get_node("/root/global").enterMenu()

extends Node

#Highscores that are saved to disk.
#  highArray[difficulty][rank][stat] = value
#  difficulty: range(SIZE_DIFFICULTY)
#  rank:       range(SIZE_RANK)
#  stat:       STAT_NAME, STAT_SCORE, STAT_TIME, STAT_NEW

var highArray
var highNode
var highCount
var diffNode
var rankNode
var difficulty
var d

func _ready():
	get_tree().set_auto_accept_quit(false) #Enables: _notification(what) to recieve MainLoop.NOTIFICATION_WM_QUIT_REQUEST
	highArray = get_node("/root/global").highArray
	#root.get_child(root.get_child_count() - 1)
	highNode = get_node("highNode")
	highCount = highNode.get_child_count()
	difficulty = -1
	d = 0
	for d in range(highCount):
		diffNode = highNode.get_child(highCount - d - 1)
		if diffNode.is_type("TextureFrame") == false:
			continue

		difficulty += 1
		var i = 0
		for rank in range(diffNode.get_child_count()):
			rankNode = diffNode.get_child(rank)
			if highArray[difficulty][rank][get_node("/root/global").STAT_NEW]:
				rankNode.set_normal_texture(load("res://visual/atlasBloodyTomb.xatex"))

			if i == diffNode.get_child_count() - 1: # do not randomize last tombs position.
				i = (rank + 1) * (100 + 175 / 9)
			else:
				i = (rank + 1) * (100 + 175 / 9) + (rand_range(-175 / 18, 175 / 18))

			rankNode.set_margin(0, i)
			rankNode.set_size(Vector2(100, 130))
			rankNode.get_child(0).get_node("name").set_text(str(highArray[difficulty][rank][get_node("/root/global").STAT_NAME]))
			rankNode.get_child(0).get_node("score").set_text(str(highArray[difficulty][rank][get_node("/root/global").STAT_SCORE]))
			rankNode.get_child(0).get_node("time").set_text(str(highArray[difficulty][rank][get_node("/root/global").STAT_TIME]))

func _notification(what):
	if (what==MainLoop.NOTIFICATION_WM_QUIT_REQUEST): #User demanding to enterOS()
		get_node("/root/global").enteringOS = true
		get_node("/root/global").enterOS()

func _on_backGround_pressed():
	if get_node("/root/global").isInputEnabled():
		if get_node("/root/global").enteringOS:
			get_node("/root/global").enterOS()
		else:
			get_node("/root/global").enterMenu()


simplifying steering to a single line with move_toward (#451)

* simplyfied the steering to a single line with lerp

Replaced:
	if steer_target < steer_angle:
		steer_angle -= STEER_SPEED * delta
		if steer_target > steer_angle:
			steer_angle = steer_target
	elif steer_target > steer_angle:
		steer_angle += STEER_SPEED * delta
		if steer_target < steer_angle:
			steer_angle = steer_target

	steering = steer_angle
with
	steering = lerp(steering, steer_target, STEER_SPEED)

and lowered STEER_SPEED to 0.2

* Update vehicle.gd

* added space around *

extends VehicleBody

const STEER_SPEED = 1
const STEER_LIMIT = 0.4

var steer_target = 0

export var engine_force_value = 40

func _physics_process(delta):
	var fwd_mps = transform.basis.xform_inv(linear_velocity).x

	steer_target = Input.get_action_strength("turn_left") - Input.get_action_strength("turn_right")
	steer_target *= STEER_LIMIT

	if Input.is_action_pressed("accelerate"):
		engine_force = engine_force_value
	else:
		engine_force = 0

	if Input.is_action_pressed("reverse"):
		if (fwd_mps >= -1):
			engine_force = -engine_force_value
		else:
			brake = 1
	else:
		brake = 0.0

	steering = move_toward(steering, steer_target, STEER_SPEED * delta)

extends VehicleBody

const STEER_SPEED = 1
const STEER_LIMIT = 0.4

var steer_angle = 0
var steer_target = 0

export var engine_force_value = 40

func _physics_process(delta):
	var fwd_mps = transform.basis.xform_inv(linear_velocity).x

	steer_target = Input.get_action_strength("turn_left") - Input.get_action_strength("turn_right")
	steer_target *= STEER_LIMIT

	if Input.is_action_pressed("accelerate"):
		engine_force = engine_force_value
	else:
		engine_force = 0

	if Input.is_action_pressed("reverse"):
		if (fwd_mps >= -1):
			engine_force = -engine_force_value
		else:
			brake = 1
	else:
		brake = 0.0

	if steer_target < steer_angle:
		steer_angle -= STEER_SPEED * delta
		if steer_target > steer_angle:
			steer_angle = steer_target
	elif steer_target > steer_angle:
		steer_angle += STEER_SPEED * delta
		if steer_target < steer_angle:
			steer_angle = steer_target

	steering = steer_angle


Need some changes

Need some changes

Need to change scene changer or do smth this it

extends Control

var currentScreen = "intro.tscn"
var previousScreen = "intro.tscn"

var options = {
fullscreen = false,
windowSize = Vector2(OS.get_window_size()),
screenSize = Vector2(OS.get_screen_size())
}

var level_0Player = {
bullet = "bullet_0"
}

func save_game():
	var f = File.new()
	var err = f.open_encrypted_with_pass("user://savedata.bin", File.WRITE, "mamke_privet,_cheater_poganii")
	f.store_var(options)
	f.close()

func load_game():
	var f = File.new()
	if !f.file_exists("user://savedata.bin"):
		return #Error!  We don't have a save to load
	var err = f.open_encrypted_with_pass("user://savedata.bin", File.READ, "mamke_privet,_cheater_poganii")
	options = f.get_var()
	f.close()

func set_screen(sceneInScreensFolder):
	#add screen changer for all, or rework this systen, cos its pass not for all situations
	get_tree().change_scene("res://screens/" + sceneInScreensFolder)
	previousScreen = currentScreen
	currentScreen = sceneInScreensFolder

func get_currentScreen(scene):
	return(currentScreen)

func get_previousScreen(scene):
	return(previousScreen)

#func save_game():
#	var savegame = File.new()
#	savegame.open("user://savegame.save", File.WRITE)
#	var savenodes = get_tree().get_nodes_in_group("Persist")
#	for i in savenodes:
#		var nodedata = i.save()
#		savegame.store_line(nodedata.to_json())
#		savegame.close()
#
#func load_game():
#	var savegame = File.new()
#	if !savegame.file_exists("user://savegame.save"):
#		return #Error!  We don't have a save to load
#
# We need to revert the game state so we're not cloning objects during loading.  This will vary wildly depending on the needs of a project, so take care with this step.
# For our example, we will accomplish this by deleting savable objects.
#	var savenodes = get_tree().get_nodes_in_group("Persist")
#	for i in savenodes:
#		i.queue_free()
#
# Load the file line by line and process that dictionary to restore the object it represents
#	var currentline = {} # dict.parse_json() requires a declared dict.
#	savegame.open("user://savegame.save", File.READ)
#	while (!savegame.eof_reached()):
#		currentline.parse_json(savegame.get_line())
# First we need to create the object and add it to the tree and set its position.
#		var newobject = load(currentline["filename"]).instance()
#		get_node(currentline["parent"]).add_child(newobject)
#		newobject.set_pos(Vector2(currentline["posx"],currentline["posy"]))
# Now we set the remaining variables.
#		for i in currentline.keys():
#			if (i == "filename" or i == "parent" or i == "posx" or i == "posy"):
#				continue
#			newobject.set(i, currentline[i])
#	savegame.close()

func _ready():
	load_game()

func _exit_tree():
	save_game()

extends Control

var options = {
fullscreen = false,
windowSize = Vector2(OS.get_window_size()),
screenSize = Vector2(OS.get_screen_size())
}

var level_0Player = {
bullet = "bullet_0"
}

func save_game():
	var f = File.new()
	var err = f.open_encrypted_with_pass("user://savedata.bin", File.WRITE, "mamke_privet,_cheater_poganii")
	f.store_var(options)
	f.close()

func load_game():
	var f = File.new()
	if !f.file_exists("user://savedata.bin"):
		return #Error!  We don't have a save to load
	var err = f.open_encrypted_with_pass("user://savedata.bin", File.READ, "mamke_privet,_cheater_poganii")
	options = f.get_var()
	f.close()

#func save_game():
#	var savegame = File.new()
#	savegame.open("user://savegame.save", File.WRITE)
#	var savenodes = get_tree().get_nodes_in_group("Persist")
#	for i in savenodes:
#		var nodedata = i.save()
#		savegame.store_line(nodedata.to_json())
#		savegame.close()
#
#func load_game():
#	var savegame = File.new()
#	if !savegame.file_exists("user://savegame.save"):
#		return #Error!  We don't have a save to load
#
# We need to revert the game state so we're not cloning objects during loading.  This will vary wildly depending on the needs of a project, so take care with this step.
# For our example, we will accomplish this by deleting savable objects.
#	var savenodes = get_tree().get_nodes_in_group("Persist")
#	for i in savenodes:
#		i.queue_free()
#
# Load the file line by line and process that dictionary to restore the object it represents
#	var currentline = {} # dict.parse_json() requires a declared dict.
#	savegame.open("user://savegame.save", File.READ)
#	while (!savegame.eof_reached()):
#		currentline.parse_json(savegame.get_line())
# First we need to create the object and add it to the tree and set its position.
#		var newobject = load(currentline["filename"]).instance()
#		get_node(currentline["parent"]).add_child(newobject)
#		newobject.set_pos(Vector2(currentline["posx"],currentline["posy"]))
# Now we set the remaining variables.
#		for i in currentline.keys():
#			if (i == "filename" or i == "parent" or i == "posx" or i == "posy"):
#				continue
#			newobject.set(i, currentline[i])
#	savegame.close()

func _ready():
	load_game()

func _exit_tree():
	save_game()


add sub-puzzle to self, not to camera

add sub-puzzle to self, not to camera

# Provides functionality for the puzzle itself

extends Spatial

var DataMan = preload( "res://scripts/DataManager.gd" ).new()
var PuzzleManScript = preload( "res://scripts/PuzzleManager.gd" )
var PuzzleScn = preload("res://puzzle.scn")
var puzzleMan
var seed
var otherPuzzle
var generateRandom = true
var mainPuzzle = false

var time = {
		on = true,
		val = 0.0,
		label = Label.new(),
		tween = Tween.new() }

func addTimer():
	add_child(time.label)
	add_child(time.tween)
	time.label.set_pos(Vector2(15,15))

	time.label.set_theme(load("res://themes/MainTheme.thm"))
	time.tween.interpolate_method(time.label, "set_pos", \
			time.label.get_pos(), time.label.get_pos()*2, 0.5, \
			Tween.TRANS_BOUNCE, Tween.EASE_OUT)
	time.tween.start()
	time.label.set_text(str(time.val))

func formatTime(t):
	var mins = floor(t / 60)
	var secs = fmod(floor(t), 60)
	var millis = floor((t - floor(t)) * 1000)
	return str(mins) + ":" + str(secs).pad_zeros(2) + ":" + str(millis).pad_zeros(3)

func _process(dTime):
	# start label tween on
	time.val += dTime
	time.label.set_text(formatTime(time.val))
	if fmod(time.val, 10) < 0.1:
		time.tween.seek(0.0)

# Called for initialization
func _ready():
	if time.on:
		set_process(true) # needed for time keeping
	addTimer()

	#set up network stuffs
	add_child(load("res://networkProxy.scn").instance())
	var Network = Globals.get("Network")
	if Network != null:
		Network.proxy.set_process(Network.isClient or Network.isHost)

	# generate puzzle
	puzzleMan = PuzzleManScript.new()

	if generateRandom:
		seed = OS.get_unix_time() # unix time
		seed *= OS.get_ticks_msec() # initial time
		seed *= 1 + OS.get_time().second
		seed *= 1 + OS.get_date().weekday
		seed = abs(seed) % 7919 # 1000th prime

		var puzzle = puzzleMan.generatePuzzle( 1, puzzleMan.DIFF_EASY )
		puzzle.puzzleMan = puzzleMan
		var steps = puzzle.solvePuzzleSteps()
		print("Generated ", puzzle.shape.size(), " blocks." )
		print( "PUZZLE IS SOLVEABLE?: ", steps.solveable )

		var gridMan = get_node( "GridView/GridMan" )
		DataMan.savePuzzle("test.pzl", puzzle)
		var pCopy = DataMan.loadPuzzle("test.pzl")
		gridMan.set_puzzle(puzzle)

	# make a new puzzle, embed using Viewport
	if mainPuzzle:
		var p = PuzzleScn.instance()
		p.get_node("GridView").active = false
		p.mainPuzzle = false
		p.set_scale(Vector3(0.5, 0.5, 0.5))
		p.set_translation(Vector3(10, 5, -20))

		var v = Viewport.new()
		var c = Control.new()

		v.set_world(p.get_world())
		v.set_rect(Rect2(0, 0, 100, 100))
		v.set_physics_object_picking(false)
		add_child(p)
		v.add_child(p)
		add_child(c)
		c.add_child(v)
		otherPuzzle = p #for use with network

# Provides functionality for the puzzle itself

extends Spatial

var DataMan = preload( "res://scripts/DataManager.gd" ).new()
var PuzzleManScript = preload( "res://scripts/PuzzleManager.gd" )
var PuzzleScn = preload("res://puzzle.scn")
var puzzleMan
var seed
var otherPuzzle
var generateRandom = true
var mainPuzzle = false

var time = {
		on = true,
		val = 0.0,
		label = Label.new(),
		tween = Tween.new() }

func addTimer():
	add_child(time.label)
	add_child(time.tween)
	time.label.set_pos(Vector2(15,15))

	time.label.set_theme(load("res://themes/MainTheme.thm"))
	time.tween.interpolate_method(time.label, "set_pos", \
			time.label.get_pos(), time.label.get_pos()*2, 0.5, \
			Tween.TRANS_BOUNCE, Tween.EASE_OUT)
	time.tween.start()
	time.label.set_text(str(time.val))

func formatTime(t):
	var mins = floor(t / 60)
	var secs = fmod(floor(t), 60)
	var millis = floor((t - floor(t)) * 1000)
	return str(mins) + ":" + str(secs).pad_zeros(2) + ":" + str(millis).pad_zeros(3)

func _process(dTime):
	# start label tween on
	time.val += dTime
	time.label.set_text(formatTime(time.val))
	if fmod(time.val, 10) < 0.1:
		time.tween.seek(0.0)

# Called for initialization
func _ready():
	if time.on:
		set_process(true) # needed for time keeping
	addTimer()

	#set up network stuffs
	add_child(load("res://networkProxy.scn").instance())
	var Network = Globals.get("Network")
	if Network != null:
		Network.proxy.set_process(Network.isClient or Network.isHost)

	# generate puzzle
	puzzleMan = PuzzleManScript.new()

	if generateRandom:
		seed = OS.get_unix_time() # unix time
		seed *= OS.get_ticks_msec() # initial time
		seed *= 1 + OS.get_time().second
		seed *= 1 + OS.get_date().weekday
		seed = abs(seed) % 7919 # 1000th prime

		var puzzle = puzzleMan.generatePuzzle( 1, puzzleMan.DIFF_EASY )
		puzzle.puzzleMan = puzzleMan
		var steps = puzzle.solvePuzzleSteps()
		print("Generated ", puzzle.shape.size(), " blocks." )
		print( "PUZZLE IS SOLVEABLE?: ", steps.solveable )

		get_node( "GridView/GridMan" ).set_puzzle(puzzle)

	# make a new puzzle, embed using Viewport
	if mainPuzzle:
		var p = PuzzleScn.instance()
		#p.remove_and_delete_child(p.get_node("Lights"))
		#.remove_and_delete_child(p.get_node("Camera"))
		p.get_node("GridView").active = false
		p.mainPuzzle = false
		p.set_scale(Vector3(0.5, 0.5, 0.5))
		p.set_translation(Vector3(10, 5, -20))

		var v = Viewport.new()
		var c = Control.new()

		v.set_world(p.get_world())
		v.set_rect(Rect2(0, 0, 100, 100))
		v.set_physics_object_picking(false)
		get_tree().get_root().get_node( "Spatial" ).get_node( "Camera" ).add_child(p)
		v.add_child(p)
		add_child(c)
		c.add_child(v)
		otherPuzzle = p #for use with network
# child of control? easier input


random puzzle generation can now be toggled

# Provides functionality for the puzzle itself

extends Spatial

var DataMan = preload( "res://scripts/DataManager.gd" ).new()
var PuzzleManScript = preload( "res://scripts/PuzzleManager.gd" )
var PuzzleScn = preload("res://puzzle.scn")
var puzzleMan
var seed
var otherPuzzle
var generateRandom = true
var mainPuzzle = false

var time = {
		on = true,
		val = 0.0,
		label = Label.new(),
		tween = Tween.new() }

func addTimer():
	add_child(time.label)
	add_child(time.tween)
	time.label.set_pos(Vector2(15,15))

	time.label.set_theme(load("res://themes/MainTheme.thm"))
	time.tween.interpolate_method(time.label, "set_pos", \
			time.label.get_pos(), time.label.get_pos()*2, 0.5, \
			Tween.TRANS_BOUNCE, Tween.EASE_OUT)
	time.tween.start()
	time.label.set_text(str(time.val))

func formatTime(t):
	var mins = floor(t / 60)
	var secs = fmod(floor(t), 60)
	var millis = floor((t - floor(t)) * 1000)
	return str(mins) + ":" + str(secs).pad_zeros(2) + ":" + str(millis).pad_zeros(3)

func _process(dTime):
	# start label tween on
	time.val += dTime
	time.label.set_text(formatTime(time.val))
	if fmod(time.val, 10) < 0.1:
		time.tween.seek(0.0)

# Called for initialization
func _ready():
	if time.on:
		set_process(true) # needed for time keeping
	addTimer()

	#set up network stuffs
	add_child(load("res://networkProxy.scn").instance())
	var Network = Globals.get("Network")
	if Network != null:
		Network.proxy.set_process(Network.isClient or Network.isHost)

	# generate puzzle
	puzzleMan = PuzzleManScript.new()
	var puzzle = puzzleMan.generatePuzzle( 1, puzzleMan.DIFF_EASY )
	puzzle.puzzleMan = puzzleMan

	if generateRandom:
		seed = OS.get_unix_time() # unix time
		seed *= OS.get_ticks_msec() # initial time
		seed *= 1 + OS.get_time().second
		seed *= 1 + OS.get_date().weekday
		seed = abs(seed) % 7919 # 1000th prime

		print("Generated ", puzzle.blocks.size(), " blocks." )
		var steps = puzzle.solvePuzzleSteps()
		print( "PUZZLE IS SOLVEABLE?: ", steps.solveable )

		get_node( "GridView/GridMan" ).set_puzzle(puzzle)

	# make a new puzzle, embed using Viewport
	if mainPuzzle:
		var p = PuzzleScn.instance()
		#p.remove_and_delete_child(p.get_node("Lights"))
		#.remove_and_delete_child(p.get_node("Camera"))
		p.get_node("GridView").active = false
		p.mainPuzzle = false
		p.set_scale(Vector3(0.5, 0.5, 0.5))
		p.set_translation(Vector3(10, 5, -20))

		var v = Viewport.new()
		var c = Control.new()

		v.set_world(p.get_world())
		v.set_rect(Rect2(0, 0, 100, 100))
		v.set_physics_object_picking(false)
		get_tree().get_root().get_node( "Spatial" ).get_node( "Camera" ).add_child(p)
		v.add_child(p)
		add_child(c)
		c.add_child(v)
		otherPuzzle = p #for use with network
# child of control? easier input

# Provides functionality for the puzzle itself

extends Spatial

var DataMan = preload( "res://scripts/DataManager.gd" ).new()
var PuzzleManScript = preload( "res://scripts/PuzzleManager.gd" )
var PuzzleScn = preload("res://puzzle.scn")
var puzzleMan
var seed
var otherPuzzle
var mainPuzzle = false

var time = {
		on = true,
		val = 0.0,
		label = Label.new(),
		tween = Tween.new() }

func addTimer():
	add_child(time.label)
	add_child(time.tween)
	time.label.set_pos(Vector2(15,15))

	time.label.set_theme(load("res://themes/MainTheme.thm"))
	time.tween.interpolate_method(time.label, "set_pos", \
			time.label.get_pos(), time.label.get_pos()*2, 0.5, \
			Tween.TRANS_BOUNCE, Tween.EASE_OUT)
	time.tween.start()
	time.label.set_text(str(time.val))

func formatTime(t):
	var mins = floor(t / 60)
	var secs = fmod(floor(t), 60)
	var millis = floor((t - floor(t)) * 1000)
	return str(mins) + ":" + str(secs).pad_zeros(2) + ":" + str(millis).pad_zeros(3)

func _process(dTime):
	# start label tween on
	time.val += dTime
	time.label.set_text(formatTime(time.val))
	if fmod(time.val, 10) < 0.1:
		time.tween.seek(0.0)

# Called for initialization
func _ready():
	seed = OS.get_unix_time() # unix time
	seed *= OS.get_ticks_msec() # initial time
	seed *= 1 + OS.get_time().second
	seed *= 1 + OS.get_date().weekday
	seed = abs(seed) % 7919 # 1000th prime

	if time.on:
		set_process(true) # needed for time keeping

	# generate puzzle
	puzzleMan = PuzzleManScript.new()
	var puzzle = puzzleMan.generatePuzzle( 1, puzzleMan.DIFF_EASY )
	puzzle.puzzleMan = puzzleMan

	#set up network stuffs
	add_child(load("res://networkProxy.scn").instance())
	var Network = Globals.get("Network")
	if Network != null:
		Network.proxy.set_process(Network.isClient or Network.isHost)

	print("Generated ", puzzle.blocks.size(), " blocks." )

	print( "Saving seed " + str(seed) + "..." )
	DataMan.savePuzzle( "SavedPuzzles/RandomPuzzle" + str(seed) + ".pzl", puzzle )

	puzzle = 0

	puzzle = DataMan.loadPuzzle( "SavedPuzzles/RandomPuzzle" + str(seed) + ".pzl" )

	var steps = puzzle.solvePuzzleSteps()
	print( "PUZZLE IS SOLVEABLE?: ", steps.solveable )

	addTimer()

	# Place the blocks in the puzzle.
	var gridMan = get_node( "GridView/GridMan" )
	gridMan.set_puzzle(puzzle)

	# make a new puzzle, embed using Viewport
	if mainPuzzle:
		var p = PuzzleScn.instance()
		#p.remove_and_delete_child(p.get_node("Lights"))
		#.remove_and_delete_child(p.get_node("Camera"))
		p.get_node("GridView").active = false
		p.mainPuzzle = false
		p.set_scale(Vector3(0.5, 0.5, 0.5))
		p.set_translation(Vector3(10, 5, -20))

		var v = Viewport.new()
		var c = Control.new()

		v.set_world(p.get_world())
		v.set_rect(Rect2(0, 0, 100, 100))
		v.set_physics_object_picking(false)
		get_tree().get_root().get_node( "Spatial" ).get_node( "Camera" ).add_child(p)
		v.add_child(p)
		add_child(c)
		c.add_child(v)
		otherPuzzle = p #for use with network
# child of control? easier input


Disabled input checking on navmesh skript, caused crash on mouse events.

extends Navigation2D
var path = []
var font = null
var drawTouch = false
var touchPos = Vector2(0,0)
var closestPos = Vector2(0,0)

func _ready():
	font = load("res://resources/mono_font.fnt")
	# set_process_input(true)
	# var n = get_node("Genmap1")
	#var w = get_node("/root/globals").MAP_WIDTH
	#var h = get_node("/root/globals").MAP_HEIGHT
	#var clear_tile = n.get_tileset().find_tile_by_name("blank")
	#for x in range(w):
	#	for y in range(h):
	#		n.set_cell(x, y, clear_tile)
	#n.set_cell(4, 5, n.get_tileset().find_tile_by_name("wood_wall_l"))
	#n.set_cell(25, 5, n.get_tileset().find_tile_by_name("wood_wall_r"))
	#for x in range(20):
	#	n.set_cell(5 + x, 5, n.get_tileset().find_tile_by_name("wood_wall_m"))

func _draw():
	if(path.size()):
		for i in range(path.size()):
			draw_string(font,Vector2(path[i].x,path[i].y - 20),str(i+1))
			draw_circle(path[i],10,Color(1,1,1))

		if(drawTouch):
			draw_circle(touchPos,10,Color(0,1,0))
			draw_circle(closestPos,10,Color(0,1,0))

func _input(event):
	if(event.type == InputEvent.MOUSE_BUTTON):
		if(event.button_index == 1):
			if(path.size()):
				# touchPos = get_parent().get_node("Player_object").get_node("Camera2D").get_translated_pos(Vector2(event.x, event.y))
				touchPos = get_global_mouse_pos()
				drawTouch = true
				closestPos = get_closest_point(touchPos)
				print("Drawing touch")
				update()

		if(event.button_index == 2):
			# var sp = get_parent().get_node("Player_object").get_node("Camera2D").get_translated_pos(Vector2(event.x, event.y))
			var sp = get_global_mouse_pos()
			#path = get_simple_path(get_parent().get_node("Mob 2").get_pos(), sp)
			var new_curve = Curve2D.new()
			for p in path:
				# print(p)
				new_curve.add_point(Vector2(p.x, p.y))
			get_parent().get_node("Mob 2").get_node("Path2D").set_curve(new_curve)
			get_parent().get_node("Mob 2").get_node("Path2D").get_node("PathFollow2D").set_unit_offset(0.0)
			get_parent().get_node("Mob 2").get_node("Path2D").get_node("PathFollow2D").set_loop(false)
			# print(get_parent().get_node("Mob 2").get_node("Path2D").get_node("PathFollow2D"))
			# print(path)
			update()

extends Navigation2D
var path = []
var font = null
var drawTouch = false
var touchPos = Vector2(0,0)
var closestPos = Vector2(0,0)

func _ready():
	font = load("res://resources/mono_font.fnt")
	set_process_input(true)
	# var n = get_node("Genmap1")
	#var w = get_node("/root/globals").MAP_WIDTH
	#var h = get_node("/root/globals").MAP_HEIGHT
	#var clear_tile = n.get_tileset().find_tile_by_name("blank")
	#for x in range(w):
	#	for y in range(h):
	#		n.set_cell(x, y, clear_tile)
	#n.set_cell(4, 5, n.get_tileset().find_tile_by_name("wood_wall_l"))
	#n.set_cell(25, 5, n.get_tileset().find_tile_by_name("wood_wall_r"))
	#for x in range(20):
	#	n.set_cell(5 + x, 5, n.get_tileset().find_tile_by_name("wood_wall_m"))

func _draw():
	if(path.size()):
		for i in range(path.size()):
			draw_string(font,Vector2(path[i].x,path[i].y - 20),str(i+1))
			draw_circle(path[i],10,Color(1,1,1))

		if(drawTouch):
			draw_circle(touchPos,10,Color(0,1,0))
			draw_circle(closestPos,10,Color(0,1,0))

func _input(event):
	if(event.type == InputEvent.MOUSE_BUTTON):
		if(event.button_index == 1):
			if(path.size()):
				# touchPos = get_parent().get_node("Player_object").get_node("Camera2D").get_translated_pos(Vector2(event.x, event.y))
				touchPos = get_global_mouse_pos()
				drawTouch = true
				closestPos = get_closest_point(touchPos)
				print("Drawing touch")
				update()

		if(event.button_index == 2):
			# var sp = get_parent().get_node("Player_object").get_node("Camera2D").get_translated_pos(Vector2(event.x, event.y))
			var sp = get_global_mouse_pos()
			path = get_simple_path(get_parent().get_node("Mob 2").get_pos(), sp)
			var new_curve = Curve2D.new()
			for p in path:
				# print(p)
				new_curve.add_point(Vector2(p.x, p.y))
			get_parent().get_node("Mob 2").get_node("Path2D").set_curve(new_curve)
			get_parent().get_node("Mob 2").get_node("Path2D").get_node("PathFollow2D").set_unit_offset(0.0)
			get_parent().get_node("Mob 2").get_node("Path2D").get_node("PathFollow2D").set_loop(false)
			# print(get_parent().get_node("Mob 2").get_node("Path2D").get_node("PathFollow2D"))
			# print(path)
			update()


Reverted hit rumble power

Reverted hit rumble power

extends RigidBody2D

var bag
var ship = preload("res://scripts/ship.gd")

var GRAVITY_FACTOR = 100000000000

var current_acceleration = Vector2(0, 0)
var current_gravity = Vector2(0, 0)

var initial_velocity = Vector2(0, 0)
var started = false

var engines = []

var owner

func _integrate_forces(s):
    var pos = self.get_pos()

    if pos.distance_to(Vector2(5000, 5000)) > 3000:
        self.queue_free()

    var lv = s.get_linear_velocity()
    var step = s.get_step()

    var engines_on = {"Main" : true, "Left": false, "Right" : false}

    self.set_rot(lv.angle() + 3.14)

    self.current_gravity = s.get_total_gravity() * step * self.GRAVITY_FACTOR
    lv += self.current_gravity
    self.current_acceleration = lv

    if not self.started:
        lv += self.initial_velocity
        self.started = true

    s.set_linear_velocity(lv)
    self.__engines_start(engines_on)

func _colliding_body(body):
    if body extends self.ship and body.player_id != self.owner:
        self.bag.players.players[self.owner].score += 10

    if body extends self.ship:
        var device_id = self.bag.players.players[body.player_id].gamepad_id
        Input.start_joy_vibration(device_id, 1, 0, 0.2)
        self.bag.players.players[body.player_id].swear()

    self.bag.sound.play('rocket_bang')
    self.bag.board.add_explosion(self.get_pos())
    self.queue_free()

func __engines_start(engines):
    for engine in engines:
        if engines[engine] == true:
            self.engines[engine].set_emitting(true)

func _ready():
    self.bag = self.get_node("/root/boctok").bag
    set_fixed_process(true)
    var engines = self.get_node("Engines")
    self.engines = {
        "Main" : engines.get_node("Main"),
        "Left" : engines.get_node("Left"),
        "Right" : engines.get_node("Right"),
    }

extends RigidBody2D

var bag
var ship = preload("res://scripts/ship.gd")

var GRAVITY_FACTOR = 100000000000

var current_acceleration = Vector2(0, 0)
var current_gravity = Vector2(0, 0)

var initial_velocity = Vector2(0, 0)
var started = false

var engines = []

var owner

func _integrate_forces(s):
    var pos = self.get_pos()

    if pos.distance_to(Vector2(5000, 5000)) > 3000:
        self.queue_free()

    var lv = s.get_linear_velocity()
    var step = s.get_step()

    var engines_on = {"Main" : true, "Left": false, "Right" : false}

    self.set_rot(lv.angle() + 3.14)

    self.current_gravity = s.get_total_gravity() * step * self.GRAVITY_FACTOR
    lv += self.current_gravity
    self.current_acceleration = lv

    if not self.started:
        lv += self.initial_velocity
        self.started = true

    s.set_linear_velocity(lv)
    self.__engines_start(engines_on)

func _colliding_body(body):
    if body extends self.ship and body.player_id != self.owner:
        self.bag.players.players[self.owner].score += 10

    if body extends self.ship:
        var device_id = self.bag.players.players[body.player_id].gamepad_id
        Input.start_joy_vibration(device_id, 0.5, 0, 0.2)
        self.bag.players.players[body.player_id].swear()

    self.bag.sound.play('rocket_bang')
    self.bag.board.add_explosion(self.get_pos())
    self.queue_free()

func __engines_start(engines):
    for engine in engines:
        if engines[engine] == true:
            self.engines[engine].set_emitting(true)

func _ready():
    self.bag = self.get_node("/root/boctok").bag
    set_fixed_process(true)
    var engines = self.get_node("Engines")
    self.engines = {
        "Main" : engines.get_node("Main"),
        "Left" : engines.get_node("Left"),
        "Right" : engines.get_node("Right"),
    }


Want to merge.

Want to merge.

const DIFF_EASY		= 0
const DIFF_MEDIUM	= 1
const DIFF_HARD		= 2

const BLOCK_LASER	= 0
const BLOCK_WILD	= 1
const BLOCK_PAIR	= 2
const BLOCK_GOAL	= 3
const BLOCK_BLOCK   = 4

const blockColors = ["Blue", "Orange", "Red", "Yellow", "Purple", "Green"]
const wildColors = ["WildBlue", "WildOrange", "WildRed", "WildYellow", "WildPurple", "WildGreen"]

# Preload paired blocks
const blockScn = preload( "res://blocks/block.scn" )
const blockScripts = [ preload( "Blocks/LaserBlock.gd" )
			   	      , preload( "Blocks/LaserBlock.gd" )
			   	      , preload( "Blocks/PairedBlock.gd" )
			   	      , preload( "Blocks/LaserBlock.gd" )
			   	      ]
const aBlock = preload( "Blocks/AbstractBlock.gd" )

# Hash map of all possible positions
var shape = {}

# Stores a puzzle in a convenient class.
class Puzzle:
	var puzzleName
	var puzzleLayers
	var blocks = []
	var lasers = []

	var puzzleMan

	# Converts a puzzle to a dictionary.
	func toDict():
		var blockArr = []
		for b in range( blocks.size() ):
			blockArr.append( blocks[b].toDict() )

		var di = { pN = puzzleName
		 	     , pL = puzzleLayers
				 , bL = blockArr
			     }
		return di

	# Converts a dictionary to a puzzle.
	func fromDict( di ):
		puzzleName = di.pN
		puzzleLayers = di.pL
		for b in range( di.bL.size() ):
			var nb = puzzleMan.PickledBlock.new()
			nb.fromDict( di.bL[b] )
			blocks.append( nb )
		return

	# Determines if a puzzle is solveable.
	func solvePuzzle():
		# Simply use the solvePuzzleSteps function and return the solveable part.
		var ps = self.solvePuzzleSteps()
		return ps.solveable

	# Determines if a puzzle is solveable and returns the steps needed to solve it.
	func solvePuzzleSteps():
		var puzzleSteps = PuzzleSteps.new()
		puzzleSteps.solveable = true

		var lasers = []
		var pairs = []
		var wildblocks = []

		# Split the blocks into lasers, pairs and wild blocks.
		for b in blocks:
			if b.blockClass == BLOCK_PAIR:
				pairs.append( b )
			if b.blockClass == BLOCK_LASER:
				lasers.append( b )
			if b.blockClass == BLOCK_WILD:
				wildblocks.append( b )

		return puzzleSteps

	# Holds all of the steps needed to solve a puzzle.
	class PuzzleSteps:
		var solveable

# Randomly shuffle an array.
func shuffleArray( arr ):
	for i in range( arr.size() - 1, 1, -1 ):
		var swapVal = randi() % (i + 1)
		var temp = arr[swapVal]
		arr[swapVal] = arr[i]
		arr[i] = temp

# calculate the layer; move into a method so that it can be used elsewhere
func calcBlockLayer( x, y, z ):
	return max( max( abs( x ), abs( y ) ), abs( z ) )

# Determines the block type based on puzzle size and difficulty.
func getBlockType( difficulty, x, y, z ):
	# Determine if this is the goal block.
	if x == 0 and y == 0 and z == 0:
		return BLOCK_GOAL

	# Determine the layer this block is on.
	var layer = calcBlockLayer( x, y, z )

	# Determine how many blocks are on the outer part of the layer.
	var layerCount = 0
	if abs( x ) == layer:
		layerCount += 1
	if abs( y ) == layer:
		layerCount += 1
	if abs( z ) == layer:
		layerCount += 1

	# Determine if this block is a laser.
	if difficulty == DIFF_EASY or difficulty == DIFF_MEDIUM:
		if layerCount == 3:
			return BLOCK_LASER

	if difficulty == DIFF_HARD:
		if abs( x ) == abs( z ) and y == 0:
			return BLOCK_LASER

	# Determine if this block is a wild block.
	if difficulty == DIFF_EASY:
		if layerCount == 2:
			return BLOCK_WILD

	if difficulty == DIFF_MEDIUM:
		if layerCount == 2:
			if y == layer || y == -layer:
				return BLOCK_WILD

	if difficulty == DIFF_HARD:
		if layerCount == 1:
			if y == 0:
				return BLOCK_WILD

	# Otherwise it's a normal block.
	return BLOCK_PAIR

# Generates a solveable puzzle.
func generatePuzzle( layers, difficulty ):
	var blockID = 0
	var puzzle = Puzzle.new()
	puzzle.puzzleName = "RANDOM PUZZLE"
	puzzle.puzzleLayers = layers

	# Create all possible positions.
	var layeredblocks = []
	for l in range( 0, layers + 1 ):
		layeredblocks.append( [] )
	for x in range( -layers, layers + 1 ):
		for y in range( -layers, layers + 1 ):
			for z in range( -layers, layers + 1 ):
				layeredblocks[calcBlockLayer( x, y, z )].append(Vector3(x,y,z))
				shape[Vector3(x,y,z)] = null

	# Generate laser lines.
	for l in range( 1, layers + 1 ):
		if difficulty == DIFF_EASY:
			for lx in [ -l, l ]:
				for lz in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, lx, lz ), Vector3( lx + lx*-1, lx, lz )] )
					puzzle.lasers.append( [Vector3( lx, lx, lz ), Vector3( lx, lx + lx*-1, lz )] )
					puzzle.lasers.append( [Vector3( lx, lx, lz ), Vector3( lx, lx, lz + lz*-1 )] )

		if difficulty == DIFF_MEDIUM:
			for lx in [ -l, l ]:
				for ly in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, ly, lx ), Vector3( lx + lx*-1, ly, lx )] )
					puzzle.lasers.append( [Vector3( lx, ly, lx ), Vector3( lx, ly, lx + lx*-1 )] )

		if difficulty == DIFF_HARD:
			for lx in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, 0, lx ), Vector3( lx + lx*-1, 0, lx )] )
					puzzle.lasers.append( [Vector3( lx, 0, lx ), Vector3( lx, 0, lx + lx*-1 )] )

	#for l in puzzle.lasers:
	#	pass #print( l )

	# print( "LASERS ", puzzle.lasers.size() )

	# Assign block types based on position.
	for l in range( 0, layers + 1 ):
		# Randomize the pairs.
		shuffleArray( layeredblocks[l] )
		# print( "NUM ", layeredblocks[l].size() )
		var prevBlock = null
		var even = false
		var prevLaser = null
		var laserEven = false
		for pos in layeredblocks[l]:
			var x = pos.x
			var y = pos.y
			var z = pos.z

			var t = getBlockType( difficulty, x, y, z )

			if t == BLOCK_GOAL:
				continue

			var b = PickledBlock.new()
			b.blockPos = pos
			b.name = blockID

			blockID += 1
			puzzle.blocks.append( b )

			if t == BLOCK_LASER:
				b.setBlockClass(BLOCK_LASER)
				if laserEven:
					b.setPairName(prevLaser.name) \
					.setLaserExtent(prevLaser.blockPos - b.blockPos)

					prevLaser.setPairName(b.name) \
					.setLaserExtent(b.blockPos - prevLaser.blockPos)
				laserEven = not laserEven
				prevLaser = b
				continue

			if t == BLOCK_WILD:
				b.setBlockClass(BLOCK_PAIR) \
					.setTextureName(wildColors[randi() % wildColors.size()])
				continue

			if even:
				var randColor = blockColors[randi() % blockColors.size()]
				b.setBlockClass(BLOCK_PAIR) \
					.setPairName(prevBlock.name) \
					.setTextureName(randColor)

				prevBlock.setBlockClass(BLOCK_PAIR) \
					.setPairName(b.name) \
					.setTextureName(randColor)
			even = not even
			prevBlock = b

	return puzzle

class PickledBlock:
	var name
	var blockClass = BLOCK_PAIR
	var pairName
	var textureName = "Red"
	var blockPos
	var laserExtent

	func setName(n):
		name = n
		return self

	func setPairName(n):
		pairName = n
		return self

	func setLaserExtent(n):
		laserExtent = n
		return self

	func setBlockClass(c):
		blockClass = c
		return self

	func setTextureName(t):
		textureName = t
		return self

	func toString():
		return str(name) + ": " + str(blockClass)

	func toNode():
		# instantiate a block scene, assign the appropriate script to it
		var n = blockScn.instance()
		n.set_script(blockScripts[blockClass])

		# configure block node
		n.setName(str(name)).setTexture()
		n.blockPos = blockPos
		if blockClass == BLOCK_PAIR:
			n.setPairName(pairName).setTexture(textureName)

		if blockClass == BLOCK_LASER:
			n.setPairName(pairName).setExtent(laserExtent)
		return n

	# Convert this object to a dictionary.
	func toDict():
		var di = { n = name
		 	     , bC = blockClass
			     , pN = pairName
			     , tN = textureName
			     , bP = blockPos
			     , lE = laserExtent
			     }
		return di

	# Make this object from a dictionary.
	func fromDict( di ):
		name = di.n
		blockClass = di.bC
		pairName = di.pN
		textureName = di.tN
		blockPos = di.bP
		laserExtent = di.lE

const DIFF_EASY		= 0
const DIFF_MEDIUM	= 1
const DIFF_HARD		= 2

const BLOCK_LASER	= 0
const BLOCK_WILD	= 1
const BLOCK_PAIR	= 2
const BLOCK_GOAL	= 3
const BLOCK_BLOCK   = 4

const blockColors = ["Blue", "Orange", "Red", "Yellow", "Purple", "Green"]
const wildColors = ["WildBlue", "WildOrange", "WildRed", "WildYellow", "WildPurple", "WildGreen"]

# Preload paired blocks
const blockScn = preload( "res://blocks/block.scn" )
const blockScripts = [ preload( "Blocks/LaserBlock.gd" )
			   	      , preload( "Blocks/LaserBlock.gd" )
			   	      , preload( "Blocks/PairedBlock.gd" )
			   	      , preload( "Blocks/LaserBlock.gd" )
			   	      ]
const aBlock = preload( "Blocks/AbstractBlock.gd" )

# Hash map of all possible positions
var shape = {}

# Stores a puzzle in a convenient class.
class Puzzle:
	var puzzleName
	var puzzleLayers
	var blocks = []
	var lasers = []

	var puzzleMan

	# Converts a puzzle to a dictionary.
	func toDict():
		var blockArr = []
		for b in range( blocks.size() ):
			blockArr.append( blocks[b].toDict() )

		var di = { pN = puzzleName
		 	     , pL = puzzleLayers
				 , bL = blockArr
			     }
		return di

	# Converts a dictionary to a puzzle.
	func fromDict( di ):
		puzzleName = di.pN
		puzzleLayers = di.pL
		for b in range( di.bL.size() ):
			var nb = puzzleMan.PickledBlock.new()
			nb.fromDict( di.bL[b] )
			blocks.append( nb )
		return

	# Determines if a puzzle is solveable.
	func solvePuzzle():
		# Simply use the solvePuzzleSteps function and return the solveable part.
		var ps = self.solvePuzzleSteps()
		return ps.solveable

	# Determines if a puzzle is solveable and returns the steps needed to solve it.
	func solvePuzzleSteps():
		var puzzleSteps = PuzzleSteps.new()
		puzzleSteps.solveable = true

		# SOLVER

		return puzzleSteps

	# Holds all of the steps needed to solve a puzzle.
	class PuzzleSteps:
		var solveable

# Randomly shuffle an array.
func shuffleArray( arr ):
	for i in range( arr.size() - 1, 1, -1 ):
		var swapVal = randi() % (i + 1)
		var temp = arr[swapVal]
		arr[swapVal] = arr[i]
		arr[i] = temp

# calculate the layer; move into a method so that it can be used elsewhere
func calcBlockLayer( x, y, z ):
	return max( max( abs( x ), abs( y ) ), abs( z ) )

# Determines the block type based on puzzle size and difficulty.
func getBlockType( difficulty, x, y, z ):
	# Determine if this is the goal block.
	if x == 0 and y == 0 and z == 0:
		return BLOCK_GOAL

	# Determine the layer this block is on.
	var layer = calcBlockLayer( x, y, z )

	# Determine how many blocks are on the outer part of the layer.
	var layerCount = 0
	if abs( x ) == layer:
		layerCount += 1
	if abs( y ) == layer:
		layerCount += 1
	if abs( z ) == layer:
		layerCount += 1

	# Determine if this block is a laser.
	if difficulty == DIFF_EASY or difficulty == DIFF_MEDIUM:
		if layerCount == 3:
			return BLOCK_LASER

	if difficulty == DIFF_HARD:
		if abs( x ) == abs( z ) and y == 0:
			return BLOCK_LASER

	# Determine if this block is a wild block.
	if difficulty == DIFF_EASY:
		if layerCount == 2:
			return BLOCK_WILD

	if difficulty == DIFF_MEDIUM:
		if layerCount == 2:
			if y == layer || y == -layer:
				return BLOCK_WILD

	if difficulty == DIFF_HARD:
		if layerCount == 1:
			if y == 0:
				return BLOCK_WILD

	# Otherwise it's a normal block.
	return BLOCK_PAIR

# Generates a solveable puzzle.
func generatePuzzle( layers, difficulty ):
	var blockID = 0
	var puzzle = Puzzle.new()
	puzzle.puzzleName = "RANDOM PUZZLE"
	puzzle.puzzleLayers = layers

	# Create all possible positions.
	var layeredblocks = []
	for l in range( 0, layers + 1 ):
		layeredblocks.append( [] )
	for x in range( -layers, layers + 1 ):
		for y in range( -layers, layers + 1 ):
			for z in range( -layers, layers + 1 ):
				layeredblocks[calcBlockLayer( x, y, z )].append(Vector3(x,y,z))
				shape[Vector3(x,y,z)] = null

	# Generate laser lines.
	for l in range( 1, layers + 1 ):
		if difficulty == DIFF_EASY:
			for lx in [ -l, l ]:
				for lz in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, lx, lz ), Vector3( lx + lx*-1, lx, lz )] )
					puzzle.lasers.append( [Vector3( lx, lx, lz ), Vector3( lx, lx + lx*-1, lz )] )
					puzzle.lasers.append( [Vector3( lx, lx, lz ), Vector3( lx, lx, lz + lz*-1 )] )

		if difficulty == DIFF_MEDIUM:
			for lx in [ -l, l ]:
				for ly in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, ly, lx ), Vector3( lx + lx*-1, ly, lx )] )
					puzzle.lasers.append( [Vector3( lx, ly, lx ), Vector3( lx, ly, lx + lx*-1 )] )

		if difficulty == DIFF_HARD:
			for lx in [ -l, l ]:
					puzzle.lasers.append( [Vector3( lx, 0, lx ), Vector3( lx + lx*-1, 0, lx )] )
					puzzle.lasers.append( [Vector3( lx, 0, lx ), Vector3( lx, 0, lx + lx*-1 )] )

	for l in puzzle.lasers:
		print( l )

	# print( "LASERS ", puzzle.lasers.size() )

	# Assign block types based on position.
	for l in range( 0, layers + 1 ):
		# Randomize the pairs.
		shuffleArray( layeredblocks[l] )
		# print( "NUM ", layeredblocks[l].size() )
		var prevBlock = null
		var even = false
		var prevLaser = null
		var laserEven = false
		for pos in layeredblocks[l]:
			var x = pos.x
			var y = pos.y
			var z = pos.z

			var t = getBlockType( difficulty, x, y, z )

			if t == BLOCK_GOAL:
				continue

			var b = PickledBlock.new()
			b.blockPos = pos
			b.name = blockID

			blockID += 1
			puzzle.blocks.append( b )

			if t == BLOCK_LASER:
				b.setBlockClass(BLOCK_LASER)
				if laserEven:
					b.setPairName(prevLaser.name) \
					.setLaserExtent(prevLaser.blockPos - b.blockPos)

					prevLaser.setPairName(b.name) \
					.setLaserExtent(b.blockPos - prevLaser.blockPos)
				laserEven = not laserEven
				prevLaser = b
				continue

			if t == BLOCK_WILD:
				b.setBlockClass(BLOCK_PAIR) \
					.setTextureName(wildColors[randi() % wildColors.size()])
				continue

			if even:
				var randColor = blockColors[randi() % blockColors.size()]
				b.setBlockClass(BLOCK_PAIR) \
					.setPairName(prevBlock.name) \
					.setTextureName(randColor)

				prevBlock.setBlockClass(BLOCK_PAIR) \
					.setPairName(b.name) \
					.setTextureName(randColor)
			even = not even
			prevBlock = b

	return puzzle

class PickledBlock:
	var name
	var blockClass = BLOCK_PAIR
	var pairName
	var textureName = "Red"
	var blockPos
	var laserExtent

	func setName(n):
		name = n
		return self

	func setPairName(n):
		pairName = n
		return self

	func setLaserExtent(n):
		laserExtent = n
		return self

	func setBlockClass(c):
		blockClass = c
		return self

	func setTextureName(t):
		textureName = t
		return self

	func toString():
		return str(name) + ": " + str(blockClass)

	func toNode():
		# instantiate a block scene, assign the appropriate script to it
		var n = blockScn.instance()
		n.set_script(blockScripts[blockClass])

		# configure block node
		n.setName(str(name)).setTexture()
		n.blockPos = blockPos
		if blockClass == BLOCK_PAIR:
			n.setPairName(pairName).setTexture(textureName)

		if blockClass == BLOCK_LASER:
			n.setPairName(pairName).setExtent(laserExtent)
		return n

	# Convert this object to a dictionary.
	func toDict():
		var di = { n = name
		 	     , bC = blockClass
			     , pN = pairName
			     , tN = textureName
			     , bP = blockPos
			     , lE = laserExtent
			     }
		return di

	# Make this object from a dictionary.
	func fromDict( di ):
		name = di.n
		blockClass = di.bC
		pairName = di.pN
		textureName = di.tN
		blockPos = di.bP
		laserExtent = di.lE