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)