stuff
This commit is contained in:
604
autoload/characters.gd
Normal file
604
autoload/characters.gd
Normal file
@@ -0,0 +1,604 @@
|
||||
extends Characters_
|
||||
|
||||
|
||||
# Declare member variables here. Examples:
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
#func _process(delta):
|
||||
|
||||
onready var female = preload("res://characters/vroid1-female.tscn")
|
||||
onready var male = preload("res://characters/vroid1-man.tscn")
|
||||
onready var face_ctrl = preload("res://scenes/face/head_comtrol.tscn")
|
||||
onready var modules = {
|
||||
# "physics": load("res://scripts/modules/character_physics.gd"),
|
||||
"cmdq": load("res://scripts/modules/cmdq.gd"),
|
||||
"marker": load("res://scripts/modules/npc_marker.gd"),
|
||||
"sacrifice": load("res://scripts/modules/npc_sacrifice.gd"),
|
||||
"nun": load("res://scripts/modules/npc_nun.gd"),
|
||||
"player": load("res://scripts/modules/player_controls.gd"),
|
||||
"player_clothes": load("res://scripts/modules/player_clothes.gd"),
|
||||
"hurtboxes": load("res://scripts/modules/character_hurtboxes.gd"),
|
||||
"student": load("res://scripts/modules/npc_student.gd")
|
||||
}
|
||||
|
||||
var face_data_path = "res://scenes/face/"
|
||||
var hair_data_path = "res://scenes/hair/"
|
||||
var female_faces = []
|
||||
var male_faces = []
|
||||
var female_hairs = []
|
||||
var male_hairs = []
|
||||
var hair_materials = []
|
||||
|
||||
var name_data = {}
|
||||
var rnd
|
||||
|
||||
var roommates = {}
|
||||
|
||||
#var _crowd: DetourCrowdManager
|
||||
|
||||
func _ready():
|
||||
set_root_motion_mod(Transform())
|
||||
var fd = File.new()
|
||||
fd.open("res://data/names.json", File.READ)
|
||||
var names = fd.get_as_text()
|
||||
var result = JSON.parse(names)
|
||||
name_data = result.result
|
||||
rnd = RandomNumberGenerator.new()
|
||||
var data_fd: = File.new()
|
||||
for g in ["male", "female"]:
|
||||
var fp = face_data_path + g + "-face.tscn"
|
||||
if data_fd.file_exists(fp):
|
||||
match g:
|
||||
"female":
|
||||
female_faces.push_back(fp)
|
||||
"male":
|
||||
male_faces.push_back(fp)
|
||||
for id in range(10000):
|
||||
var fp_m = face_data_path + "male-face" + str(id) + ".tscn"
|
||||
var fp_f = face_data_path + "female-face" + str(id) + ".tscn"
|
||||
var hp_m = hair_data_path + "male-hair" + str(id) + ".tscn"
|
||||
var hp_f = hair_data_path + "female-hair" + str(id) + ".tscn"
|
||||
var mat = hair_data_path + "hair" + str(id) + ".tres"
|
||||
if data_fd.file_exists(fp_m):
|
||||
male_faces.push_back(fp_m)
|
||||
if data_fd.file_exists(fp_f):
|
||||
female_faces.push_back(fp_f)
|
||||
if data_fd.file_exists(hp_m):
|
||||
male_hairs.push_back(hp_m)
|
||||
if data_fd.file_exists(hp_f):
|
||||
female_hairs.push_back(hp_f)
|
||||
if data_fd.file_exists(mat):
|
||||
hair_materials.push_back(mat)
|
||||
assert(male_faces.size() > 0)
|
||||
assert(female_faces.size() > 0)
|
||||
assert(male_hairs.size() > 0)
|
||||
assert(female_hairs.size() > 0)
|
||||
assert(hair_materials.size() > 0)
|
||||
|
||||
func get_relationship(obj1, obj2, s) -> int:
|
||||
var stats1 = {}
|
||||
var stats2 = {}
|
||||
if obj1.has_meta("stats"):
|
||||
stats1 = obj1.get_meta("stats")
|
||||
if obj2.has_meta("stats"):
|
||||
stats2 = obj2.get_meta("stats")
|
||||
if !stats2.has("relationships"):
|
||||
return 0
|
||||
var rel = stats2.relationships
|
||||
var cid = stats1.firstname + stats1.lastname
|
||||
if !rel.has(cid):
|
||||
return 0
|
||||
var rel_data = rel[cid]
|
||||
if rel_data.has(s):
|
||||
return rel_data[s]
|
||||
return 0
|
||||
func set_relationships(obj1, obj2, s, v: int) -> void:
|
||||
assert(obj1)
|
||||
assert(obj2)
|
||||
var stats1 = {}
|
||||
var stats2 = {}
|
||||
if obj1.has_meta("stats"):
|
||||
stats1 = obj1.get_meta("stats")
|
||||
if obj2.has_meta("stats"):
|
||||
stats2 = obj2.get_meta("stats")
|
||||
if !stats2.has("relationships"):
|
||||
stats2.relationships = {}
|
||||
var rel = stats2.relationships
|
||||
var cid = stats1.firstname + stats1.lastname
|
||||
if !rel.has(cid):
|
||||
rel[cid] = {}
|
||||
rel[cid][s] = v
|
||||
print(stats2)
|
||||
obj2.set_meta("stats", stats2)
|
||||
func get_face_node(sc: Node) -> Node:
|
||||
var face_node_paths = ["skeleton/Skeleton/head/face", "Skeleton/head/face"]
|
||||
for e in face_node_paths:
|
||||
if sc.has_node(e):
|
||||
print("face node: ", e)
|
||||
return sc.get_node(e)
|
||||
assert(0)
|
||||
return null
|
||||
|
||||
func get_hair_node(sc: Node) -> Node:
|
||||
var hair_node_paths = ["skeleton/Skeleton/head/hair", "Skeleton/head/hair"]
|
||||
for e in hair_node_paths:
|
||||
if sc.has_node(e):
|
||||
print("hair node: ", e)
|
||||
return sc.get_node(e)
|
||||
assert(0)
|
||||
return null
|
||||
func compose_kinematic_character(g, enable_modules = [], face = -1, hair = -1, hair_mat = -1):
|
||||
var body = KinematicBody.new()
|
||||
var cshape = CollisionShape.new()
|
||||
body.add_child(cshape)
|
||||
var capsule = CapsuleShape.new()
|
||||
var character_data = {
|
||||
"sex": g,
|
||||
"modules": enable_modules
|
||||
}
|
||||
var face_scene: PackedScene
|
||||
var hair_scene: PackedScene
|
||||
var face_i: Node
|
||||
var hair_i: Node
|
||||
var face_node: Node
|
||||
var hair_node: Node
|
||||
match g:
|
||||
"female":
|
||||
if face == -1:
|
||||
face = rnd.randi() % female_faces.size()
|
||||
if hair == -1:
|
||||
hair = rnd.randi() % female_hairs.size()
|
||||
face_scene = load(female_faces[face])
|
||||
hair_scene = load(female_hairs[hair])
|
||||
capsule.radius = 0.2
|
||||
capsule.height = 1.1
|
||||
capsule.margin = 0.05
|
||||
cshape.translation.x = 0
|
||||
cshape.translation.y = 0.751
|
||||
cshape.translation.z = 0
|
||||
cshape.rotation = Vector3(-PI/2.0, 0, 0)
|
||||
var i = female.instance()
|
||||
body.add_child(i)
|
||||
i.transform = Transform()
|
||||
face_node = get_face_node(i)
|
||||
hair_node = get_hair_node(i)
|
||||
"male":
|
||||
if face == -1:
|
||||
face = rnd.randi() % male_faces.size()
|
||||
if hair == -1:
|
||||
hair = rnd.randi() % male_hairs.size()
|
||||
face_scene = load(male_faces[face])
|
||||
hair_scene = load(male_hairs[hair])
|
||||
capsule.radius = 0.3
|
||||
capsule.height = 1.2
|
||||
capsule.margin = 0.05
|
||||
cshape.translation.x = 0
|
||||
cshape.translation.y = 0.899
|
||||
cshape.translation.z = 0
|
||||
cshape.rotation = Vector3(-PI/2.0, 0, 0)
|
||||
var i = male.instance()
|
||||
body.add_child(i)
|
||||
i.transform = Transform()
|
||||
face_node = get_face_node(i)
|
||||
hair_node = get_hair_node(i)
|
||||
assert(face_node)
|
||||
face_i = face_scene.instance()
|
||||
face_i.add_to_group("face")
|
||||
prepare_extra_skeleton(face_i, "face")
|
||||
hair_i = hair_scene.instance()
|
||||
hair_i.add_to_group("hair")
|
||||
prepare_extra_skeleton(hair_i, "hair")
|
||||
if hair_mat == -1:
|
||||
hair_mat = rnd.randi() % hair_materials.size()
|
||||
var hmat = load(hair_materials[hair_mat])
|
||||
assert(hmat)
|
||||
set_hair_material(hair_i, hmat)
|
||||
for e in face_node.get_children():
|
||||
e.queue_free()
|
||||
for e in hair_node.get_children():
|
||||
e.queue_free()
|
||||
face_node.add_child(face_i)
|
||||
hair_node.add_child(hair_i)
|
||||
var face_ctrl_i = face_ctrl.instance()
|
||||
face_ctrl_i.active = true
|
||||
face_i.add_child(face_ctrl_i)
|
||||
face_i.set_meta("body", body)
|
||||
body.set_meta("face_control", face_ctrl_i)
|
||||
body.set_meta("face_playback", "parameters/state/playback")
|
||||
face_ctrl_i.add_to_group("face")
|
||||
face_i.transform = Transform()
|
||||
character_data.face = face
|
||||
character_data.hair = hair
|
||||
character_data.hair_mat = hair_mat
|
||||
cshape.shape = capsule
|
||||
body.set_meta("character_data", character_data)
|
||||
for e in enable_modules:
|
||||
assert(modules.has(e))
|
||||
if modules.has(e):
|
||||
assert(modules[e])
|
||||
var obj = modules[e].new()
|
||||
body.add_child(obj)
|
||||
setup_character_physics(body)
|
||||
body.add_to_group("character")
|
||||
return body
|
||||
|
||||
func replace_character(obj, g, enable_modules = [], face = -1, hair = -1, hair_mat = -1):
|
||||
assert(obj)
|
||||
var xform = obj.global_transform
|
||||
var p = obj.get_parent()
|
||||
obj.queue_free()
|
||||
var body = compose_kinematic_character(g, enable_modules, face, hair, hair_mat)
|
||||
p.add_child(body)
|
||||
body.global_transform = xform
|
||||
var orientation = Transform()
|
||||
orientation.basis = xform.basis
|
||||
body.set_meta("orientation", orientation)
|
||||
return body
|
||||
const basedir = "res://scenes/clothes/"
|
||||
func prepare_extra_skeleton(obj, g):
|
||||
var queue = [obj]
|
||||
while queue.size() > 0:
|
||||
var item = queue.pop_front()
|
||||
if item is Skeleton:
|
||||
item.add_to_group(g)
|
||||
break
|
||||
for g in item.get_children():
|
||||
queue.push_back(g)
|
||||
func set_hair_material(hair, mat: Material):
|
||||
assert(mat)
|
||||
var queue = [hair]
|
||||
while queue.size() > 0:
|
||||
var item = queue.pop_front()
|
||||
if item is MeshInstance:
|
||||
item.set_surface_material(0, mat)
|
||||
break
|
||||
for g in item.get_children():
|
||||
queue.push_back(g)
|
||||
func setup_garments(obj, garments, garments_head, material):
|
||||
var skel = obj.get_meta("skeleton")
|
||||
var hair_skel = obj.get_meta("hair_skeleton")
|
||||
|
||||
if obj.has_meta("garments"):
|
||||
print("Can remove garments")
|
||||
var d = obj.get_meta("garments")
|
||||
var db = d.body_data
|
||||
var dh = d.head_data
|
||||
for e in db + dh:
|
||||
print("remove: ", e)
|
||||
# obj.remove_child(e)
|
||||
if e.get_parent() == obj:
|
||||
obj.remove_child(e)
|
||||
e.queue_free()
|
||||
var gdata_body = []
|
||||
for g in garments:
|
||||
var m: MeshInstance = MeshInstance.new()
|
||||
m.name = g
|
||||
print("loading: ", basedir + g + ".mesh")
|
||||
var geo: ArrayMesh = load(basedir + g + ".mesh")
|
||||
assert(geo)
|
||||
print("mesh: ", geo, "mat: ", material)
|
||||
geo.surface_set_material(0, material)
|
||||
m.mesh = geo
|
||||
# m.skeleton = m.get_path_to(root.get_meta("skeleton"))
|
||||
# = root.get_meta("skeleton")
|
||||
skel.add_child(m)
|
||||
m.transform = Transform()
|
||||
gdata_body.push_back(m)
|
||||
var gdata_head = []
|
||||
for g in garments_head:
|
||||
var m: MeshInstance = MeshInstance.new()
|
||||
m.name = g
|
||||
var geo: ArrayMesh = load(basedir + g + ".mesh")
|
||||
print("mesh: ", geo, "mat: ", material)
|
||||
geo.surface_set_material(0, material)
|
||||
m.mesh = geo
|
||||
# m.skeleton = m.get_path_to(root.get_meta("skeleton"))
|
||||
# = root.get_meta("skeleton")
|
||||
hair_skel.add_child(m)
|
||||
m.transform = Transform()
|
||||
gdata_head.push_back(m)
|
||||
var gdata = {
|
||||
"body": garments,
|
||||
"head": garments_head,
|
||||
"material": material,
|
||||
"body_data": gdata_body,
|
||||
"head_data": gdata_head
|
||||
}
|
||||
obj.set_meta("garments", gdata)
|
||||
|
||||
func lastname():
|
||||
var lastnames = name_data.lastname
|
||||
var d = lastnames.size()
|
||||
return lastnames[rnd.randi() % d].to_lower().capitalize()
|
||||
|
||||
func firstname(g):
|
||||
var firstnames = name_data[g].firstname
|
||||
var d = firstnames.size()
|
||||
return firstnames[rnd.randi() % d].to_lower().capitalize()
|
||||
|
||||
func generate_stats(npc: Node):
|
||||
var stats = npc.get_meta("stats")
|
||||
var strength = 10 + rnd.randi() % 100
|
||||
var max_health = 10 + rnd.randi() % 100
|
||||
var max_stamina = 10 + rnd.randi() % 100
|
||||
stats.tiredness = 0.0
|
||||
stats.hunger = 0.0
|
||||
stats.thirst = 0.0
|
||||
stats.libido = 0.0
|
||||
stats.toilet = 0.0
|
||||
stats.stress = 0.0
|
||||
stats.health = max_health
|
||||
stats.stamina = max_stamina
|
||||
stats.max_health = max_health
|
||||
stats.max_stamina = max_stamina
|
||||
stats.violence = rnd.randi() % (int(strength * 0.5))
|
||||
stats.xp = 0
|
||||
npc.set_meta("stats", stats)
|
||||
var stat_changes = {
|
||||
"sleep":{
|
||||
"tiredness": -0.3,
|
||||
"stress": -0.03
|
||||
},
|
||||
"eating": {
|
||||
"hunger": -0.9,
|
||||
"stress": -0.01
|
||||
},
|
||||
"drinking": {
|
||||
"thirst": -2.8,
|
||||
"stress": -0.01
|
||||
},
|
||||
"use_tap": {
|
||||
"thirst": -2.8,
|
||||
"stress": -0.01
|
||||
},
|
||||
"locomotion": {
|
||||
"tiredness": 0.0015,
|
||||
"hunger": 0.025,
|
||||
"thirst": 0.045,
|
||||
"stress": 0.0001,
|
||||
"libido": 0.00015,
|
||||
"toilet": 0.0002
|
||||
}
|
||||
}
|
||||
func update_stats(npc: Node):
|
||||
var stats = npc.get_meta("stats")
|
||||
if stats.tiredness < 10.0:
|
||||
if stats.stamina < stats.max_stamina:
|
||||
stats.stamina += 0.1
|
||||
stats.stamina = clamp(stats.stamina, 0, stats.max_stamina)
|
||||
var animtree = npc.get_meta("animation_tree")
|
||||
var state = animtree["parameters/state/playback"].get_current_node()
|
||||
if state in stat_changes.keys():
|
||||
for s in stat_changes[state].keys():
|
||||
stats[s] += stat_changes[state][s]
|
||||
if stats[s] < 0:
|
||||
stats[s] = 0.0
|
||||
npc.set_meta("stats", stats)
|
||||
|
||||
# Action part should be integrated into SmartObjectManager
|
||||
func check_leave_smart(npc: Node):
|
||||
return
|
||||
if !npc.has_meta("smart_object"):
|
||||
return
|
||||
var sm = npc.get_meta("smart_object")
|
||||
var new_goal = calculate_goal(npc)
|
||||
if !sm.is_in_group(new_goal):
|
||||
# var animtree = npc.get_meta("animation_tree")
|
||||
# animtree["parameters/state/playback"].travel("locomotion")
|
||||
npc.remove_meta("smart_object")
|
||||
|
||||
func calculate_goal(npc: Node):
|
||||
var utility = {
|
||||
"sleep": ["tiredness", 900],
|
||||
"hungry": ["hunger", 1000],
|
||||
"thirsty": ["thirst", 1300],
|
||||
"relieve_stress": ["stress", 800],
|
||||
"have_sex": ["libido", 500],
|
||||
"idle": ["", 600]
|
||||
}
|
||||
var stats = npc.get_meta("stats")
|
||||
var rutility = -10000
|
||||
var goal = "idle"
|
||||
var last_goal = ""
|
||||
var last_utility = -1
|
||||
if npc.has_meta("last_goal"):
|
||||
last_goal = npc.get_meta("last_goal")
|
||||
goal = npc.get_meta("last_goal")
|
||||
if npc.has_meta("last_utility"):
|
||||
last_utility = int(npc.get_meta("last_utility"))
|
||||
rutility = int(npc.get_meta("last_utility") * 2.0)
|
||||
for k in utility.keys():
|
||||
var st = 1.0
|
||||
if utility[k][0] != "":
|
||||
st = stats[utility[k][0]]
|
||||
var mul = utility[k][1]
|
||||
var cutil = int(st * mul)
|
||||
if rutility < cutil:
|
||||
rutility = cutil
|
||||
goal = k
|
||||
npc.set_meta("last_goal", goal)
|
||||
if goal == last_goal:
|
||||
npc.set_meta("last_utility", last_utility)
|
||||
else:
|
||||
npc.set_meta("last_utility", rutility)
|
||||
|
||||
return goal
|
||||
|
||||
var cooldown = 0.0
|
||||
|
||||
var close_groups = {}
|
||||
|
||||
func walkto_(npc, target):
|
||||
assert(npc.has_meta("agent_id"))
|
||||
if npc.has_mete("agent_id"):
|
||||
walkto_agent(npc, target)
|
||||
# if npc.has_meta("_target"):
|
||||
# var otarget = npc.get_meta("_target")
|
||||
# if target == otarget:
|
||||
# return
|
||||
# assert(npc.has_meta("agent_id"))
|
||||
# npc.set_meta("_target", target)
|
||||
## print("walk to ", target)
|
||||
## print("walk to ", target)
|
||||
## print("walk to ", target)
|
||||
# var agent_id = npc.get_meta("agent_id")
|
||||
# if target is Spatial:
|
||||
# get_crowd().set_agent_target_position(agent_id, target.global_transform.origin)
|
||||
# elif target is Vector3:
|
||||
# get_crowd().set_agent_target_position(agent_id, target)
|
||||
|
||||
#func update_to_agent(root):
|
||||
# if !_crowd:
|
||||
# return
|
||||
# if !root.has_meta("agent_id"):
|
||||
# _crowd.add_agent(root, 0, false, PoolRealArray([0.2, 1.5, 0.3, 3.0]))
|
||||
# if !root.has_meta("agent_id"):
|
||||
# return
|
||||
# if !root.has_meta("_target"):
|
||||
# return
|
||||
# var velocity = root.get_meta("agent_velocity")
|
||||
# if velocity.length() == 0:
|
||||
# characters.set_walk_speed(root, 0, 0)
|
||||
# else:
|
||||
## print("agent_velocity=", velocity)
|
||||
# var vel1 = velocity
|
||||
# vel1.y = 0
|
||||
# var xform: = Transform().looking_at(vel1, Vector3.UP)
|
||||
# xform = xform.orthonormalized()
|
||||
# var orientation = root.get_meta("orientation")
|
||||
# orientation.basis = orientation.basis.slerp(xform.basis, get_physics_process_delta_time())
|
||||
# root.set_meta("orientation", orientation)
|
||||
# characters.set_walk_speed(root, clamp(vel1.length() / 6.5, 0.0, 1.0), 0)
|
||||
#
|
||||
#func character_physics(root):
|
||||
# var delta = get_physics_process_delta_time()
|
||||
# var animtree = root.get_meta("animation_tree")
|
||||
# var orientation = root.get_meta("orientation")
|
||||
# var root_motion = animtree.get_root_motion_transform()
|
||||
# orientation *= root_motion
|
||||
# var h_velocity = orientation.origin / delta
|
||||
# var velocity: = Vector3()
|
||||
# velocity.x = h_velocity.x
|
||||
# velocity.z = h_velocity.z
|
||||
# velocity.y = h_velocity.y
|
||||
## if root.has_meta("climb"):
|
||||
## print("has climb meta")
|
||||
## if root.has_meta("cmdqueue"):
|
||||
## print("+has cmdqueue")
|
||||
# if !root.has_meta("vehicle") && !root.has_meta("cmdqueue"):
|
||||
# if root is KinematicBody:
|
||||
# if !root.is_on_floor():
|
||||
# velocity += Vector3(0, -9.8, 0)
|
||||
# velocity = root.move_and_slide(velocity, Vector3.UP, true, 4, 0.785, false)
|
||||
# elif root.has_meta("cmdqueue") && root.has_meta("cmdq_walk"):
|
||||
# if root is KinematicBody:
|
||||
# if !root.is_on_floor() && !root.has_meta("climb"):
|
||||
# velocity += Vector3(0, -9.8, 0)
|
||||
# velocity = root.move_and_slide(velocity, Vector3.UP, true, 4, 0.785, false)
|
||||
# elif root.has_meta("cmdqueue") && root.has_meta("climb"):
|
||||
# if root is KinematicBody:
|
||||
# velocity.y = h_velocity.y
|
||||
# velocity = root.move_and_slide(velocity, Vector3.UP, true, 4, 0.785, false)
|
||||
# orientation.origin = Vector3()
|
||||
# orientation = orientation.orthonormalized()
|
||||
# root.global_transform.basis = orientation.basis
|
||||
# root.set_meta("orientation", orientation)
|
||||
# if root.has_meta("vehicle"):
|
||||
# var vehicle: VehicleBody = get_meta("vehicle")
|
||||
# if has_meta("vehicle_offset"):
|
||||
# var xform = get_meta("vehicle_offset")
|
||||
# root.global_transform = vehicle.global_transform * xform
|
||||
# if root.has_node("blackboard"):
|
||||
# var bb = root.get_node("blackboard")
|
||||
# bb.set("velocity", velocity)
|
||||
# update_to_agent(root)
|
||||
|
||||
func check_main_animtree(item):
|
||||
if !item is AnimationTree:
|
||||
return false
|
||||
for g in ["hair", "face"]:
|
||||
if item.is_in_group(g):
|
||||
return false
|
||||
return true
|
||||
|
||||
func check_main_skeleton(item):
|
||||
if !item is Skeleton:
|
||||
return false
|
||||
for g in ["hair", "face"]:
|
||||
if item.is_in_group(g):
|
||||
return false
|
||||
return true
|
||||
|
||||
func setup_character_physics(root):
|
||||
var queue = [root]
|
||||
while queue.size() > 0:
|
||||
var item = queue.pop_front()
|
||||
if check_main_animtree(item):
|
||||
root.set_meta("animation_tree", item)
|
||||
if check_main_skeleton(item):
|
||||
root.set_meta("skeleton", item)
|
||||
if item is Skeleton && item.is_in_group("hair"):
|
||||
root.set_meta("hair_skeleton", item)
|
||||
if item is Skeleton && item.is_in_group("face"):
|
||||
root.set_meta("face_skeleton", item)
|
||||
for e in item.get_children():
|
||||
queue.push_back(e)
|
||||
# var velocity = Vector3()
|
||||
var orientation = Transform()
|
||||
if root.is_inside_tree():
|
||||
orientation = root.global_transform
|
||||
orientation.origin = Vector3()
|
||||
root.set_meta("orientation", orientation)
|
||||
|
||||
func _process(delta):
|
||||
if cooldown > 0.0:
|
||||
cooldown -= delta
|
||||
return
|
||||
for e in get_tree().get_nodes_in_group("character"):
|
||||
var gr = []
|
||||
for o in get_tree().get_nodes_in_group("character"):
|
||||
if e == o:
|
||||
continue
|
||||
var e_org = e.global_transform.origin
|
||||
var o_org = o.global_transform.origin
|
||||
if e_org.distance_to(o_org) < 1.2:
|
||||
gr.push_back(o)
|
||||
close_groups[e] = gr
|
||||
if e.has_meta("animation_tree"):
|
||||
var animtree = e.get_meta("animation_tree")
|
||||
var state = animtree["parameters/state/playback"].get_current_node()
|
||||
var face_playback = e.get_meta("face_playback")
|
||||
var face_ctrl = e.get_meta("face_control")
|
||||
var p = face_ctrl[face_playback]
|
||||
if state == "sleeping":
|
||||
if p.get_current_node() != "sleeping":
|
||||
p.travel("sleeping")
|
||||
else:
|
||||
if p.get_current_node() != "locomotion":
|
||||
p.travel("locomotion")
|
||||
cooldown = 0.2
|
||||
func get_player():
|
||||
var c = get_viewport().get_camera()
|
||||
if !c:
|
||||
return null
|
||||
if !c.has_meta("player"):
|
||||
return null
|
||||
var player = c.get_meta("player")
|
||||
if !player:
|
||||
return null
|
||||
return player
|
||||
|
||||
func _physics_process(delta):
|
||||
var player = get_player()
|
||||
if !player:
|
||||
return
|
||||
if player.has_meta("animation_tree") && !player.has_meta("vehicle"):
|
||||
character_physics(player)
|
||||
# for e in get_tree().get_nodes_in_group("character") + [player]:
|
||||
# if e && e.has_meta("animation_tree"):
|
||||
# character_physics(e)
|
||||
192
autoload/controls.gd
Normal file
192
autoload/controls.gd
Normal file
@@ -0,0 +1,192 @@
|
||||
extends Node
|
||||
|
||||
var is_gui = false
|
||||
|
||||
var rot_cam = Vector3()
|
||||
var mouse_sens = 0.3
|
||||
var camera_anglev = 0
|
||||
|
||||
var fps_mode = false
|
||||
var tmp_fps_mode = false
|
||||
var focus_cam: Camera
|
||||
var cam_focused: bool = false
|
||||
|
||||
var menu: Node
|
||||
func display_menu():
|
||||
menu.popup()
|
||||
|
||||
|
||||
func _ready():
|
||||
focus_cam = Camera.new()
|
||||
add_child(focus_cam)
|
||||
focus_cam.set_as_toplevel(true)
|
||||
# var escape_menu = preload("res://ui/save_game.tscn")
|
||||
# menu = escape_menu.instance()
|
||||
# add_child(menu)
|
||||
|
||||
func is_fps_mode():
|
||||
return fps_mode || tmp_fps_mode
|
||||
|
||||
func _input(event):
|
||||
if !is_gui:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
if event is InputEventMouseMotion && !is_gui:
|
||||
rot_cam.y = deg2rad(-event.relative.x * mouse_sens)
|
||||
var changev = -event.relative.y * mouse_sens
|
||||
var player
|
||||
if get_viewport().get_camera().has_meta("player"):
|
||||
player = get_viewport().get_camera().get_meta("player")
|
||||
if !player:
|
||||
return
|
||||
var cam = player.get_meta("cam")
|
||||
var fps_cam = player.get_meta("fps_cam")
|
||||
if cam.current:
|
||||
if camera_anglev + changev > -30 and camera_anglev + changev < 40:
|
||||
camera_anglev += changev
|
||||
rot_cam.x = deg2rad(changev)
|
||||
elif fps_cam.current:
|
||||
if camera_anglev + changev > -60 and camera_anglev + changev < 60:
|
||||
camera_anglev += changev
|
||||
rot_cam.x = deg2rad(changev)
|
||||
func focus_camera(obj):
|
||||
if !obj:
|
||||
print("NOTHING TO FOCUS")
|
||||
return
|
||||
if cam_focused:
|
||||
return
|
||||
print("FOCUS")
|
||||
var cur_cam = get_viewport().get_camera()
|
||||
var player = cur_cam.get_meta("player")
|
||||
var cam = player.get_meta("cam")
|
||||
focus_cam.global_transform = cam.global_transform
|
||||
var do = obj.global_transform.origin
|
||||
focus_cam.look_at(do, Vector3.UP)
|
||||
cam_focused = true
|
||||
focus_cam.set_meta("camera", cur_cam)
|
||||
focus_cam.set_current(true)
|
||||
focus_cam.set_meta("player", player)
|
||||
func unfocus_camera():
|
||||
cam_focused = false
|
||||
var ncam = focus_cam.get_meta("camera")
|
||||
ncam.set_current(true)
|
||||
|
||||
func fix_cam(state, _delta):
|
||||
var player = get_viewport().get_camera().get_meta("player")
|
||||
if !is_fps_mode():
|
||||
var cam = player.get_meta("cam")
|
||||
var cam_rot_y = cam.get_meta("cam_rot_y")
|
||||
var cam_rot_x = cam.get_meta("cam_rot_x")
|
||||
cam_rot_y.rotate_y(rot_cam.y)
|
||||
cam_rot_x.rotate_x(rot_cam.x)
|
||||
else:
|
||||
if !player.has_meta("vehicle") && !player.has_meta("cmdqueue"):
|
||||
var fps_cam = player.get_meta("fps_cam")
|
||||
var fps_cam_rot_x = fps_cam.get_meta("fps_cam_rot_x")
|
||||
var o: Transform = player.get_meta("orientation")
|
||||
o.basis = o.basis.rotated(Vector3(0, 1, 0), rot_cam.y)
|
||||
fps_cam_rot_x.rotate_x(rot_cam.x)
|
||||
player.set_meta("orientation", o)
|
||||
|
||||
rot_cam.y = 0
|
||||
rot_cam.x = 0
|
||||
func get_player():
|
||||
var c = get_viewport().get_camera()
|
||||
assert(c)
|
||||
if !c:
|
||||
return null
|
||||
assert(c.has_meta("player"))
|
||||
if !c.has_meta("player"):
|
||||
return null
|
||||
var player = c.get_meta("player")
|
||||
assert(player)
|
||||
if !player:
|
||||
return null
|
||||
assert(player)
|
||||
return player
|
||||
|
||||
func switch_fps_mode(value):
|
||||
var player = get_player()
|
||||
print(player)
|
||||
if !player:
|
||||
return
|
||||
assert(player != null)
|
||||
var cam = player.get_meta("cam")
|
||||
var fps_cam = player.get_meta("fps_cam")
|
||||
var cam_rot_y = cam.get_meta("cam_rot_y")
|
||||
if !value:
|
||||
cam.current = true
|
||||
player.show_face()
|
||||
#need to convert to globals
|
||||
cam_rot_y.rotation.y = player.rotation.y
|
||||
else:
|
||||
fps_cam.current = true
|
||||
player.hide_face()
|
||||
|
||||
var tmp_fps_cooldown = 0.0
|
||||
|
||||
|
||||
func _process(delta):
|
||||
var c = get_viewport().get_camera()
|
||||
if !c:
|
||||
return
|
||||
|
||||
if !c.has_meta("player"):
|
||||
return
|
||||
|
||||
var player = get_player()
|
||||
if !player:
|
||||
return
|
||||
if !is_gui && Input.is_action_just_pressed("ui_cancel"):
|
||||
is_gui = true
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||
display_menu()
|
||||
if !is_gui && Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
elif is_gui && Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||
var cam = player.get_meta("cam")
|
||||
var fps_cam = player.get_meta("fps_cam")
|
||||
var cam_pos = cam.get_meta("cam_pos")
|
||||
var cam_arm = cam.get_meta("cam_arm")
|
||||
cam_pos.global_transform.origin = player.global_transform.origin
|
||||
cam.look_at(player.global_transform.origin + Vector3(0, 1.9, 0), Vector3.UP)
|
||||
|
||||
if Input.is_action_just_pressed("fps_mode") && !tmp_fps_mode:
|
||||
fps_mode = !fps_mode
|
||||
switch_fps_mode(fps_mode)
|
||||
if !fps_mode && !tmp_fps_mode && !player.has_meta("vehicle"):
|
||||
var s = cam_arm.global_transform.origin
|
||||
var t = cam.global_transform.origin
|
||||
if tmp_fps_cooldown <= 0.0:
|
||||
if s.distance_to(t) < 0.3:
|
||||
tmp_fps_mode = true
|
||||
switch_fps_mode(tmp_fps_mode)
|
||||
tmp_fps_cooldown = 1.0
|
||||
if !fps_mode && tmp_fps_mode:
|
||||
var s = cam_arm.global_transform.origin
|
||||
var t = cam.global_transform.origin
|
||||
if tmp_fps_cooldown <= 0.0:
|
||||
if s.distance_to(t) > 0.4:
|
||||
tmp_fps_mode = false
|
||||
switch_fps_mode(tmp_fps_mode)
|
||||
tmp_fps_cooldown = 3.0
|
||||
if tmp_fps_cooldown > 0.0:
|
||||
tmp_fps_cooldown -= delta
|
||||
|
||||
var spawn_delay = 0.5
|
||||
func _physics_process(delta):
|
||||
if spawn_delay > 0.5:
|
||||
spawn_delay -= delta
|
||||
return
|
||||
var c = get_viewport().get_camera()
|
||||
if !c:
|
||||
return
|
||||
if !c.has_meta("player"):
|
||||
return
|
||||
var player = c.get_meta("player")
|
||||
if !player:
|
||||
return
|
||||
var space = player.get_world().space
|
||||
var state = PhysicsServer.space_get_direct_state(space)
|
||||
fix_cam(state, delta)
|
||||
|
||||
72
autoload/doors.gd
Normal file
72
autoload/doors.gd
Normal file
@@ -0,0 +1,72 @@
|
||||
extends Node
|
||||
|
||||
|
||||
# Declare member variables here. Examples:
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
var door_list = {}
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
func register_door(obj: Node, name, door_obj, axis, cangle, oangle, spd):
|
||||
assert(obj)
|
||||
assert(door_obj)
|
||||
var root_name = str(obj.get_path())
|
||||
if !door_list.has(root_name):
|
||||
door_list[root_name] = {}
|
||||
var base = door_obj.transform
|
||||
door_list[root_name][name] = {}
|
||||
door_list[root_name][name].obj = door_obj
|
||||
door_list[root_name][name].base = base
|
||||
door_list[root_name][name].axis = axis
|
||||
door_list[root_name][name].cangle = cangle
|
||||
door_list[root_name][name].oangle = oangle
|
||||
door_list[root_name][name].cur_angle = cangle
|
||||
door_list[root_name][name].speed = spd
|
||||
door_list[root_name][name].active = false
|
||||
door_list[root_name][name].state = 0
|
||||
func open_door(obj, name):
|
||||
var root_name = str(obj.get_path())
|
||||
if !door_list.has(root_name):
|
||||
return
|
||||
door_list[root_name][name].active = true
|
||||
door_list[root_name][name].state = 1
|
||||
func close_door(obj, name):
|
||||
var root_name = str(obj.get_path())
|
||||
if !door_list.has(root_name):
|
||||
return
|
||||
door_list[root_name][name].active = true
|
||||
door_list[root_name][name].state = 0
|
||||
func is_active(obj, name):
|
||||
var root_name = str(obj.get_path())
|
||||
if !door_list.has(root_name):
|
||||
return false
|
||||
return door_list[root_name][name].active
|
||||
func get_state(obj, name):
|
||||
var root_name = str(obj.get_path())
|
||||
if !door_list.has(root_name):
|
||||
return -1
|
||||
return door_list[root_name][name].state
|
||||
func _process(delta):
|
||||
for e in door_list.keys():
|
||||
for j in door_list[e].keys():
|
||||
var m = door_list[e][j]
|
||||
if m.active:
|
||||
var change = min(1.0, m.speed * delta)
|
||||
match m.state:
|
||||
0:
|
||||
if abs(m.cur_angle - m.cangle) < 0.001:
|
||||
m.cur_angle = m.cangle
|
||||
m.active = false
|
||||
else:
|
||||
m.cur_angle = lerp_angle(m.cur_angle, m.cangle, change)
|
||||
1:
|
||||
if abs(m.cur_angle - m.oangle) < 0.001:
|
||||
m.cur_angle = m.oangle
|
||||
m.active = false
|
||||
else:
|
||||
m.cur_angle = lerp_angle(m.cur_angle, m.oangle, change)
|
||||
m.obj.transform.basis = m.base.basis.rotated(m.axis, m.cur_angle)
|
||||
|
||||
131
autoload/freezer.gd
Normal file
131
autoload/freezer.gd
Normal file
@@ -0,0 +1,131 @@
|
||||
extends Node
|
||||
|
||||
|
||||
# Declare member variables here. Examples:
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
var freeze_dist = 20.0
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func freeze_character(c):
|
||||
var pos = c.transform
|
||||
var sp = Spatial.new()
|
||||
var pp = c.get_parent()
|
||||
var character_data = {}
|
||||
var stats = {}
|
||||
if c.has_meta("character_data"):
|
||||
character_data = c.get_meta("character_data")
|
||||
if c.has_meta("stats"):
|
||||
stats = c.get_meta("stats")
|
||||
pp.add_child(sp)
|
||||
sp.transform = pos
|
||||
sp.add_to_group("frozen")
|
||||
sp.set_meta("character_data", character_data)
|
||||
var animtree: AnimationTree = c.get_meta("animation_tree")
|
||||
assert(animtree)
|
||||
var animation_node = animtree["parameters/state/playback"].get_current_node()
|
||||
sp.set_meta("animation_node", animation_node)
|
||||
# sp.set_meta("animation_tree", str(c.get_path_to(animtree)))
|
||||
sp.set_meta("stats", stats)
|
||||
if characters.get_crowd():
|
||||
characters.get_crowd().remove_agent(c)
|
||||
c.queue_free()
|
||||
|
||||
func prepare_save_data() -> bool:
|
||||
if !freeze_all():
|
||||
return false
|
||||
scenario.save_data.characters = []
|
||||
for c in get_tree().get_nodes_in_group("frozen"):
|
||||
var n = {}
|
||||
n.character_data = c.get_meta("character_data")
|
||||
n.stats = c.get_meta("stats")
|
||||
n.animation_node = c.get_meta("animation_node")
|
||||
n.xform = var2str(c.global_transform)
|
||||
scenario.save_data.characters.push_back(n)
|
||||
return true
|
||||
func get_player():
|
||||
var c = get_viewport().get_camera()
|
||||
if !c:
|
||||
return null
|
||||
if !c.has_meta("player"):
|
||||
return null
|
||||
var player = c.get_meta("player")
|
||||
if !player:
|
||||
return null
|
||||
return player
|
||||
|
||||
func unfreeze_character(c):
|
||||
var data = c.get_meta("character_data")
|
||||
var stats = c.get_meta("stats")
|
||||
print("HAIR: ", data.hair, " ", data.hair_mat)
|
||||
var nc = characters.replace_character(c, data.sex, data.modules, data.face, data.hair, data.hair_mat)
|
||||
nc.set_meta("stats", stats)
|
||||
var animtree: AnimationTree = nc.get_meta("animation_tree")
|
||||
assert(animtree)
|
||||
var animation_node = c.get_meta("animation_node")
|
||||
animtree["parameters/state/playback"].start(animation_node)
|
||||
animtree["parameters/state/playback"].travel(animation_node)
|
||||
nc.set_meta("saved_anim_state", animation_node)
|
||||
var state = 0
|
||||
var delay = 0.0
|
||||
func freeze_all() -> bool:
|
||||
var player = get_player()
|
||||
var ok = true
|
||||
for c in get_tree().get_nodes_in_group("character"):
|
||||
if c == player:
|
||||
continue
|
||||
elif c.name.begins_with("npc_spawn"):
|
||||
c.queue_free()
|
||||
continue
|
||||
elif c.name == "npc" && !c.has_meta("animation_tree"):
|
||||
print("bad ", c.name, " ", c.get_meta_list())
|
||||
for e in c.get_meta_list():
|
||||
print("bad", c.get_meta(e))
|
||||
c.queue_free()
|
||||
continue
|
||||
assert(c.has_meta("animation_tree"))
|
||||
if c.has_meta("animation_tree"):
|
||||
freeze_character(c)
|
||||
else:
|
||||
ok = false
|
||||
assert(ok)
|
||||
return ok
|
||||
func _process(delta):
|
||||
var cam = get_viewport().get_camera()
|
||||
var player = get_player()
|
||||
if !player:
|
||||
return
|
||||
var cpos = cam.global_transform.origin
|
||||
match state:
|
||||
0:
|
||||
characters.set_process(false)
|
||||
for c in get_tree().get_nodes_in_group("character"):
|
||||
if c == player:
|
||||
continue
|
||||
var p = c.global_transform.origin
|
||||
if p.distance_squared_to(cpos) > freeze_dist * freeze_dist:
|
||||
if c.has_meta("animation_tree"):
|
||||
freeze_character(c)
|
||||
characters.set_process(true)
|
||||
state = 1
|
||||
delay = 1.0
|
||||
# print("spawned: ", get_tree().get_nodes_in_group("character").size())
|
||||
# print("frozen: ", get_tree().get_nodes_in_group("frozen").size())
|
||||
1:
|
||||
characters.set_process(false)
|
||||
for c in get_tree().get_nodes_in_group("frozen"):
|
||||
var p = c.global_transform.origin
|
||||
if p.distance_squared_to(cpos) < 0.25 * freeze_dist * freeze_dist:
|
||||
print("unfreeze")
|
||||
unfreeze_character(c)
|
||||
characters.set_process(true)
|
||||
if delay > 0.0:
|
||||
delay -= delta
|
||||
else:
|
||||
state = 0
|
||||
89
autoload/inventory.gd
Normal file
89
autoload/inventory.gd
Normal file
@@ -0,0 +1,89 @@
|
||||
extends Node
|
||||
signal pick_up(item_name, obj)
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
var items = {
|
||||
"s_dagger": false
|
||||
}
|
||||
|
||||
var item_dialogue = {
|
||||
"s_dagger": {
|
||||
"item_fullname": "sacrificial dagger",
|
||||
"item_artname": "the sacrificial dagger",
|
||||
"item_msg": "You see ancient dagger a small piece of metal with nothing special about it except the feeling of uneasiness and understanding that this is not ordinary weapon, but something with different purpose than just defeating the enemy. Something to thank bloodthirsty gods? Or avoid their wrath.",
|
||||
"item_take_msg": "You fill freezing touch of the rough dagger at your hand. You feel the touch of ancient history, of many many veins opened, and lots of hearts pierced.",
|
||||
"item_leave_msg": "You left the dagger be."
|
||||
}
|
||||
}
|
||||
|
||||
onready var item_scenes = {
|
||||
"s_dagger": load("res://scenes/weapons/sacrificial_dagger.tscn")
|
||||
}
|
||||
onready var item_collision_scenes = {
|
||||
"s_dagger": load("res://scenes/weapons/dagger_collision.tscn")
|
||||
}
|
||||
func equip(obj, item_name):
|
||||
if obj.has_meta("equipped"):
|
||||
return
|
||||
print("EQUIP ", item_name)
|
||||
assert(obj)
|
||||
assert(item_scenes.has(item_name))
|
||||
var r = item_scenes[item_name].instance()
|
||||
var c = item_collision_scenes[item_name].instance()
|
||||
obj.add_child(r)
|
||||
r.add_child(c)
|
||||
r.transform = Transform()
|
||||
c.transform = Transform()
|
||||
print("EQUIP ", item_name, " OK", obj, r)
|
||||
obj.set_meta("equipped", item_name)
|
||||
func register_pick_up(m, obj, item_name):
|
||||
var mdata = {
|
||||
"method": "pick_up",
|
||||
"item": item_name,
|
||||
"item_obj": obj
|
||||
}
|
||||
markers.init_marker(self, m, mdata)
|
||||
|
||||
func pick_up_dialogue(item, item_obj):
|
||||
return
|
||||
# if controls.is_gui:
|
||||
# return
|
||||
# Dialogic.set_autosave(false)
|
||||
# var scene = "pick_up_item"
|
||||
# print("SCENE: ", scene)
|
||||
# controls.is_gui = true
|
||||
# var dialogue = Dialogic.start(scene, false)
|
||||
# Dialogic.set_variable("item_name", item)
|
||||
# Dialogic.set_variable("item_fullname", item_dialogue[item].item_fullname)
|
||||
# Dialogic.set_variable("item_artname", item_dialogue[item].item_artname)
|
||||
# Dialogic.set_variable("item_msg", item_dialogue[item].item_msg)
|
||||
# Dialogic.set_variable("item_take_msg", item_dialogue[item].item_take_msg)
|
||||
# Dialogic.set_variable("item_leave_msg", item_dialogue[item].item_leave_msg)
|
||||
# add_child(dialogue)
|
||||
# dialogue.connect("timeline_end", self, "finish_dialogue", [dialogue])
|
||||
# dialogue.connect("dialogic_signal", self, "signal_process", [dialogue])
|
||||
# dialogue.set_meta("item", item)
|
||||
# dialogue.set_meta("item_obj", item_obj)
|
||||
func finish_dialogue(dname, d):
|
||||
controls.is_gui = false
|
||||
d.queue_free()
|
||||
|
||||
func signal_process(s, d):
|
||||
var item = d.get_meta("item")
|
||||
var item_obj = d.get_meta("item_obj")
|
||||
match s:
|
||||
"item_accepted":
|
||||
items[item] = true
|
||||
emit_signal("pick_up", item, item_obj)
|
||||
"item_rejected":
|
||||
pass
|
||||
func pick_up(obj):
|
||||
if items.has(obj.item) && items[obj.item]:
|
||||
return
|
||||
if item_dialogue.has(obj.item):
|
||||
pick_up_dialogue(obj.item, obj.item_obj)
|
||||
else:
|
||||
items[obj.item] = true
|
||||
emit_signal("pick_up", obj.item, obj.item_obj)
|
||||
52
autoload/map.gd
Normal file
52
autoload/map.gd
Normal file
@@ -0,0 +1,52 @@
|
||||
tool
|
||||
extends Node
|
||||
export var noise: OpenSimplexNoise
|
||||
export var curve: Curve
|
||||
#
|
||||
#var points = []
|
||||
##var rg: RoadGrid
|
||||
#var setup = false
|
||||
#
|
||||
#func _ready():
|
||||
# if curve:
|
||||
# curve.bake()
|
||||
# else:
|
||||
# curve = Curve.new()
|
||||
# curve.min_value = -300
|
||||
# curve.max_value = 300
|
||||
# curve.add_point(Vector2(0, -300))
|
||||
# curve.add_point(Vector2(1, 300))
|
||||
# curve.bake()
|
||||
# rg.build(curve, noise)
|
||||
# setup = true
|
||||
#
|
||||
#func _init():
|
||||
# rg = Roads.get_road_grid()
|
||||
|
||||
# var center = Vector2(0, 0)
|
||||
# points.push_back(center)
|
||||
# randomize()
|
||||
# var npatches = 8
|
||||
# var sa = randf() * 2.0 * PI
|
||||
# var center_count = 15 + randi() % 5
|
||||
# var center_step = 500
|
||||
# var centers = []
|
||||
# while centers.size() < center_count:
|
||||
# var center_x = clamp(center_step * ((randi() % 100) - 50), -10000, 10000)
|
||||
# var center_y = clamp(center_step * ((randi() % 100) - 50), -10000, 10000)
|
||||
# var c = Vector2(center_x, center_y)
|
||||
# if !c in centers:
|
||||
# centers.push_back(c)
|
||||
# for cx in centers:
|
||||
# for e in range(npatches * 8):
|
||||
# var a = sa + sqrt(e) * 8.0
|
||||
# var r = 0 if e == 0 else 100 + e * 100.0 + 50 * randf()
|
||||
# var x = cos(a) * r + cx.x
|
||||
# var y = sin(a) * r + cx.y
|
||||
# var d = Vector2(x, y)
|
||||
# points.push_back(d)
|
||||
# print("voronoi start")
|
||||
# var diagram = Voronoi.generate_diagram(points, 11)
|
||||
# print("voronoi end, processing")
|
||||
# rg.process_diagram(diagram)
|
||||
# print("processing done")
|
||||
16
autoload/map.tscn
Normal file
16
autoload/map.tscn
Normal file
@@ -0,0 +1,16 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://autoload/map.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="OpenSimplexNoise" id=2]
|
||||
|
||||
[sub_resource type="Curve" id=1]
|
||||
min_value = -300.0
|
||||
max_value = 300.0
|
||||
bake_resolution = 200
|
||||
_data = [ Vector2( 0, -259.615 ), 0.0, 0.0, 0, 0, Vector2( 0.975, 300 ), 0.0, 0.0, 0, 0 ]
|
||||
|
||||
[node name="Map" type="Node"]
|
||||
script = ExtResource( 1 )
|
||||
noise = SubResource( 2 )
|
||||
curve = SubResource( 1 )
|
||||
213
autoload/marker.gd
Normal file
213
autoload/marker.gd
Normal file
@@ -0,0 +1,213 @@
|
||||
extends Node
|
||||
|
||||
var marker_list = []
|
||||
var label_count = 10
|
||||
var labels = []
|
||||
var max_dist = 4
|
||||
var current_marker
|
||||
var cam
|
||||
|
||||
func node_added(node):
|
||||
if node.name.begins_with("marker_"):
|
||||
if !node in marker_list:
|
||||
marker_list.push_back(node)
|
||||
func node_removed(node):
|
||||
marker_list.erase(node)
|
||||
|
||||
var state = 0
|
||||
func _ready():
|
||||
get_tree().connect("node_added", self, "node_added")
|
||||
get_tree().connect("node_removed", self, "node_removed")
|
||||
var root = get_tree().get_root()
|
||||
var queue = [root]
|
||||
while queue.size() > 0:
|
||||
var item = queue.pop_front()
|
||||
if item.name.begins_with("marker_"):
|
||||
marker_list.push_back(item)
|
||||
for e in item.get_children():
|
||||
queue.push_back(e)
|
||||
|
||||
func see_through_marker(m):
|
||||
if !m.has_meta("marker_data"):
|
||||
return false
|
||||
var md = m.get_meta("marker_data")
|
||||
if md.has("see_through") && md.see_through == true:
|
||||
return true
|
||||
return false
|
||||
|
||||
func _process(delta):
|
||||
if state == 0:
|
||||
var root = get_tree().get_root()
|
||||
for _e in range(label_count):
|
||||
var tl = Label.new()
|
||||
root.add_child(tl)
|
||||
tl.hide()
|
||||
labels.push_back(tl)
|
||||
state = 1
|
||||
if state == 1:
|
||||
var cam = get_viewport().get_camera()
|
||||
if !cam.has_meta("player"):
|
||||
return
|
||||
var player = cam.get_meta("player")
|
||||
assert(player)
|
||||
var size = get_viewport().size
|
||||
var center = size/2
|
||||
var visible_markers = []
|
||||
var wstate = cam.get_world().direct_space_state
|
||||
for e in marker_list:
|
||||
var cam_pos = cam.global_transform.origin
|
||||
var player_pos = player.global_transform.origin
|
||||
var marker_pos = e.global_transform.origin
|
||||
if player_pos.distance_squared_to(marker_pos) < max_dist * max_dist:
|
||||
var lpos = cam.global_transform.xform_inv(marker_pos)
|
||||
if lpos.z < 0:
|
||||
if see_through_marker(e) && e.visible:
|
||||
visible_markers.push_back(e)
|
||||
elif e.visible:
|
||||
var xlist = [player]
|
||||
if e.has_meta("marker_data"):
|
||||
var md = e.get_meta("marker_data")
|
||||
if !md.has("obj"):
|
||||
e.hide()
|
||||
else:
|
||||
if md.obj is PhysicsBody:
|
||||
xlist.push_back(md.obj)
|
||||
else:
|
||||
e.hide()
|
||||
|
||||
var result = wstate.intersect_ray(cam_pos, marker_pos, xlist)
|
||||
if !result.has("collider") || !result.collider:
|
||||
visible_markers.push_back(e)
|
||||
|
||||
var free_labels = []
|
||||
var process_markers = visible_markers.duplicate()
|
||||
for e in labels:
|
||||
var l: Label = e
|
||||
if l.has_meta("marker"):
|
||||
# var n = l.get_meta("marker")
|
||||
# if n in visible_markers:
|
||||
# process_markers.erase(n)
|
||||
# else:
|
||||
l.remove_meta("marker")
|
||||
free_labels.push_back(l)
|
||||
l.hide()
|
||||
else:
|
||||
free_labels.push_back(l)
|
||||
l.hide()
|
||||
if free_labels.size() == 0:
|
||||
state = 2
|
||||
return
|
||||
for e in process_markers:
|
||||
if free_labels.size() == 0:
|
||||
break
|
||||
var pos = cam.unproject_position(e.global_transform.origin)
|
||||
var l = free_labels.pop_front()
|
||||
var t = InputMap.get_action_list("activate")[0].as_text() + ": "
|
||||
if e.name.ends_with("_door"):
|
||||
t += "Open"
|
||||
elif e.name.ends_with("_container"):
|
||||
t += "Access"
|
||||
elif e.name.ends_with("_pickup"):
|
||||
t += "Pick up"
|
||||
elif e.name.ends_with("_vehicleseat") || e.name.ends_with("_seat"):
|
||||
t += "Sit"
|
||||
elif e.name.ends_with("_exit"):
|
||||
t += "Exit"
|
||||
elif e.name.ends_with("_talk"):
|
||||
t += "Talk"
|
||||
elif e.name.ends_with("_action"):
|
||||
t += "Action"
|
||||
elif e.name.ends_with("_grab"):
|
||||
t += "Grab"
|
||||
elif e.name.ends_with("_take"):
|
||||
t += "Take"
|
||||
elif e.name.ends_with("_sacrifice"):
|
||||
t += "Sacrifice"
|
||||
l.set_meta("marker", e)
|
||||
l.text = t
|
||||
l.add_color_override("font_color", Color(0.6,0.6,1,1))
|
||||
l.rect_position = pos - l.rect_size / 2.0
|
||||
l.show()
|
||||
var current = null
|
||||
var cur_d = INF
|
||||
for l in labels:
|
||||
if l.visible:
|
||||
var d = l.rect_position.distance_squared_to(center)
|
||||
if !current:
|
||||
cur_d = d
|
||||
current = l
|
||||
else:
|
||||
if cur_d > d:
|
||||
current = l
|
||||
cur_d = d
|
||||
if current:
|
||||
current.add_color_override("font_color", Color(0.9,0.9,1,1))
|
||||
current_marker = current.get_meta("marker")
|
||||
else:
|
||||
current_marker = null
|
||||
|
||||
state = 2
|
||||
|
||||
if state == 2:
|
||||
state = 1
|
||||
# var player = get_viewport().get_camera().get_meta("player")
|
||||
# if !controls.is_gui && !player.has_meta("group_behavior") && !player.has_meta("")
|
||||
# if Input.is_action_just_pressed("activate"):
|
||||
# var marker = current_marker
|
||||
# if marker && marker.has_meta("marker_data"):
|
||||
# var md = marker.get_meta("marker_data")
|
||||
# print("marker_data: ", md)
|
||||
# if md.has("obj"):
|
||||
# print("obj: ", md.obj.name)
|
||||
# if md.has("obj") && md.has("method"):
|
||||
# print("activate ", md.obj.name, " ", md.method)
|
||||
# md.obj.call_deferred(md.method, md)
|
||||
func activate_marker():
|
||||
print("Activate marker")
|
||||
var marker = current_marker
|
||||
if marker && marker.has_meta("marker_data"):
|
||||
var md = marker.get_meta("marker_data")
|
||||
print("marker_data: ", md)
|
||||
if md.has("obj"):
|
||||
print("obj: ", md.obj.name)
|
||||
if md.has("obj") && md.has("method"):
|
||||
print("activate ", md.obj.name, " ", md.method)
|
||||
md.obj.call_deferred(md.method, md)
|
||||
|
||||
func init_markers(obj, marker_info):
|
||||
var queue = [obj]
|
||||
while queue.size() > 0:
|
||||
var item = queue.pop_front()
|
||||
if item.name.begins_with("marker_"):
|
||||
if marker_info.has(item.name):
|
||||
marker_info[item.name].marker_obj = item
|
||||
for e in item.get_children():
|
||||
queue.push_back(e)
|
||||
queue = [obj]
|
||||
while queue.size() > 0:
|
||||
var item = queue.pop_front()
|
||||
if item.name.begins_with("marker_"):
|
||||
var marker_data = {}
|
||||
marker_data.obj = obj
|
||||
if marker_info.has(item.name):
|
||||
var o = marker_info[item.name]
|
||||
for k in o.keys():
|
||||
marker_data[k] = o[k]
|
||||
if o.has("see_through") && o.see_through:
|
||||
item.hide()
|
||||
item.set_meta("marker_data", marker_data)
|
||||
for e in item.get_children():
|
||||
queue.push_back(e)
|
||||
func init_marker(m, obj, data):
|
||||
assert(m)
|
||||
assert(obj)
|
||||
assert(data)
|
||||
var marker_data = {}
|
||||
marker_data.obj = m
|
||||
for e in data.keys():
|
||||
marker_data[e] = data[e]
|
||||
if data.has("see_through") && data.see_through:
|
||||
obj.hide()
|
||||
obj.set_meta("marker_data", marker_data)
|
||||
if !obj in marker_list:
|
||||
marker_list.push_back(obj)
|
||||
17
autoload/scenario.gd
Normal file
17
autoload/scenario.gd
Normal file
@@ -0,0 +1,17 @@
|
||||
extends Node
|
||||
|
||||
|
||||
# Declare member variables here. Examples:
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
var save_data = {}
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
#func _process(delta):
|
||||
# pass
|
||||
296
autoload/streaming.gd
Normal file
296
autoload/streaming.gd
Normal file
@@ -0,0 +1,296 @@
|
||||
extends Node
|
||||
|
||||
export var trailer_house: PackedScene
|
||||
export var palace: PackedScene
|
||||
export var car: PackedScene
|
||||
|
||||
onready var obj_names = {
|
||||
"palace": palace,
|
||||
"trailer_house": trailer_house
|
||||
}
|
||||
|
||||
var done = false
|
||||
|
||||
class radial_grid:
|
||||
var radial_points = []
|
||||
var max_r = 0.0
|
||||
var grid = []
|
||||
var width: int = 0
|
||||
var height: int = 0
|
||||
var nodes = []
|
||||
func build(poly, center):
|
||||
var height = center.y
|
||||
max_r = 0.0
|
||||
for p in range(poly.size()):
|
||||
var ep1 = poly[p]
|
||||
ep1.y = height
|
||||
var ep2 = poly[(p + 1) % poly.size()]
|
||||
ep2.y = height
|
||||
var d = (ep2 - ep1).normalized()
|
||||
radial_points.push_back(ep1)
|
||||
var dst = ep1.distance_to(ep2)
|
||||
while dst > 32:
|
||||
ep1 += d * 32
|
||||
radial_points.push_back(ep1)
|
||||
dst -= 32
|
||||
for p in range(radial_points.size()):
|
||||
var ep = radial_points[p]
|
||||
var dst = ep.distance_to(center)
|
||||
if max_r < dst:
|
||||
max_r = dst
|
||||
width = radial_points.size()
|
||||
height = int(max_r / 32)
|
||||
grid.resize(width * height)
|
||||
for p in range(width):
|
||||
var start = radial_points[p]
|
||||
var end = center
|
||||
var step = (end - start).normalized() * (end - start).length() / float(height + 1)
|
||||
var val = start
|
||||
for q in range(height):
|
||||
grid[p * height + q] = {"position": val, "node": null}
|
||||
func get_grid_node(x, y):
|
||||
return grid[x * height + y].node
|
||||
func set_grid_node(x, y, node):
|
||||
if !node in nodes:
|
||||
nodes.push_back(node)
|
||||
grid[x * height + y].node = node
|
||||
func place_grid(aabb: AABB, node) -> void:
|
||||
for u in range(width):
|
||||
for v in range(height):
|
||||
if aabb.has_point(grid[u * height + v].position):
|
||||
set_grid_node(u, v, node)
|
||||
func get_pos(x, y):
|
||||
return grid[x * height + y].position
|
||||
|
||||
onready var grid = radial_grid.new()
|
||||
|
||||
func debug_poly(poly):
|
||||
for k in range(poly.size()):
|
||||
var p1 = poly[k]
|
||||
var p2 = poly[(k + 1) % poly.size()]
|
||||
var l = p1.distance_to(p2)
|
||||
var d = (p2 - p1).normalized()
|
||||
var pt = p1
|
||||
while l > 0.0:
|
||||
for e in range(0, 30, 2):
|
||||
var mi = MeshInstance.new()
|
||||
mi.mesh = CubeMesh.new()
|
||||
get_tree().root.add_child(mi)
|
||||
mi.global_transform.origin = pt + Vector3(0, e, 0)
|
||||
pt += d * 5.0
|
||||
l -= 5.0
|
||||
|
||||
func calc_border(poly, offt):
|
||||
var height = RoadsData.get_site_avg_height(0)
|
||||
var border = []
|
||||
border.resize(poly.size())
|
||||
for k in range(poly.size()):
|
||||
var i = k - 1
|
||||
if i < 0:
|
||||
i += poly.size()
|
||||
var p1 = poly[i]
|
||||
var p2 = poly[k]
|
||||
var p3 = poly[(k + 1) % poly.size()]
|
||||
var p1x = Vector2(p1.x, p1.z)
|
||||
var p2x = Vector2(p2.x, p2.z)
|
||||
var p3x = Vector2(p2.x, p2.z)
|
||||
var p4x = Vector2(p3.x, p3.z)
|
||||
var n1 = (p2x - p1x).tangent().normalized()
|
||||
var n2 = (p4x - p3x).tangent().normalized()
|
||||
p1x -= n1 * offt
|
||||
p2x -= n1 * offt
|
||||
p3x -= n2 * offt
|
||||
p4x -= n2 * offt
|
||||
|
||||
var xp = Geometry.segment_intersects_segment_2d(p1x, p2x, p3x, p4x)
|
||||
if !xp:
|
||||
xp = p2x.linear_interpolate(p3x, 0.5) - (n1 + n2).normalized() * offt
|
||||
var tp = Vector3(xp.x, height, xp.y)
|
||||
border[k] = tp
|
||||
return border
|
||||
|
||||
var towns = 0
|
||||
func setup_town(site):
|
||||
if !RoadsData.site_is_town(site):
|
||||
print("site ", site, " type: ", RoadsData.get_site_type(site))
|
||||
return
|
||||
var poly = RoadsData.get_site_polygon_3d(site)
|
||||
var height = RoadsData.get_site_avg_height(site)
|
||||
var border2 = calc_border(poly, 60)
|
||||
var aabbs = []
|
||||
var poly2 = []
|
||||
poly2.resize(border2.size())
|
||||
for p in range(border2.size()):
|
||||
poly2[p] = Vector2(border2[p].x, border2[p].z)
|
||||
var center = Vector3()
|
||||
for p in poly:
|
||||
center += p
|
||||
center /= poly.size()
|
||||
center.y = height
|
||||
grid.build(border2, center)
|
||||
var radial_points = grid.radial_points
|
||||
var max_r = 0.0
|
||||
for p in range(radial_points.size()):
|
||||
var ep = radial_points[p]
|
||||
var dst = ep.distance_to(center)
|
||||
if max_r < dst:
|
||||
max_r = dst
|
||||
for p in range(radial_points.size()):
|
||||
var ep = radial_points[p]
|
||||
var d = (center - ep).normalized()
|
||||
var dst = ep.distance_to(center)
|
||||
print(dst)
|
||||
if dst < 64.0 + 12 + 8 + 4:
|
||||
continue
|
||||
var step = 16.0
|
||||
var pstart = ep
|
||||
while dst > 0.0:
|
||||
var ok = true
|
||||
if !Geometry.is_point_in_polygon(Vector2(pstart.x, pstart.z), poly2):
|
||||
ok = false
|
||||
if ok:
|
||||
for b in aabbs:
|
||||
if b.has_point(pstart):
|
||||
ok = false
|
||||
if ok:
|
||||
var xform = Transform(Basis(), pstart).looking_at(pstart + d, Vector3.UP)
|
||||
stream_obj("trailer_house", xform)
|
||||
var aabb = AABB(pstart, Vector3())
|
||||
aabb = aabb.grow(20)
|
||||
aabbs.push_back(aabb)
|
||||
print("placed to: ", pstart)
|
||||
pstart = pstart + d * step
|
||||
dst -= step
|
||||
towns += 1
|
||||
|
||||
func setup_first_town():
|
||||
assert(!done)
|
||||
var poly = RoadsData.get_site_polygon_3d(0)
|
||||
var height = RoadsData.get_site_avg_height(0)
|
||||
var border = calc_border(poly, 32)
|
||||
var border1a = calc_border(poly, 42)
|
||||
var border2 = calc_border(poly, 60)
|
||||
|
||||
var poly2 = []
|
||||
poly2.resize(border2.size())
|
||||
for p in range(border2.size()):
|
||||
poly2[p] = Vector2(border2[p].x, border2[p].z)
|
||||
var center = Vector3()
|
||||
for p in poly:
|
||||
center += p
|
||||
center /= poly.size()
|
||||
center.y = height
|
||||
grid.build(border2, center)
|
||||
var radial_points = grid.radial_points
|
||||
var max_r = 0.0
|
||||
for p in range(radial_points.size()):
|
||||
var ep = radial_points[p]
|
||||
var dst = ep.distance_to(center)
|
||||
if max_r < dst:
|
||||
max_r = dst
|
||||
var u = radial_points.size()
|
||||
var v = int(max_r / 32)
|
||||
var grid = []
|
||||
grid.resize(u * v)
|
||||
for p in range(u):
|
||||
var start = radial_points[p]
|
||||
var end = center
|
||||
var step = (end - start).normalized() * (end - start).length() / float(v + 1)
|
||||
var val = start
|
||||
for q in range(v):
|
||||
grid[p * v + q] = {"position": val}
|
||||
var aabbs = []
|
||||
var palace_aabb = AABB(center, Vector3())
|
||||
palace_aabb = palace_aabb.grow(48)
|
||||
print(palace_aabb)
|
||||
aabbs.push_back(palace_aabb)
|
||||
stream_obj("palace", Transform(Basis(), center))
|
||||
|
||||
for p in range(radial_points.size()):
|
||||
var ep = radial_points[p]
|
||||
var d = (center - ep).normalized()
|
||||
var dst = ep.distance_to(center)
|
||||
print(dst)
|
||||
if dst < 64.0 + 12 + 8 + 4:
|
||||
continue
|
||||
var step = 16.0
|
||||
var pstart = ep
|
||||
while dst > 0.0:
|
||||
var ok = true
|
||||
if !Geometry.is_point_in_polygon(Vector2(pstart.x, pstart.z), poly2):
|
||||
ok = false
|
||||
if ok:
|
||||
for b in aabbs:
|
||||
if b.has_point(pstart):
|
||||
ok = false
|
||||
if ok:
|
||||
var xform = Transform(Basis(), pstart).looking_at(pstart + d, Vector3.UP)
|
||||
stream_obj("trailer_house", xform)
|
||||
var aabb = AABB(pstart, Vector3())
|
||||
aabb = aabb.grow(20)
|
||||
aabbs.push_back(aabb)
|
||||
print("placed to: ", pstart)
|
||||
pstart = pstart + d * step
|
||||
dst -= step
|
||||
towns += 1
|
||||
done = true
|
||||
|
||||
func _ready():
|
||||
for k in obj_names.keys():
|
||||
Spawner.add_scene(k, obj_names[k])
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
var delay = 3.0
|
||||
var state = 0
|
||||
func _process(delta):
|
||||
match state:
|
||||
0:
|
||||
delay -= delta
|
||||
if delay < 0:
|
||||
state = 1
|
||||
1:
|
||||
Spawner.update_view(self, 300)
|
||||
var sc = get_tree().root
|
||||
var viewport: = get_viewport()
|
||||
if !viewport:
|
||||
return
|
||||
var cam: = viewport.get_camera()
|
||||
if !cam:
|
||||
return
|
||||
var cam_xform: = cam.global_transform
|
||||
|
||||
func stream_obj(obj: String, xform: Transform):
|
||||
Spawner.place_scene(obj, xform)
|
||||
func _physics_process(delta):
|
||||
var cam = get_viewport().get_camera()
|
||||
if !cam:
|
||||
return
|
||||
match state:
|
||||
1:
|
||||
var space_state = get_viewport().get_world().direct_space_state
|
||||
# probaly should not be here
|
||||
for n in get_tree().get_nodes_in_group("spawn"):
|
||||
var ok = false
|
||||
if !n.is_in_group("keep"):
|
||||
var where = n.get_global_transform().origin
|
||||
var from = where
|
||||
var to = where
|
||||
from.y -= 8.0
|
||||
to.y += 8.0
|
||||
var result = space_state.intersect_ray(from, to)
|
||||
if result.empty() || !result.has("collider"):
|
||||
continue
|
||||
if result.collider:
|
||||
n.global_transform.origin = result.position
|
||||
ok = true
|
||||
if ok || n.is_in_group("keep"):
|
||||
if n.is_in_group("male"):
|
||||
characters.replace_character(n, "male", ["cmdq", "marker", "hurtboxes", "student"])
|
||||
elif n.is_in_group("female"):
|
||||
characters.replace_character(n, "female", ["cmdq", "marker", "hurtboxes", "student"])
|
||||
elif n.is_in_group("car"):
|
||||
var c = car.instance()
|
||||
var p = get_tree().root
|
||||
p.add_child(c)
|
||||
c.global_transform = n.global_transform
|
||||
n.queue_free()
|
||||
12
autoload/streaming.tscn
Normal file
12
autoload/streaming.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://autoload/streaming.gd" type="Script" id=1]
|
||||
[ext_resource path="res://objects/trailer-house.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://objects/palace.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://scenes/vehicles/car.tscn" type="PackedScene" id=4]
|
||||
|
||||
[node name="streaming" type="Node"]
|
||||
script = ExtResource( 1 )
|
||||
trailer_house = ExtResource( 2 )
|
||||
palace = ExtResource( 3 )
|
||||
car = ExtResource( 4 )
|
||||
Reference in New Issue
Block a user