base_plant.gd 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. extends CharacterBody2D
  2. class_name Plant
  3. signal shoot(ufo: UFO)
  4. @export var y_offset: float = 0.0
  5. @export var height: float = 100.0
  6. @export_range(1.0, 30.0) var grow_time: float = 1.0
  7. var growing: bool = true
  8. var grow_value: float = 0.0
  9. @export_range(0.0, 1.0) var base_scale: float = 0.5
  10. @onready var target_scale: float = get_scale().x
  11. @export_range(0.0, 1000.0) var max_hp = 100.0
  12. @onready var hp: float = max_hp
  13. var planted_position: Vector2 = Vector2(0, 0)
  14. var dead: bool = false
  15. var attackers: Array[UFO] = []
  16. var target_attacker: UFO = null # Used when the plant is dying
  17. @export var cost: int = 10
  18. @export var bullet_color: Color = Color(1, 1, 1, 1)
  19. @export var bullet_base_speed_u: int = 2000
  20. @export var bullet_base_speed_l: int = 1000
  21. @export var constant_sound: bool = false
  22. @onready var body = $Body
  23. enum TargetMode {
  24. NEAREST, HIGHEST, LOWEST
  25. }
  26. var ufo_search_timer: Timer = Timer.new()
  27. var attack_timer: Timer = Timer.new()
  28. @onready var ufos: Node2D = get_tree().get_root().find_child("UFOs", true, false)
  29. var victim: UFO = null
  30. @export var target_mode: TargetMode = TargetMode.NEAREST
  31. @export var attack_rate: float = 0.1
  32. @export var attack_range: float = 300.0
  33. @export var attack_damage: float = 10.0
  34. func _ready():
  35. move_local_y(y_offset)
  36. planted_position = get_position()
  37. ufo_search_timer.set_wait_time(0.1)
  38. ufo_search_timer.set_autostart(false)
  39. ufo_search_timer.set_one_shot(true)
  40. ufo_search_timer.connect("timeout", _on_attack)
  41. attack_timer.set_wait_time(attack_rate)
  42. attack_timer.set_autostart(false)
  43. attack_timer.set_one_shot(true)
  44. attack_timer.connect("timeout", _on_attack)
  45. add_child(ufo_search_timer)
  46. add_child(attack_timer)
  47. attack_timer.start()
  48. # Workaround crash run out of packets
  49. if constant_sound:
  50. $Coin.set_volume_db(-100)
  51. $Coin.play()
  52. func get_class():
  53. return "Plant"
  54. func _on_attack():
  55. find_ufo()
  56. if victim == null or victim.dead:
  57. ufo_search_timer.start()
  58. else:
  59. emit_signal("shoot", victim)
  60. attack_timer.start()
  61. if !constant_sound:
  62. $Coin.play()
  63. func find_ufo():
  64. victim = null
  65. var all_ufos = ufos.get_children()
  66. var plant_pos = get_global_position()
  67. if all_ufos.size() > 0:
  68. var best_ufo = all_ufos[0]
  69. var best_value = 0.0
  70. if target_mode == TargetMode.NEAREST:
  71. best_value = 10000000.0
  72. for ufo in ufos.get_children():
  73. if ufo.dead:
  74. continue
  75. var tested_value: float
  76. if target_mode == TargetMode.NEAREST:
  77. tested_value = ufo.get_global_position().distance_to(plant_pos)
  78. if tested_value <= attack_range:
  79. if tested_value < best_value:
  80. best_value = tested_value
  81. best_ufo = ufo
  82. victim = best_ufo
  83. else:
  84. tested_value = ufo.hp
  85. if tested_value > best_value:
  86. best_value = tested_value
  87. best_ufo = ufo
  88. victim = best_ufo
  89. func _process(delta):
  90. if growing:
  91. grow_value += delta / grow_time
  92. if grow_value > 1.0:
  93. grow_value = 1.0
  94. growing = false
  95. set_scale(Vector2(target_scale, target_scale))
  96. else:
  97. var new_scale = target_scale * (base_scale + grow_value * (1.0 - base_scale))
  98. set_scale(Vector2(new_scale, new_scale))
  99. elif dead:
  100. if target_attacker == null or target_attacker.dead:
  101. select_attacker()
  102. if target_attacker != null:
  103. velocity = target_attacker.get_global_position() - get_global_position()
  104. move_and_slide()
  105. var scale = get_scale().x
  106. scale *= (1.0 - delta)
  107. set_scale(Vector2(scale, scale))
  108. set_z_index(-30)
  109. rotate(delta * PI)
  110. if scale < 0.1:
  111. get_parent().remove_child(self)
  112. queue_free()
  113. else:
  114. if target_attacker == null or target_attacker.dead:
  115. alter_hp(delta * max_hp / 10.0)
  116. if constant_sound:
  117. $Coin.set_volume_db(-100)
  118. if victim != null and not victim.dead and constant_sound:
  119. $Coin.set_volume_db(-12)
  120. func select_attacker():
  121. for attacker in attackers:
  122. #if !attacker.dead:
  123. target_attacker = attacker
  124. func alter_hp(delta: float):
  125. hp += delta
  126. hp = min(hp, max_hp)
  127. set_position(Vector2(planted_position.x, planted_position.y - height * (1.0 - hp / max_hp)))
  128. func deal_damage(damage: float, attacker: UFO):
  129. if dead:
  130. return
  131. alter_hp(-damage)
  132. if attacker != null:
  133. attackers.push_back(attacker)
  134. if hp < 0:
  135. dead = true
  136. func is_ready():
  137. return !growing