minijam-166/scripts/plant.gd
2024-09-04 20:04:20 +02:00

184 lines
5.6 KiB
GDScript

class_name Plant
extends Node2D
enum PlantState { SAPLING, GROWN, DEAD}
signal grown
signal died
@onready var growing_timer: Timer = $Growing
@onready var need_checker: Timer = $NeedChecker
@onready var sapling_count_down: Timer = $SaplingCountDown
@onready var reproduction: Timer = $Reproduction
@onready var sprite_node: AnimatedSprite2D = $AnimatedSprite2D
const NEED_CHECK_PERIOD := 0.5
const SAPLING_LIFETIME_MULT := 20.0 # this multiplies the time to grow to tell the time it can stay as a sapling
const OFFSET_REPRODUCTION_PERCT_DIST := 0.1
var parameter: PlantType
var state := PlantState.SAPLING
var sapling_time_left: float
var can_grow := true
var n_offsprings_left: int
func init(plant_parameter: PlantType):
parameter = plant_parameter
sapling_count_down.start(SAPLING_LIFETIME_MULT * parameter.growing_time)
sprite_node.sprite_frames = parameter.sprite_frames
need_checker.start(NEED_CHECK_PERIOD)
n_offsprings_left = parameter.offspring_per_lifetime
func _on_need_checker_timeout() -> void:
can_grow = check_terrain_viability()
growing_timer.paused = not can_grow and state == PlantState.SAPLING
reproduction.paused = not can_grow
if can_grow:
sprite_node.frame = 1
else:
sprite_node.frame = 0
func check_terrain_viability() -> bool:
var water := GameTerrain.get_stat(position, GameTerrain.Stats.WATER)
if water < parameter.water_need[0] or water > parameter.water_need[1]:
return false
var fertility := GameTerrain.get_stat(position, GameTerrain.Stats.FERTILITY)
if fertility < parameter.fertility_need[0] or fertility > parameter.fertility_need[1]:
return false
var presence := GameTerrain.get_stat(position, GameTerrain.Stats.PRESENCE)
presence += float(GameTerrain.LEVELS_NUMBER) / 2
if presence < parameter.presence_need[0] or presence > parameter.presence_need[1]:
return false
return true
func _on_growing_timeout() -> void:
if state == PlantState.SAPLING:
can_grow = check_terrain_viability()
if not can_grow:
growing_timer.start()
return
match state:
PlantState.SAPLING:
grow()
PlantState.GROWN:
die()
PlantState.DEAD:
remove()
func plant(new_position: Vector2):
if not GameTerrain.is_on_map_real(new_position):
push_error("Planting out of the map")
position = new_position
state = PlantState.SAPLING
growing_timer.start(parameter.growing_time)
sprite_node.play("SAPLING")
$AnimationPlayer.play("Growing")
func grow():
if state != PlantState.SAPLING:
push_error("Tried to grow " + parameter.type + ", but was not at sapling state")
return
state = PlantState.GROWN
sapling_count_down.stop()
growing_timer.start(parameter.dying_time)
GameTerrain.modify_zone_falloff(position,
parameter.distance_prod,
parameter.distance_prod_falloff,
GameTerrain.Stats.WATER,
parameter.water_prod)
GameTerrain.modify_zone_falloff(position,
parameter.distance_prod,
parameter.distance_prod_falloff,
GameTerrain.Stats.FERTILITY,
parameter.fertility_prod)
GameTerrain.modify_zone_falloff(position,
parameter.distance_prod,
parameter.distance_prod_falloff,
GameTerrain.Stats.PRESENCE,
parameter.presence_prod)
reproduction.start(parameter.dying_time / (n_offsprings_left + 1))
grown.emit()
sprite_node.play("GROWN")
$AnimationPlayer.play("Growing")
func die():
state = PlantState.DEAD
# remove alive prod and add dead prod
GameTerrain.modify_zone_falloff(position,
parameter.distance_prod,
parameter.distance_prod_falloff,
GameTerrain.Stats.WATER,
-parameter.water_prod + parameter.dead_water_prod)
GameTerrain.modify_zone_falloff(position,
parameter.distance_prod,
parameter.distance_prod_falloff,
GameTerrain.Stats.FERTILITY,
-parameter.fertility_prod + parameter.dead_fertility_prod)
GameTerrain.modify_zone_falloff(position,
parameter.distance_prod,
parameter.distance_prod_falloff,
GameTerrain.Stats.PRESENCE,
-parameter.presence_prod)
growing_timer.start(parameter.dead_time)
died.emit()
sprite_node.play("DEAD")
$AnimationPlayer.play("Growing")
func remove(was_dead: bool = true):
if was_dead:
GameTerrain.modify_zone_falloff(position,
parameter.distance_prod,
parameter.distance_prod_falloff,
GameTerrain.Stats.WATER,
-parameter.dead_water_prod)
GameTerrain.modify_zone_falloff(position,
parameter.distance_prod,
parameter.distance_prod_falloff,
GameTerrain.Stats.FERTILITY,
-parameter.dead_fertility_prod)
queue_free()
func _on_sapling_count_down_timeout() -> void:
remove(false)
func _on_reproduction_timeout() -> void:
var min_dist := parameter.distance_prod - parameter.distance_prod * OFFSET_REPRODUCTION_PERCT_DIST
var max_dist := parameter.distance_prod + parameter.distance_prod * OFFSET_REPRODUCTION_PERCT_DIST
var plant_pos = position + (Vector2.RIGHT * randf_range(min_dist, max_dist)).rotated(randf_range(0, PI))
if not GameTerrain.is_on_map_real(plant_pos):
return
var space := get_world_2d().direct_space_state
var parameters = PhysicsPointQueryParameters2D.new()
parameters.position = plant_pos
parameters.collide_with_areas = true
parameters.collide_with_bodies = false
parameters.collision_mask = 1
var result := space.intersect_point(parameters, 1)
if result.size() > 0:
return
var offspring = self.duplicate()
self.get_parent().add_child(offspring)
offspring.init(parameter)
offspring.plant(plant_pos)
n_offsprings_left -= 1
reproduction.start(parameter.dying_time / (n_offsprings_left + 1))
if n_offsprings_left == 0:
reproduction.stop()