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 * 27 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.set_status("basic_offset", Vector3(0, center_height, randf() * 0.001)) status.set_status("ui_offset", Vector3(0, height * 1.25, 0)) status.set_status("ui_center_offset", Vector3(0, half_height, 0)) status.set_status("radius", width) status.set_status("height", height) effect.set_body_scale(body_scale) func set_material(material: ShaderMaterial, material_sub: ShaderMaterial): view.material_override = material_sub # 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_new: Vector3): position = pos_new emit_pos_changed() func emit_pos_changed(): SignalManager.character_pos_changed.emit(id(), pos()) SignalManager.character_ui_pos_changed.emit(id(), ui_pos()) func move_to(dir: Vector2): set_status("move_dir", dir.normalized()) func move_stop(): set_status("move_dir", Vector2.ZERO) move.stop() func move_tick(delta) -> bool: return move.move_tick(delta) 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.set_status("hit_back_dir", hit_back_dir) status.set_status("hit_back_speed", hit_back_speed) status.set_status("hit_up_speed", hit_up_speed) func set_pause_time(pause_time: float): status.set_status("pause_time", pause_time) add_buff("pause", pause_time) func add_ai_skill_order(order: Status.SkillOrder): status.ai_skill_order.append(order) status.emit_status("ai_skill_order") func cast_skill_by_name(skill_name: String, cast_dir: Vector2) -> void: skill.cast_skill_by_name(skill_name, cast_dir) func cast_skill(skill_cfg: SkillCfg, cast_dir: Vector2) -> void: skill.cast_skill(skill_cfg, cast_dir) func cancel_skill(): skill.cancel_skill() func set_view_trigger(trigger_name: String): status.set_status("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 add_hp(value: float): battle.add_hp(value) func cost_mp(value: int): battle.cost_mp(value) func cost_mp_sub(): battle.cost_mp_sub() func get_break_level_def() -> int: var shield: float = get_status("shield") var break_level_def: int = cfg().shield.break_level_on if shield > 0 else cfg().shield.break_level_off break_level_def += get_status("skill_break_level_add") return break_level_def func set_effect_lock(value: bool): effect.set_effect_lock(value) func set_target(target_new: int): set_status("target", target_new) 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, effect_scale: Vector3 = Vector3.ONE): effect.cast_particle(resource, is_attach, offset, effect_scale) func get_character_owner() -> Character: var character_owner: Character = Global.character_mgr.get_character(status.owner_id) as Character if character_owner: return character_owner return self func attack1() -> void: battle.character_attack1() func attack2() -> void: battle.character_attack2()