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