extends CharacterBody3D class_name Character @onready var collision: CollisionShape3D = (%Collision) @onready var pushbox: Hitbox = (%Pushbox as Hitbox) @onready var status: Status = (%Status as Status) @onready var view: View = (%View as View) @onready var buff: Buff = (%Buff as Buff) @onready var skill: Skill = (%Skill as Skill) @onready var battle: Battle = (%Battle as Battle) @onready var effect: Effect = (%Effect as Effect) @onready var move: Move = (%Move as Move) func init(id: int, cfg: CharacterCfg, team: Enum.ETeam, owner_id: int): status.id = id status.owner_id = owner_id status.team = team status.cfg = cfg view.init(cfg.sprite_frames) skill.init() effect.init(cfg.type) effect.cast_self_particle() set_body_scale(cfg) func init_after(): var cfg: CharacterCfg = status.cfg as CharacterCfg set_status("hp_max", cfg.hp_max) set_status("hp", cfg.hp_max) set_status("shield_max", cfg.shield.shield_max) set_status("stun_max", cfg.stun.stun_max) set_status("mp_max", cfg.mp.mp_max) set_status("mp_sub_max", cfg.mp.mp_sub_max) set_shield(cfg.shield.shield_max) add_mp_sub(0, true) if cfg.ai: set_status("ai_alert_max", cfg.ai.alert_max) set_status("ai_is_alert", false) set_status("ai_alert", 0) func set_body_scale(cfg: CharacterCfg) -> void: if not cfg: cfg = status.cfg if not cfg: return var height: float = Setting.pixel_size * cfg.sprite_height var width: float = Setting.pixel_size * cfg.sprite_width var body_scale: Vector3 = Vector3(width, height, width) var half_height: float = height / 2 var center_height: float = Setting.pixel_size * 26 collision.position = Vector3(0, half_height, 0) var shape: Shape3D = collision.shape if shape is CapsuleShape3D: var new_shape: CapsuleShape3D = CapsuleShape3D.new() new_shape.radius = width new_shape.height = height collision.shape = new_shape else: collision.scale = body_scale pushbox.position = Vector3(0, half_height, 0) pushbox.scale = body_scale status.basic_offset = Vector3(0, center_height, randf()*0.001) status.ui_offset = Vector3(0, height*1.25, 0) status.ui_center_offset = Vector3(0, half_height, 0) status.radius = width status.height = height effect.set_body_scale(body_scale) func set_material(material: ShaderMaterial, material_sub: ShaderMaterial): view.material_override = material view.material_override.next_pass = material_sub #==getter== func id()->int: return status.id func cfg()->CharacterCfg: return status.cfg func team()->Enum.ETeam: return status.team func is_player()->bool: return id() == Global.character_mgr.get_player_id() func pos2D()->Vector2: return Vector2(position.x, position.z) func pos()->Vector3: return position func radius()->float: return status.radius func height()->float: return status.height func view_pos()->Vector3: return position + view.position func ui_pos()->Vector3: return position + status.ui_offset func ui_pos_center()->Vector3: return position + status.ui_center_offset func target()->int: return status.target func is_right()->bool: return status.is_right #==interface== func get_status(status_name: String) -> Variant: return status.get_status(status_name) func set_status(status_name: String, value): status.set_status(status_name, value) func set_shield(value: float): status.set_shield(value) func set_pos(pos: Vector3): position = pos SignalManager.character_pos_changed.emit(id(), pos()) func move_to(dir: Vector2): set_status("move_dir", dir.normalized()) func move_stop(): set_status("move_dir", Vector2.ZERO) move.stop() func get_face_dir() -> Vector2: if status.move_dir == Vector2.ZERO: return Vector2.RIGHT if is_right() else Vector2.LEFT return status.move_dir func add_buff(buff_name: String, duration: float, ignore_pause: bool = false): buff.add_buff(buff_name, duration, ignore_pause) func remove_buff(buff_name: String): buff.remove_buff(buff_name) func has_buff(buff_name: String)->bool: return buff.has_buff(buff_name) func set_hit_move(hit_back_dir: Vector2, hit_back_speed: float, hit_up_speed: float): status.hit_back_dir = hit_back_dir status.hit_back_speed = hit_back_speed status.hit_up_speed = hit_up_speed func set_pause_time(pause_time: float): status.pause_time=pause_time add_buff("pause", pause_time) func add_ai_skill_order(order: Status.SkillOrder): status.ai_skill_order.append(order) func cancel_skill(): skill.cancel_skill() func set_view_trigger(trigger_name: String): status.set("trigger_%s" % trigger_name, true) func show_hit_text(value: String): SignalManager.character_hit_text.emit(id(), value) func show_hit_damage(value: float): SignalManager.character_hit_damage.emit(id(), value) func add_mp_sub(value: float, from_battle: bool): battle.add_mp_sub(value, from_battle) func cost_mp(value: int): battle.cost_mp(value) func set_target(target: int): set_status("target", target) set_status("is_lock", false) func set_is_lock(value: bool): set_status("is_lock", value) func cast_particle(resource: Resource, is_attach: bool, offset: Vector3 = Vector3.ZERO, scale: Vector3 = Vector3.ONE): effect.cast_particle(resource, is_attach, offset, scale) func get_character_owner() -> Character: var owner: Character = Global.character_mgr.get_character(status.owner_id) as Character if owner: return owner return self func attack1() -> bool: return battle.character_attack1() func attack2() -> bool: return battle.character_attack2()