broken_seals/game/scripts/dungeons/dungeon.gd

221 lines
5.2 KiB
GDScript

tool
extends Spatial
export(bool) var generate_on_ready : bool = true
export(PropData) var start_room : PropData
export(Array, PropData) var rooms : Array
export(bool) var generate : bool setget set_generate, get_generate
#todo calc aabbs and store in PropData during prop conversion
var room_aabbs : Dictionary
var portal_map : Dictionary
var portals : Array
var current_aabbs : Array
var debug : bool = true
func _enter_tree() -> void:
if not Engine.editor_hint && generate_on_ready:
call_deferred("generate")
func set_up_room_data() -> void:
clear_room_data()
process_prop(start_room)
for r in rooms:
process_prop(r)
process_portals()
func process_prop(room : PropData) -> void:
if !room:
return
if !room.is_room:
return
if room in room_aabbs:
return
var ps : PoolVector3Array = room.room_bounds
var aabb : AABB = AABB()
for p in ps:
aabb.expand(p)
room_aabbs[room] = aabb
for i in range(room.props.size()):
var pe : PropDataEntry = room.props[i]
if pe is PropDataPortal:
portals.append([pe, room, i])
func process_portals() -> void:
for i in range(portals.size()):
var pe = portals[i]
var portal : PropDataPortal = pe[0]
var room : PropData = pe[1]
var portal_points : PoolVector2Array = portal.points
if portal in portal_map:
continue
var map_data : Array = Array()
for j in range(portals.size()):
if i == j:
continue
var pp : Array = portals[j]
var cportal : PropDataPortal = pp[0]
var cportal_points : PoolVector2Array = cportal.points
if (cportal_points.size() != portal_points.size()):
continue
var eq : bool = true
for k in range(portal_points.size()):
var p1 : Vector2 = portal_points[k]
var p2 : Vector2 = cportal_points[k]
if !p1.is_equal_approx(p2):
eq = false
break
if !eq:
continue
var croom : PropData = pp[1]
var cj : int = pp[2]
map_data.append([ croom, cportal, cj ])
portal_map[portal] = map_data
#print(portal_map)
func clear_room_data() -> void:
portal_map.clear()
portals.clear()
room_aabbs.clear()
current_aabbs.clear()
func generate() -> void:
clear()
set_up_room_data()
spawn_room(Transform(), start_room)
func spawn_room(room_lworld_transform : Transform, room : PropData, level : int = 0, current_portal : PropDataPortal = null) -> void:
if level > 4:
return
var sr : PropInstanceMerger = PropInstanceMerger.new()
sr.prop_data = room
add_child(sr)
if current_portal:
var lworld_curr_portal : Transform = current_portal.transform
#portal center should be precalculated
#this will only work with the current portals
lworld_curr_portal = lworld_curr_portal.translated(Vector3(-0.5, 0, 0))
lworld_curr_portal.basis = lworld_curr_portal.basis.rotated(Vector3(0, 1, 0), PI)
room_lworld_transform = room_lworld_transform * lworld_curr_portal.inverse()
sr.transform = room_lworld_transform
if Engine.editor_hint and debug:
sr.owner = get_tree().edited_scene_root
#var caabb : AABB = room_aabbs[room]
#caabb.position = tf.xform(Vector3())
#current_aabbs.push_back(caabb)
for pe in room.props:
if pe is PropDataPortal:
if pe == current_portal:
continue
var current_portal_lworld_position : Transform = room_lworld_transform * pe.transform
var d : Array = portal_map[pe]
if d.size() == 0:
continue
randomize()
var new_room_data = d[randi() % d.size()]
#[ croom, cportal, cj ]
var new_room : PropData = new_room_data[0]
var new_room_portal : PropDataPortal = new_room_data[1]
#todo figure out the transforms
var poffset : Vector3 = new_room_portal.transform.xform(Vector3())
#middle of the current portal
var offset_current_portal_lworld_position : Transform = current_portal_lworld_position
#portal center should be precalculated
#this will only work with the current portals
offset_current_portal_lworld_position = offset_current_portal_lworld_position.translated(Vector3(-0.5, 0, 0))
#var ab : AABB = room_aabbs[new_room]
#ab.position = offsert_ntf.xform(Vector3())
test_spawn_pos(offset_current_portal_lworld_position)
var can_spawn : bool = true
#for saab in current_aabbs:
# if ab.intersects(saab):
# #todo implement plugs
# can_spawn = false
# break
if can_spawn:
spawn_room(offset_current_portal_lworld_position, new_room, level + 1, new_room_portal)
func clear() -> void:
if Engine.editor_hint and debug:
#don't destroy the user's nodes
for c in get_children():
if c.owner == get_tree().edited_scene_root:
c.queue_free()
else:
for c in get_children():
c.queue_free()
func test_spawn_pos(lworld_position : Transform):
var testspat : ImmediateGeometry = ImmediateGeometry.new()
add_child(testspat)
testspat.transform = lworld_position
testspat.begin(Mesh.PRIMITIVE_LINES)
testspat.add_vertex(Vector3(0, -0.5, 0))
testspat.add_vertex(Vector3(0, 0.5, 0))
testspat.add_vertex(Vector3(-0.5, 0, 0))
testspat.add_vertex(Vector3(0.5, 0, 0))
testspat.add_vertex(Vector3(0, 0, -0.5))
testspat.add_vertex(Vector3(0, 0, 0.5))
testspat.end()
func set_generate(on) -> void:
if on:
generate()
func get_generate() -> bool:
return false