diff --git a/godot/project.godot b/godot/project.godot index 37ee600..8bf8e4e 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -18,6 +18,7 @@ config/icon="res://icon.svg" [autoload] UserSettings="*res://settings/user_settings.gd" +Signals="*res://scenes/signals.gd" [display] diff --git a/godot/scenes/DisplayMood.gd b/godot/scenes/DisplayMood.gd index 349ae5e..ddbf263 100644 --- a/godot/scenes/DisplayMood.gd +++ b/godot/scenes/DisplayMood.gd @@ -2,6 +2,7 @@ extends Label @onready var crowd_controller: Crowd = get_node("/root/IngameScene/Crowd") + # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(_delta): text = str(int(crowd_controller.overall_mood)) diff --git a/godot/scenes/Tim.gd b/godot/scenes/Tim.gd index aaf12d5..812ea9e 100644 --- a/godot/scenes/Tim.gd +++ b/godot/scenes/Tim.gd @@ -3,14 +3,18 @@ extends Node2D @export var move_speed = 100 @export var boundary: Boundary -@export var tim_sprite : Sprite2D +@export var tim_sprite: Sprite2D @export var transmitter_area: Area2D +@export var stamina: int = 100 + +var default_texture: Texture2D = load("res://sprites/tim_side.png") +var ducking_texture: Texture2D = load("res://sprites/tim_ducking.svg") -@export var stamina : int = 100 # Called when the node enters the scene tree for the first time. func _ready(): - pass # Replace with function body. + Signals.hit_tim.connect(ouch) + # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): @@ -19,7 +23,7 @@ func _process(delta): global_position += Vector2.RIGHT * delta * move_speed if global_position.x > boundary.get_most_right_position(): global_position = Vector2(boundary.get_most_right_position(), global_position.y) - + if Input.is_action_pressed("move_left"): tim_sprite.flip_h = false global_position += Vector2.LEFT * delta * move_speed @@ -28,19 +32,20 @@ func _process(delta): func _on_joke_button_button_pressed(joke: Joke): + $AnimationPlayer.play("talking") stamina -= joke.required_stamina - + for body in transmitter_area.get_overlapping_bodies(): var person = body.find_parent("Person") if not (person is AudienceMember): continue - + person.on_joke(joke) - - + if stamina <= 0: _on_stamina_empty() + func _on_stamina_empty(): get_node("../DisplayGUI").visible = false @@ -55,3 +60,10 @@ func _on_stamina_empty(): score_overlay.get_node("VBoxContainer3/FinalScore").text = str(int(get_node("/root/IngameScene/Crowd").overall_mood)) score_overlay.grab_button_focus() score_overlay.visible = true + pass + + +func ouch(): + $Sprite2D.texture = ducking_texture + await get_tree().create_timer(1).timeout + $Sprite2D.texture = default_texture diff --git a/godot/scenes/crowd/audience_profile.gd b/godot/scenes/crowd/audience_profile.gd index 5750f49..74cbcc0 100644 --- a/godot/scenes/crowd/audience_profile.gd +++ b/godot/scenes/crowd/audience_profile.gd @@ -1,6 +1,7 @@ class_name AudienceProfile extends Node2D + class ProfileData: var happy_threshold: float var angry_threshold: float @@ -9,7 +10,14 @@ class ProfileData: var lashout_decay: float var joke_mood_mapping: Dictionary - func _init(happy_threshold, angry_threshold, lashout_threshold, happiness_decay, lashout_decay, joke_mood_mapping): + func _init( + happy_threshold, + angry_threshold, + lashout_threshold, + happiness_decay, + lashout_decay, + joke_mood_mapping + ): self.happy_threshold = happy_threshold self.angry_threshold = angry_threshold self.lashout_threshold = lashout_threshold @@ -17,32 +25,37 @@ class ProfileData: self.lashout_decay = lashout_decay self.joke_mood_mapping = joke_mood_mapping -var happy_threshold : float -var angry_threshold : float -var lashout_threshold : float -var happiness_decay : float -var lashout_decay : float +var happy_threshold: float +var angry_threshold: float +var lashout_threshold: float + +var happiness_decay: float +var lashout_decay: float # Maps JokeType (as int) to mood change (as float) var joke_mood_mapping: Dictionary + static func get_profile_data(index) -> ProfileData: var profiles = [ - ProfileData.new(3, -3, -10, 0.1, 0.1, { 0: 1, 1: -0.25, 2: 0 }), - ProfileData.new(3, -3, -10, 0.1, 0.1, { 0: 0, 1: 1, 2: -0.25 }), - ProfileData.new(3, -3, -10, 0.1, 0.1, { 0: -0.25, 1: 0, 2: 1 }), + ProfileData.new(3, -3, -10, 0.1, 0.1, {0: 1, 1: -0.25, 2: 0}), + ProfileData.new(3, -3, -10, 0.1, 0.1, {0: 0, 1: 1, 2: -0.25}), + ProfileData.new(3, -3, -10, 0.1, 0.1, {0: -0.25, 1: 0, 2: 1}), ] return profiles[index] + # Called when the node enters the scene tree for the first time. func _ready(): - pass # Replace with function body. + pass # Replace with function body. + # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(_delta): pass + func load_data(data: ProfileData): happy_threshold = data.happy_threshold angry_threshold = data.angry_threshold diff --git a/godot/scenes/crowd/crowd.gd b/godot/scenes/crowd/crowd.gd index 008a5f8..15cbdde 100644 --- a/godot/scenes/crowd/crowd.gd +++ b/godot/scenes/crowd/crowd.gd @@ -1,8 +1,8 @@ class_name Crowd extends Node2D -@export_range(1, 16, 1) -var max_persons = 16 +@export_range(1, 16, 1) var max_persons = 16 + var audience : Array[AudienceMember] = [] var overall_mood : float = 0 diff --git a/godot/scenes/crowd/person.gd b/godot/scenes/crowd/person.gd index a6f82a3..6de18e4 100644 --- a/godot/scenes/crowd/person.gd +++ b/godot/scenes/crowd/person.gd @@ -54,7 +54,7 @@ func _map_color_to_profile_data_index(color): "red": return 2 return 0 - + static func get_random_color(): var keys = ["blue", "green", "red"] return keys[randi() % keys.size()] @@ -64,14 +64,14 @@ func _ready(): laughter_left = 0. mood = randf_range(profile.lashout_threshold, profile.happy_threshold) update_expression() - + var profile_index = _map_color_to_profile_data_index(color) var profile_data = AudienceProfile.get_profile_data(profile_index) profile.load_data(profile_data) - + if body_shape == null: set_random_body(color) - + if face == null: set_random_face() @@ -79,16 +79,16 @@ func _ready(): func _process(delta): if laughter_left >= 0: laughter_left -= delta - + if mood > profile.happy_threshold * .5: mood -= profile.happiness_decay * delta elif mood < profile.lashout_threshold * .9: mood += profile.lashout_decay * delta - + if mood < profile.lashout_threshold: throw_bottle() - + update_expression() func _input(event): @@ -107,7 +107,7 @@ func update_mood(change: float): var bob_duration = laughter_duration / laughter_bobs / 2 tween.tween_property(face, "position", Vector2.UP * 20, bob_duration).set_delay(randf_range(0, bob_duration)) tween.tween_property(face, "position", Vector2.ZERO, bob_duration) - + mood += change func update_expression(): @@ -119,7 +119,7 @@ func update_expression(): expression = "angry" else: expression = "neutral" - + func set_random_body(for_color): if str(for_color) not in known_bodies: var keys = known_bodies.keys() diff --git a/godot/scenes/ingame_scene.gd b/godot/scenes/ingame_scene.gd index efb84d5..3337a84 100644 --- a/godot/scenes/ingame_scene.gd +++ b/godot/scenes/ingame_scene.gd @@ -3,20 +3,23 @@ extends Node2D @onready var fade_overlay = %FadeOverlay @onready var pause_overlay = %PauseOverlay + func _ready() -> void: fade_overlay.visible = true - + if SaveGame.has_save(): SaveGame.load_game(get_tree()) - + pause_overlay.game_exited.connect(_save_game) + func _input(event) -> void: if event.is_action_pressed("pause") and not pause_overlay.visible: get_viewport().set_input_as_handled() get_tree().paused = true pause_overlay.grab_button_focus() pause_overlay.visible = true - + + func _save_game() -> void: SaveGame.save_game(get_tree()) diff --git a/godot/scenes/objects/bottle.gd b/godot/scenes/objects/bottle.gd index 6b7061f..d68b6e8 100644 --- a/godot/scenes/objects/bottle.gd +++ b/godot/scenes/objects/bottle.gd @@ -1,5 +1,7 @@ extends Sprite2D +signal hit_tim + @export var bottle_speed: float = 120; var tim_global_position: Vector2 @@ -7,26 +9,27 @@ var is_hidding: bool # Called when the node enters the scene tree for the first time. func _ready(): - tim_global_position = get_node("/root/IngameScene/Stage/Tim/ThrowPoint").global_position + tim_global_position = get_node("/root/IngameScene/Stage/Tim/ThrowPoint").global_position # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): - var t = create_tween().set_parallel() - t.tween_property(self, "global_position", tim_global_position, 3.0) - t.tween_property(self, "rotation_degrees", rotation_degrees + 270, 3.0) - t.tween_callback(remove_bottle).set_delay(3.05) + var t = create_tween().set_parallel() + t.tween_property(self, "global_position", tim_global_position, 3.0) + t.tween_property(self, "rotation_degrees", rotation_degrees + 270, 3.0) + t.tween_callback(remove_bottle).set_delay(3.05) func _on_bottle_area_entered(area): - is_hidding = true + is_hidding = true func _on_bottle_area_exited(area): - is_hidding = false + is_hidding = false func _on_growth_timer_timeout(): - var t = create_tween() - t.tween_property(self, "scale", self.scale + Vector2(0.01, 0.01), 0.02) + var t = create_tween() + t.tween_property(self, "scale", self.scale + Vector2(0.01, 0.01), 0.02) func remove_bottle(): - if is_hidding: - print("Ouch") - queue_free() + if is_hidding: + print("Ouch") + Signals.hit_tim.emit() + queue_free() diff --git a/godot/scenes/signals.gd b/godot/scenes/signals.gd new file mode 100644 index 0000000..45b76e2 --- /dev/null +++ b/godot/scenes/signals.gd @@ -0,0 +1,3 @@ +extends Node + +signal hit_tim diff --git a/godot/scenes/stage.tscn b/godot/scenes/stage.tscn index 5008fda..74ff3dd 100644 --- a/godot/scenes/stage.tscn +++ b/godot/scenes/stage.tscn @@ -1,11 +1,13 @@ -[gd_scene load_steps=12 format=3 uid="uid://cicyfp5xjvvu4"] +[gd_scene load_steps=17 format=3 uid="uid://cicyfp5xjvvu4"] [ext_resource type="Texture2D" uid="uid://bg85if5rrrdmm" path="res://sprites/room/buehne.svg" id="1_32lst"] [ext_resource type="Script" path="res://scenes/Tim.gd" id="1_g3k2b"] [ext_resource type="Texture2D" uid="uid://kq63ictuirhc" path="res://sprites/tim_side.png" id="1_saxit"] [ext_resource type="Script" path="res://scenes/Boundary.gd" id="2_8p6ir"] [ext_resource type="PackedScene" uid="uid://r1i7ln2hpwq5" path="res://scenes/joke_button.tscn" id="3_0t41i"] +[ext_resource type="Texture2D" uid="uid://b8tb4o75kjffn" path="res://sprites/tim_talk.svg" id="3_e1fvx"] [ext_resource type="Script" path="res://scenes/DisplayStamina.gd" id="6_88orn"] +[ext_resource type="Texture2D" uid="uid://d2264dy2o4q6d" path="res://sprites/tim_side.svg" id="6_qpa7m"] [ext_resource type="FontFile" uid="uid://le2vdo2626vw" path="res://fonts/Montserrat-Medium.ttf" id="6_pb3a7"] [ext_resource type="Script" path="res://scenes/DisplayMood.gd" id="7_5m0td"] @@ -15,6 +17,59 @@ radius = 23.0217 [sub_resource type="RectangleShape2D" id="RectangleShape2D_wmfel"] size = Vector2(250, 10000) +[sub_resource type="Animation" id="Animation_n0bwh"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D:texture") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [ExtResource("3_e1fvx")] +} + +[sub_resource type="Animation" id="Animation_5tnw3"] +resource_name = "idle" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D:texture") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 1, +"values": [ExtResource("6_qpa7m"), ExtResource("6_qpa7m")] +} + +[sub_resource type="Animation" id="Animation_kkrfv"] +resource_name = "talking" +length = 4.0 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D:texture") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 3.95), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), +"update": 1, +"values": [ExtResource("1_saxit"), ExtResource("3_e1fvx"), ExtResource("6_qpa7m"), ExtResource("3_e1fvx"), ExtResource("6_qpa7m"), ExtResource("3_e1fvx"), ExtResource("6_qpa7m"), ExtResource("3_e1fvx"), ExtResource("1_saxit"), ExtResource("3_e1fvx"), ExtResource("6_qpa7m"), ExtResource("3_e1fvx"), ExtResource("6_qpa7m"), ExtResource("3_e1fvx"), ExtResource("6_qpa7m"), ExtResource("3_e1fvx"), ExtResource("1_saxit")] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_xvfym"] +_data = { +"RESET": SubResource("Animation_n0bwh"), +"idle": SubResource("Animation_5tnw3"), +"talking": SubResource("Animation_kkrfv") +} + [sub_resource type="LabelSettings" id="LabelSettings_aq472"] font = ExtResource("6_pb3a7") font_size = 32 @@ -46,7 +101,7 @@ shape = SubResource("CircleShape2D_jfw8v") z_index = 110 position = Vector2(-12, -142) scale = Vector2(0.4, 0.4) -texture = ExtResource("1_saxit") +texture = ExtResource("3_e1fvx") offset = Vector2(0, 50) [node name="Joke Buttons" type="Node2D" parent="Tim"] @@ -71,6 +126,11 @@ action = "joke_button_3" [node name="CollisionShape2D" type="CollisionShape2D" parent="Tim/Joke Transmitter/Area2D"] shape = SubResource("RectangleShape2D_wmfel") +[node name="AnimationPlayer" type="AnimationPlayer" parent="Tim"] +libraries = { +"": SubResource("AnimationLibrary_xvfym") +} + [node name="Boundary" type="Node2D" parent="."] script = ExtResource("2_8p6ir") diff --git a/godot/sprites/01_tim_cycle_silent.svg b/godot/sprites/01_tim_cycle_silent.svg new file mode 100644 index 0000000..9ace5cf --- /dev/null +++ b/godot/sprites/01_tim_cycle_silent.svg @@ -0,0 +1,138 @@ + + + + diff --git a/godot/sprites/01_tim_cycle_talk.svg b/godot/sprites/01_tim_cycle_talk.svg new file mode 100644 index 0000000..f53e612 --- /dev/null +++ b/godot/sprites/01_tim_cycle_talk.svg @@ -0,0 +1,138 @@ + + + + diff --git a/godot/sprites/02_tim_cycle_silent.svg b/godot/sprites/02_tim_cycle_silent.svg new file mode 100644 index 0000000..5388daf --- /dev/null +++ b/godot/sprites/02_tim_cycle_silent.svg @@ -0,0 +1,140 @@ + + + + diff --git a/godot/sprites/02_tim_cycle_talk.svg b/godot/sprites/02_tim_cycle_talk.svg new file mode 100644 index 0000000..ae395a8 --- /dev/null +++ b/godot/sprites/02_tim_cycle_talk.svg @@ -0,0 +1,138 @@ + + + + diff --git a/godot/sprites/03_tim_cycle_silent.svg b/godot/sprites/03_tim_cycle_silent.svg new file mode 100644 index 0000000..3273437 --- /dev/null +++ b/godot/sprites/03_tim_cycle_silent.svg @@ -0,0 +1,140 @@ + + + + diff --git a/godot/sprites/03_tim_cycle_talk.svg b/godot/sprites/03_tim_cycle_talk.svg new file mode 100644 index 0000000..75a5dc1 --- /dev/null +++ b/godot/sprites/03_tim_cycle_talk.svg @@ -0,0 +1,141 @@ + + + + diff --git a/godot/sprites/04_tim_cycle_silent.svg b/godot/sprites/04_tim_cycle_silent.svg new file mode 100644 index 0000000..90fb067 --- /dev/null +++ b/godot/sprites/04_tim_cycle_silent.svg @@ -0,0 +1,139 @@ + + + + diff --git a/godot/sprites/04_tim_cycle_talk.svg b/godot/sprites/04_tim_cycle_talk.svg new file mode 100644 index 0000000..6c338d3 --- /dev/null +++ b/godot/sprites/04_tim_cycle_talk.svg @@ -0,0 +1,138 @@ + + + + diff --git a/godot/sprites/tim_side.svg b/godot/sprites/tim_side.svg new file mode 100644 index 0000000..16d5361 --- /dev/null +++ b/godot/sprites/tim_side.svg @@ -0,0 +1,135 @@ + + + + diff --git a/godot/sprites/tim_side.svg.import b/godot/sprites/tim_side.svg.import new file mode 100644 index 0000000..e2e41cf --- /dev/null +++ b/godot/sprites/tim_side.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d2264dy2o4q6d" +path="res://.godot/imported/tim_side.svg-e21ef55d796afaf54c86d6a3abe989e5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://sprites/tim_side.svg" +dest_files=["res://.godot/imported/tim_side.svg-e21ef55d796afaf54c86d6a3abe989e5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/sprites/tim_talk.svg b/godot/sprites/tim_talk.svg new file mode 100644 index 0000000..87ec8d2 --- /dev/null +++ b/godot/sprites/tim_talk.svg @@ -0,0 +1,136 @@ + + + + diff --git a/godot/sprites/tim_talk.svg.import b/godot/sprites/tim_talk.svg.import new file mode 100644 index 0000000..16d21aa --- /dev/null +++ b/godot/sprites/tim_talk.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8tb4o75kjffn" +path="res://.godot/imported/tim_talk.svg-0c82c9a95046071242d6f5927c9a9d8e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://sprites/tim_talk.svg" +dest_files=["res://.godot/imported/tim_talk.svg-0c82c9a95046071242d6f5927c9a9d8e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false