extends Characters_ 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": preload("res://scripts/modules/cmdq.gd"), "marker": preload("res://scripts/modules/npc_marker.gd"), "sacrifice": preload("res://scripts/modules/npc_sacrifice.gd"), "nun": preload("res://scripts/modules/npc_nun.gd"), "mystress": preload("res://scripts/modules/npc_mystress.gd"), "player": preload("res://scripts/modules/player_controls.gd"), "player_clothes": preload("res://scripts/modules/player_clothes.gd"), "hurtboxes": preload("res://scripts/modules/character_hurtboxes.gd"), "student": preload("res://scripts/modules/npc_student.gd"), "bandit": preload("res://scripts/modules/npc_bandit.gd") } var face_data_path = "res://scenes/face/" var hair_data_path = "res://scenes/hair/" var female_faces = [] var mesh_female_faces = {} var male_faces = [] var mesh_male_faces = {} var female_hairs = [] var mesh_female_hairs = {} var male_hairs = [] var mesh_male_hairs = {} var hair_materials = [] var data_hair_materials = {} var name_data = {} var rnd var roommates = {} #var _crowd: DetourCrowdManager func _ready(): var capsule_male = CapsuleShape.new() capsule_male.radius = 0.4 capsule_male.height = 1.12 capsule_male.margin = 0.08 var capsule_female = CapsuleShape.new() capsule_female.radius = 0.35 capsule_female.height = 0.9 capsule_female.margin = 0.08 CharacterSystemWorld.add_character_scene(female, {}, "female") CharacterSystemWorld.add_character_scene(male, {}, "male") for k in modules.keys(): CharacterSystemWorld.add_module(k, modules[k]) CharacterSystemWorld.set_face_ctrl_scene(face_ctrl) CharacterSystemWorld.add_character_shape(capsule_female, Transform(Basis().rotated(Vector3(1, 0, 0), -PI/2.0), Vector3(0, 0.805, 0)), "female") CharacterSystemWorld.add_character_shape(capsule_male, Transform(Basis().rotated(Vector3(1, 0, 0), -PI/2.0), Vector3(0, 0.965, 0)), "male") 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) mesh_female_faces[fp] = load(fp) CharacterSystemWorld.add_face_scene(mesh_female_faces[fp], "female") "male": male_faces.push_back(fp) mesh_male_faces[fp] = load(fp) CharacterSystemWorld.add_face_scene(mesh_male_faces[fp], "male") 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) mesh_male_faces[fp_m] = load(fp_m) CharacterSystemWorld.add_face_scene(mesh_male_faces[fp_m], "male") if data_fd.file_exists(fp_f): female_faces.push_back(fp_f) mesh_female_faces[fp_f] = load(fp_f) CharacterSystemWorld.add_face_scene(mesh_female_faces[fp_f], "female") if data_fd.file_exists(hp_m): male_hairs.push_back(hp_m) mesh_male_hairs[hp_m] = load(hp_m) CharacterSystemWorld.add_hair_scene(mesh_male_hairs[hp_m], "male") if data_fd.file_exists(hp_f): female_hairs.push_back(hp_f) mesh_female_hairs[hp_f] = load(hp_f) CharacterSystemWorld.add_hair_scene(mesh_female_hairs[hp_f], "female") if data_fd.file_exists(mat): hair_materials.push_back(mat) data_hair_materials[mat] = load(mat) CharacterSystemWorld.add_hair_material(data_hair_materials[mat], "male") CharacterSystemWorld.add_hair_material(data_hair_materials[mat], "female") CharacterSystemWorld.create_character_pool(1024) 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 id = create_character_in_pool( # return CharacterSystemWorld.create_character(g, enable_modules, face, hair, hair_mat) func replace_player_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() CharacterSystemWorld.create_player_character_in_pool(enable_modules, xform) var body = CharacterSystemWorld.create_character_visual(0) # var body = compose_kinematic_character(g, enable_modules, face, hair, hair_mat) # var body = CharacterSystemWorld.create_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") assert(skel) var hair_skel = obj.get_meta("hair_skeleton") assert(hair_skel) 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"): if streaming.can_spawn: character_physics(player)