|
|
|
|
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.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 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 set_effect_lock(value: bool):
|
|
|
|
|
effect.set_effect_lock(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()
|