2026-04-13 11:34:00 -05:00
|
|
|
class_name Citizen extends CharacterBody2D
|
|
|
|
|
|
2026-04-15 10:45:43 -05:00
|
|
|
enum Status { NONE, DRUNK, ARMED, CAFFEINATED }
|
|
|
|
|
|
|
|
|
|
const DRUNK_ICON = preload("uid://28x2e52skdt1")
|
|
|
|
|
const COFFEE_ICON = preload("uid://0644a3psplk8")
|
|
|
|
|
const ARMED_ICON = preload("uid://cn8biugbtcns5")
|
|
|
|
|
|
2026-04-13 11:34:00 -05:00
|
|
|
var direction: Board.Direction:
|
|
|
|
|
set(new_direction):
|
|
|
|
|
direction = new_direction
|
|
|
|
|
if direction == Board.Direction.NONE:
|
|
|
|
|
idle()
|
|
|
|
|
else:
|
|
|
|
|
walk()
|
|
|
|
|
|
2026-04-15 10:45:43 -05:00
|
|
|
var paused: bool:
|
|
|
|
|
set(value):
|
|
|
|
|
paused = value
|
|
|
|
|
if paused:
|
|
|
|
|
animated_sprite.pause()
|
|
|
|
|
else:
|
|
|
|
|
animated_sprite.play()
|
|
|
|
|
|
2026-04-13 11:34:00 -05:00
|
|
|
var speed: float = 50
|
|
|
|
|
var current_tile_coords: Vector2i
|
2026-04-15 10:45:43 -05:00
|
|
|
var direction_queue: Array[Board.Direction] = []
|
|
|
|
|
var money: int = 0
|
|
|
|
|
var money_label_tween: Tween
|
|
|
|
|
var tiles_visited: Dictionary[Tile, int] = {}
|
|
|
|
|
var buildings_visited: Dictionary[Building, int] = {}
|
|
|
|
|
|
|
|
|
|
var _statuses: Array[Status] = []
|
2026-04-13 11:34:00 -05:00
|
|
|
|
|
|
|
|
@onready var animated_sprite: AnimatedSprite2D = %AnimatedSprite
|
|
|
|
|
@onready var sprite_collision: CollisionShape2D = %SpriteCollision
|
|
|
|
|
@onready var tile_area: Area2D = %TileArea
|
2026-04-15 10:45:43 -05:00
|
|
|
@onready var money_label: Label = %MoneyLabel
|
|
|
|
|
@onready var status_container: Container = %StatusContainer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _ready() -> void:
|
2026-04-20 13:03:39 -05:00
|
|
|
Globals.board_game.citizen_count += 1
|
2026-04-15 10:45:43 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
func pause() -> void:
|
|
|
|
|
paused = true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func unpause() -> void:
|
|
|
|
|
paused = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func add_status(status: Status) -> void:
|
|
|
|
|
_statuses.push_back(status)
|
|
|
|
|
match status:
|
|
|
|
|
Status.DRUNK:
|
|
|
|
|
status_container.add_child(DRUNK_ICON.instantiate())
|
|
|
|
|
Status.CAFFEINATED:
|
|
|
|
|
status_container.add_child(COFFEE_ICON.instantiate())
|
|
|
|
|
Status.ARMED:
|
|
|
|
|
status_container.add_child(ARMED_ICON.instantiate())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func remove_status(status: Status) -> void:
|
|
|
|
|
var status_idx := _statuses.find(status)
|
|
|
|
|
_statuses.remove_at(status_idx)
|
|
|
|
|
status_container.get_child(status_idx).free()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_status_count(status: Status) -> int:
|
|
|
|
|
return _statuses.count(status)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func remove_all_statuses(status: Status) -> void:
|
|
|
|
|
while _statuses.has(status):
|
|
|
|
|
remove_status(status)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func play_money_animation() -> void:
|
|
|
|
|
if is_instance_valid(money_label_tween):
|
|
|
|
|
money_label_tween.kill()
|
|
|
|
|
var starting_position = sprite_collision.position - (money_label.size / 2)
|
|
|
|
|
money_label_tween = create_tween()
|
|
|
|
|
(
|
|
|
|
|
money_label_tween
|
|
|
|
|
. tween_property(money_label, "position", starting_position - Vector2(0, 25), 0.75)
|
|
|
|
|
. from(starting_position)
|
|
|
|
|
)
|
|
|
|
|
(
|
|
|
|
|
money_label_tween
|
|
|
|
|
. parallel()
|
|
|
|
|
. tween_property(money_label, "modulate", Color(1, 1, 1, 0), 0.75)
|
|
|
|
|
. from(Color(1, 1, 1, 1))
|
|
|
|
|
)
|
|
|
|
|
|
2026-04-13 11:34:00 -05:00
|
|
|
|
|
|
|
|
func set_offset(offset: Vector2) -> void:
|
|
|
|
|
animated_sprite.position = offset
|
|
|
|
|
sprite_collision.position = offset
|
2026-04-15 10:45:43 -05:00
|
|
|
status_container.position = offset + Vector2(5, -5)
|
|
|
|
|
|
2026-04-13 11:34:00 -05:00
|
|
|
|
2026-04-15 10:45:43 -05:00
|
|
|
func _physics_process(delta: float) -> void:
|
|
|
|
|
if paused:
|
|
|
|
|
return
|
2026-04-13 11:34:00 -05:00
|
|
|
var motion: Vector2
|
|
|
|
|
match direction:
|
|
|
|
|
Board.Direction.UP:
|
|
|
|
|
#position = position.move_toward(position + Vector2.UP, speed * delta)
|
|
|
|
|
motion = Vector2.UP * speed * delta
|
|
|
|
|
Board.Direction.DOWN:
|
|
|
|
|
#position = position.move_toward(position + Vector2.DOWN, speed * delta)
|
|
|
|
|
motion = Vector2.DOWN * speed * delta
|
|
|
|
|
Board.Direction.RIGHT:
|
|
|
|
|
#position = position.move_toward(position + Vector2.RIGHT, speed * delta)
|
|
|
|
|
motion = Vector2.RIGHT * speed * delta
|
|
|
|
|
Board.Direction.LEFT:
|
|
|
|
|
#position = position.move_toward(position + Vector2.LEFT, speed * delta)
|
|
|
|
|
motion = Vector2.LEFT * speed * delta
|
|
|
|
|
move_and_collide(motion)
|
2026-04-15 10:45:43 -05:00
|
|
|
|
2026-04-13 11:34:00 -05:00
|
|
|
|
|
|
|
|
func idle() -> void:
|
2026-04-20 13:03:39 -05:00
|
|
|
Globals.board_game.citizen_count -= 1
|
2026-04-13 11:34:00 -05:00
|
|
|
animated_sprite.play("idle")
|
|
|
|
|
|
2026-04-15 10:45:43 -05:00
|
|
|
|
2026-04-13 11:34:00 -05:00
|
|
|
func walk() -> void:
|
|
|
|
|
match direction:
|
|
|
|
|
Board.Direction.UP:
|
|
|
|
|
animated_sprite.play("walk_up")
|
|
|
|
|
Board.Direction.DOWN:
|
|
|
|
|
animated_sprite.play("walk_down")
|
|
|
|
|
Board.Direction.LEFT:
|
|
|
|
|
animated_sprite.flip_h = true
|
|
|
|
|
animated_sprite.play("walk_right")
|
|
|
|
|
Board.Direction.RIGHT:
|
|
|
|
|
animated_sprite.flip_h = false
|
|
|
|
|
animated_sprite.play("walk_right")
|
|
|
|
|
|
2026-04-15 10:45:43 -05:00
|
|
|
|
2026-04-20 13:03:39 -05:00
|
|
|
#func check_for_wall() -> void:
|
|
|
|
|
#var tile_walls = board.wall_map.get_cell_scene(current_tile_coords).walls
|
|
|
|
|
#if tile_walls.has(direction):
|
|
|
|
|
#direction = Board.get_next_direction(direction)
|
|
|
|
|
#check_for_wall()
|
2026-04-13 11:34:00 -05:00
|
|
|
|
2026-04-15 10:45:43 -05:00
|
|
|
|
2026-04-13 11:34:00 -05:00
|
|
|
func check_for_turn(tile: Tile) -> void:
|
|
|
|
|
if tile is Turn:
|
2026-04-15 10:45:43 -05:00
|
|
|
if _statuses.has(Status.DRUNK):
|
|
|
|
|
remove_status(Status.DRUNK)
|
|
|
|
|
else:
|
|
|
|
|
direction = tile.direction
|
|
|
|
|
|
2026-04-13 11:34:00 -05:00
|
|
|
|
|
|
|
|
func check_for_building() -> void:
|
2026-04-20 13:03:39 -05:00
|
|
|
if Globals.board_game.board.buildings.has(
|
|
|
|
|
current_tile_coords + Board.get_direction_vector(direction)
|
|
|
|
|
):
|
|
|
|
|
var building = Globals.board_game.board.buildings[
|
|
|
|
|
current_tile_coords + Board.get_direction_vector(direction)
|
|
|
|
|
]
|
2026-04-13 11:34:00 -05:00
|
|
|
if !building.can_citizen_enter(current_tile_coords, direction):
|
|
|
|
|
direction = Board.get_next_direction(direction)
|
|
|
|
|
check_for_building()
|
|
|
|
|
|
2026-04-15 10:45:43 -05:00
|
|
|
|
2026-04-20 13:03:39 -05:00
|
|
|
func handle_tile_area_exited(_area: Area2D):
|
|
|
|
|
if is_queued_for_deletion():
|
|
|
|
|
return
|
|
|
|
|
current_tile_coords = Globals.board_game.board.tile_map.local_to_map(tile_area.global_position)
|
|
|
|
|
if (
|
|
|
|
|
!Globals.board_game.board.tiles.has(current_tile_coords)
|
|
|
|
|
and !Globals.board_game.board.buildings.has(current_tile_coords)
|
|
|
|
|
):
|
|
|
|
|
if direction != Board.Direction.NONE:
|
|
|
|
|
direction = Board.Direction.NONE
|
|
|
|
|
return
|
2026-04-15 10:45:43 -05:00
|
|
|
if !direction_queue.is_empty():
|
|
|
|
|
direction = direction_queue.pop_front()
|
2026-04-20 13:03:39 -05:00
|
|
|
elif Globals.board_game.board.buildings.has(current_tile_coords):
|
|
|
|
|
var building = Globals.board_game.board.buildings[current_tile_coords]
|
|
|
|
|
if !buildings_visited.has(building):
|
|
|
|
|
buildings_visited.set(building, 0)
|
|
|
|
|
buildings_visited[building] += 1
|
|
|
|
|
building.activate(self)
|
|
|
|
|
direction_queue = building.get_direction_queue(self)
|
2026-04-15 10:45:43 -05:00
|
|
|
direction = direction_queue.pop_front()
|
2026-04-20 13:03:39 -05:00
|
|
|
elif Globals.board_game.board.tiles.has(current_tile_coords):
|
|
|
|
|
var tile = Globals.board_game.board.tiles[current_tile_coords]
|
2026-04-15 10:45:43 -05:00
|
|
|
if !tiles_visited.has(tile):
|
|
|
|
|
tiles_visited.set(tile, 0)
|
|
|
|
|
tiles_visited[tile as Tile] += 1
|
|
|
|
|
check_for_building()
|
|
|
|
|
check_for_turn(tile)
|
|
|
|
|
if (
|
|
|
|
|
buildings_visited.values().any(func(v: int): return v > 3)
|
|
|
|
|
or tiles_visited.values().any(func(v: int): return v > 3)
|
|
|
|
|
):
|
|
|
|
|
direction = Board.Direction.NONE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func handle_post_turn_actions() -> void:
|
|
|
|
|
queue_free()
|