diff --git a/.gitignore b/.gitignore index 37f05f2..40886ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.import +*.import +build/ diff --git a/HexGrid.gd b/HexGrid.gd new file mode 100644 index 0000000..a294c56 --- /dev/null +++ b/HexGrid.gd @@ -0,0 +1,67 @@ +extends Node2D + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +var rings = 4 +var storage = [] + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +func init_storage(rings: int): + self.rings = rings + self.storage = [] + # Not the smallest size, but will make a "square" buffer and some + # indices will never be accessed by get_item() + var size = (rings * 2) - 1 + size *= size + self.storage.resize(size) + +func _get_index(q: int, r: int): + # Using axial coordinates q and r are bounded from -(rings-1) to (rings-1) + assert(_is_valid_q_r(q, r)) + # To map to storage, we "push" the values up by (rings-1) so there are + # never any negative indices. Once there, we can use q, r as row, column + # addresses + var q_mod = q + (self.rings - 1) + var r_mod = r + (self.rings - 1) + var row_size = (self.rings * 2) - 1 + var index = (q_mod * row_size) + r_mod + assert(index < self.storage.size()) + return index + +func _is_valid_q_r(q: int, r: int): + return abs(q) < self.rings and abs(r) < self.rings + +func get_item(q: int, r: int): + var index = self._get_index(q, r) + return self.storage[index] + +func set_item(q: int, r: int, item): + var index = _get_index(q, r) + self.storage[index] = item + +func tag_edge_nodes(direction: Vector2, group: String): + var edges = [] + for item in self.storage: + if item == null: + continue + var loc = item.pf_location + var adjacent_spot = loc + direction + #print("Testing location: ", loc) + if not self._is_valid_q_r(adjacent_spot.x, adjacent_spot.y): + edges.append(loc) + continue + var neighbour = self.get_item(adjacent_spot.x, adjacent_spot.y) + if neighbour == null: + edges.append(loc) + for e in edges: + var item = self.get_item(e.x, e.y) + item.add_to_group(group) + +func get_neighbours(q, r): + return [] diff --git a/Menu.gd b/Menu.gd new file mode 100644 index 0000000..e69fbc6 --- /dev/null +++ b/Menu.gd @@ -0,0 +1,46 @@ +extends PopupPanel + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + + +func _on_Continue_pressed(): + self.set_visible(false) + +func _on_Quit_pressed(): + get_tree().quit() + +func _on_Help_pressed(): + self.set_visible(false) + # Brittle, refers to the layout in "Game" scenetree + get_node("../Help").set_visible(true) + + +func _on_Restart_pressed(): + get_tree().get_root().get_node("/root/Game").reset() + self.set_visible(false) + +func _on_scores_updated(scores): + var total = 0 + var max_score = 0 + for x in scores: + total += x + max_score = max(max_score, x) + get_node("VBoxContainer/Score").set_bbcode("[center]Score: %d[/center]" % total) + var s = "" + for x in range(scores.size()): + s += "Year %d: %d\n" % [x, scores[x]] + print(s) + get_node("VBoxContainer/ScoreByYear").set_bbcode(s) diff --git a/README.md b/README.md index e69de29..7fe3054 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,20 @@ +# LD54 : Da 'lil Patch + +You only have a small space. Can you keep it cultivated and producing well as +the years go on? + +## Tools + + * Debian Linux + * Godot 3.5 (gdscript) + * Art: GIMP, mypaint, inkscape, krita + * Sound: Audacity + +## External Assets + + * Font: Bitstream Vera Mono Nerd + +## Licenses + + * Assets (excluding font): CC-BY-SA-4.0 + * Source code: GPLv3 diff --git a/assets/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf b/assets/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf new file mode 100644 index 0000000..e63b764 Binary files /dev/null and b/assets/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf differ diff --git a/assets/Burn.wav b/assets/Burn.wav new file mode 100644 index 0000000..289a207 Binary files /dev/null and b/assets/Burn.wav differ diff --git a/assets/Cull.wav b/assets/Cull.wav new file mode 100644 index 0000000..35f9813 Binary files /dev/null and b/assets/Cull.wav differ diff --git a/assets/Fertilize.wav b/assets/Fertilize.wav new file mode 100644 index 0000000..94d9e95 Binary files /dev/null and b/assets/Fertilize.wav differ diff --git a/assets/Plant.wav b/assets/Plant.wav new file mode 100644 index 0000000..ab5b657 Binary files /dev/null and b/assets/Plant.wav differ diff --git a/assets/Query.wav b/assets/Query.wav new file mode 100644 index 0000000..93d8f6e Binary files /dev/null and b/assets/Query.wav differ diff --git a/assets/Rock.wav b/assets/Rock.wav new file mode 100644 index 0000000..246a17d Binary files /dev/null and b/assets/Rock.wav differ diff --git a/assets/Tweet.wav b/assets/Tweet.wav new file mode 100644 index 0000000..ff2e880 Binary files /dev/null and b/assets/Tweet.wav differ diff --git a/assets/apple fruit.png b/assets/apple fruit.png new file mode 100644 index 0000000..d77adea Binary files /dev/null and b/assets/apple fruit.png differ diff --git a/assets/apple icon.png b/assets/apple icon.png new file mode 100644 index 0000000..86761be Binary files /dev/null and b/assets/apple icon.png differ diff --git a/assets/apple plant.png b/assets/apple plant.png new file mode 100644 index 0000000..3e8086d Binary files /dev/null and b/assets/apple plant.png differ diff --git a/assets/apple tree.png b/assets/apple tree.png new file mode 100644 index 0000000..2d3975e Binary files /dev/null and b/assets/apple tree.png differ diff --git a/assets/audio recordings.aup3 b/assets/audio recordings.aup3 new file mode 100644 index 0000000..47ffaa8 Binary files /dev/null and b/assets/audio recordings.aup3 differ diff --git a/assets/bean icon.png b/assets/bean icon.png new file mode 100644 index 0000000..f7eb946 Binary files /dev/null and b/assets/bean icon.png differ diff --git a/assets/bean plant.png b/assets/bean plant.png new file mode 100644 index 0000000..a28ba5e Binary files /dev/null and b/assets/bean plant.png differ diff --git a/assets/bg.kra b/assets/bg.kra new file mode 100644 index 0000000..84ccdaf Binary files /dev/null and b/assets/bg.kra differ diff --git a/assets/bg.png b/assets/bg.png new file mode 100644 index 0000000..dc1113e Binary files /dev/null and b/assets/bg.png differ diff --git a/assets/clover flower.png b/assets/clover flower.png new file mode 100644 index 0000000..75dc66e Binary files /dev/null and b/assets/clover flower.png differ diff --git a/assets/clover icon.png b/assets/clover icon.png new file mode 100644 index 0000000..e2cde4b Binary files /dev/null and b/assets/clover icon.png differ diff --git a/assets/clover plant.png b/assets/clover plant.png new file mode 100644 index 0000000..f59803b Binary files /dev/null and b/assets/clover plant.png differ diff --git a/assets/corn fruit.png b/assets/corn fruit.png new file mode 100644 index 0000000..bf9041a Binary files /dev/null and b/assets/corn fruit.png differ diff --git a/assets/corn ripe.png b/assets/corn ripe.png new file mode 100644 index 0000000..2444e21 Binary files /dev/null and b/assets/corn ripe.png differ diff --git a/assets/hex.png b/assets/hex.png new file mode 100644 index 0000000..0db5f1d Binary files /dev/null and b/assets/hex.png differ diff --git a/assets/hex.svg b/assets/hex.svg new file mode 100644 index 0000000..eb2796c --- /dev/null +++ b/assets/hex.svg @@ -0,0 +1,58 @@ + + + + + + + + + + diff --git a/assets/icon burn.png b/assets/icon burn.png new file mode 100644 index 0000000..83a8b81 Binary files /dev/null and b/assets/icon burn.png differ diff --git a/assets/icon corn.png b/assets/icon corn.png new file mode 100644 index 0000000..1cf697d Binary files /dev/null and b/assets/icon corn.png differ diff --git a/assets/icon cull.png b/assets/icon cull.png new file mode 100644 index 0000000..a03246f Binary files /dev/null and b/assets/icon cull.png differ diff --git a/assets/icon fertilize.png b/assets/icon fertilize.png new file mode 100644 index 0000000..921ea41 Binary files /dev/null and b/assets/icon fertilize.png differ diff --git a/assets/icon plant.png b/assets/icon plant.png new file mode 100644 index 0000000..eb74342 Binary files /dev/null and b/assets/icon plant.png differ diff --git a/assets/icon query.png b/assets/icon query.png new file mode 100644 index 0000000..6a3cedc Binary files /dev/null and b/assets/icon query.png differ diff --git a/assets/icon remove rock.png b/assets/icon remove rock.png new file mode 100644 index 0000000..f234dce Binary files /dev/null and b/assets/icon remove rock.png differ diff --git a/assets/plant.png b/assets/plant.png new file mode 100644 index 0000000..14b1e74 Binary files /dev/null and b/assets/plant.png differ diff --git a/assets/rocky 1.png b/assets/rocky 1.png new file mode 100644 index 0000000..aec720d Binary files /dev/null and b/assets/rocky 1.png differ diff --git a/assets/rocky 2.png b/assets/rocky 2.png new file mode 100644 index 0000000..92b2f4b Binary files /dev/null and b/assets/rocky 2.png differ diff --git a/assets/rocky 3.png b/assets/rocky 3.png new file mode 100644 index 0000000..695448e Binary files /dev/null and b/assets/rocky 3.png differ diff --git a/assets/screenshots/light.png b/assets/screenshots/light.png new file mode 100644 index 0000000..2bd9fdb Binary files /dev/null and b/assets/screenshots/light.png differ diff --git a/assets/screenshots/tile.png b/assets/screenshots/tile.png new file mode 100644 index 0000000..d9bd849 Binary files /dev/null and b/assets/screenshots/tile.png differ diff --git a/assets/seeds.png b/assets/seeds.png new file mode 100644 index 0000000..ce3355a Binary files /dev/null and b/assets/seeds.png differ diff --git a/assets/small arrow.png b/assets/small arrow.png new file mode 100644 index 0000000..e52a070 Binary files /dev/null and b/assets/small arrow.png differ diff --git a/assets/soil.png b/assets/soil.png new file mode 100644 index 0000000..ee1c0e8 Binary files /dev/null and b/assets/soil.png differ diff --git a/assets/sound-.wav b/assets/sound-.wav new file mode 100644 index 0000000..a9d1297 Binary files /dev/null and b/assets/sound-.wav differ diff --git a/assets/sprouts.png b/assets/sprouts.png new file mode 100644 index 0000000..ac9ddc3 Binary files /dev/null and b/assets/sprouts.png differ diff --git a/assets/strong weed icon.png b/assets/strong weed icon.png new file mode 100644 index 0000000..e6a88fc Binary files /dev/null and b/assets/strong weed icon.png differ diff --git a/assets/strong weed plant.png b/assets/strong weed plant.png new file mode 100644 index 0000000..9cf0d94 Binary files /dev/null and b/assets/strong weed plant.png differ diff --git a/assets/sun.png b/assets/sun.png new file mode 100644 index 0000000..9bf92ff Binary files /dev/null and b/assets/sun.png differ diff --git a/assets/tiles.xcf b/assets/tiles.xcf new file mode 100644 index 0000000..7cc88b9 Binary files /dev/null and b/assets/tiles.xcf differ diff --git a/assets/weed icon.png b/assets/weed icon.png new file mode 100644 index 0000000..52835f4 Binary files /dev/null and b/assets/weed icon.png differ diff --git a/assets/weed plant.png b/assets/weed plant.png new file mode 100644 index 0000000..e5b2da6 Binary files /dev/null and b/assets/weed plant.png differ diff --git a/export_presets.cfg b/export_presets.cfg new file mode 100644 index 0000000..8d12d07 --- /dev/null +++ b/export_presets.cfg @@ -0,0 +1,176 @@ +[preset.0] + +name="Linux/X11" +platform="Linux/X11" +runnable=true +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="build/linux-x86_64/dalilpatch.x86_64" +script_export_mode=1 +script_encryption_key="" + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +binary_format/64_bits=true +binary_format/embed_pck=false +texture_format/bptc=false +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false +texture_format/no_bptc_fallbacks=true + +[preset.1] + +name="Windows Desktop" +platform="Windows Desktop" +runnable=true +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="build/win11-x64_64/dalilpatch.x86_64.exe" +script_export_mode=1 +script_encryption_key="" + +[preset.1.options] + +custom_template/debug="" +custom_template/release="" +binary_format/64_bits=true +binary_format/embed_pck=false +texture_format/bptc=false +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false +texture_format/no_bptc_fallbacks=true +codesign/enable=false +codesign/identity_type=0 +codesign/identity="" +codesign/password="" +codesign/timestamp=true +codesign/timestamp_server_url="" +codesign/digest_algorithm=1 +codesign/description="" +codesign/custom_options=PoolStringArray( ) +application/modify_resources=true +application/icon="" +application/file_version="" +application/product_version="" +application/company_name="" +application/product_name="" +application/file_description="" +application/copyright="" +application/trademarks="" + +[preset.2] + +name="HTML5" +platform="HTML5" +runnable=true +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="build/web/dalilpatch.x86_64.exe.html" +script_export_mode=1 +script_encryption_key="" + +[preset.2.options] + +custom_template/debug="" +custom_template/release="" +variant/export_type=0 +vram_texture_compression/for_desktop=true +vram_texture_compression/for_mobile=false +html/export_icon=true +html/custom_html_shell="" +html/head_include="" +html/canvas_resize_policy=2 +html/focus_canvas_on_start=true +html/experimental_virtual_keyboard=false +progressive_web_app/enabled=false +progressive_web_app/offline_page="" +progressive_web_app/display=1 +progressive_web_app/orientation=0 +progressive_web_app/icon_144x144="" +progressive_web_app/icon_180x180="" +progressive_web_app/icon_512x512="" +progressive_web_app/background_color=Color( 0, 0, 0, 1 ) + +[preset.3] + +name="Mac OSX" +platform="Mac OSX" +runnable=true +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="build/osx/dalilpatch.x86_64.exe.html.zip" +script_export_mode=1 +script_encryption_key="" + +[preset.3.options] + +custom_template/debug="" +custom_template/release="" +application/name="" +application/info="Made with Godot Engine" +application/icon="" +application/identifier="" +application/signature="" +application/app_category="Games" +application/short_version="1.0" +application/version="1.0" +application/copyright="" +display/high_res=false +privacy/microphone_usage_description="" +privacy/camera_usage_description="" +privacy/location_usage_description="" +privacy/address_book_usage_description="" +privacy/calendar_usage_description="" +privacy/photos_library_usage_description="" +privacy/desktop_folder_usage_description="" +privacy/documents_folder_usage_description="" +privacy/downloads_folder_usage_description="" +privacy/network_volumes_usage_description="" +privacy/removable_volumes_usage_description="" +codesign/enable=true +codesign/identity="" +codesign/timestamp=true +codesign/hardened_runtime=true +codesign/replace_existing_signature=true +codesign/entitlements/custom_file="" +codesign/entitlements/allow_jit_code_execution=false +codesign/entitlements/allow_unsigned_executable_memory=false +codesign/entitlements/allow_dyld_environment_variables=false +codesign/entitlements/disable_library_validation=false +codesign/entitlements/audio_input=false +codesign/entitlements/camera=false +codesign/entitlements/location=false +codesign/entitlements/address_book=false +codesign/entitlements/calendars=false +codesign/entitlements/photos_library=false +codesign/entitlements/apple_events=false +codesign/entitlements/debugging=false +codesign/entitlements/app_sandbox/enabled=false +codesign/entitlements/app_sandbox/network_server=false +codesign/entitlements/app_sandbox/network_client=false +codesign/entitlements/app_sandbox/device_usb=false +codesign/entitlements/app_sandbox/device_bluetooth=false +codesign/entitlements/app_sandbox/files_downloads=0 +codesign/entitlements/app_sandbox/files_pictures=0 +codesign/entitlements/app_sandbox/files_music=0 +codesign/entitlements/app_sandbox/files_movies=0 +codesign/custom_options=PoolStringArray( ) +notarization/enable=false +notarization/apple_id_name="" +notarization/apple_id_password="" +notarization/apple_team_id="" +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false diff --git a/project.godot b/project.godot index d13afd3..c7cd80b 100644 --- a/project.godot +++ b/project.godot @@ -11,12 +11,53 @@ config_version=4 [application] config/name="Ld 54" +config/description="Get the most out of the small bit of land that you can call yours" +run/main_scene="res://src/Game.tscn" +boot_splash/show_image=false config/icon="res://icon.png" [gui] common/drop_mouse_on_gui_input_disabled=true +[input] + +ui_help={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":true,"control":false,"meta":false,"command":false,"pressed":false,"scancode":47,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +ui_plant={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +ui_query={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +ui_cull={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +ui_burn={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":70,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +ui_removerock={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":71,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +ui_fertilize={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":72,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} + [physics] common/enable_pause_aware_picking=true diff --git a/src/Game.gd b/src/Game.gd new file mode 100644 index 0000000..ac5ce8f --- /dev/null +++ b/src/Game.gd @@ -0,0 +1,435 @@ +extends Node + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" +signal day_time_changed(old, new) +signal season_changed(old, new) +signal year_changed(old, new) +signal action_points_changed(old, new) +signal scores_updated(new) + +enum SEASON {SPRING, SUMMER_1, SUMMER_2, FALL} +const season_text = ["Spring", "Early Summer", "Late Summer", "Autumn"] +const season_light_mod = [1.0, 1.1, 1.2, 1.0] +enum TIME {DAWN, MORNING, AFTERNOON, DUSK} +const time_text = ["Dawn", "Morning", "Afternoon", "Dusk"] +const time_light_strength = [20, 60, 80, 10] +const time_light_from = [ + # q-r space + Vector2(-1, 0), + Vector2(0, -1), + Vector2(1, -1), + Vector2(1, 0) +] +const time_light_to = [ + # q-r space + Vector2(1, 0), + Vector2(0, 1), + Vector2(-1, 1), + Vector2(-1, 0) +] + +const StructureSpot = preload("Spot.tscn") +const Soil = preload("Soil.tscn") +const Plant = preload("Plant.tscn") +const HexGrid = preload("HexGrid.tscn") +const FadingText = preload("res://src/ui/FadingText.tscn") + +const hex_scale = 1.5 +const hex_size = 32 * hex_scale +const hex_width = hex_size * sqrt(3) +const hex_height = 2 * hex_size + +var year = 0 +var scores = [] +var current_season = SEASON.SPRING +var current_time = TIME.DAWN +var grid = null +var action_points = 3 +var current_action = "plant" +var last_action = "plant" +var current_plant = "corn" +var current_ap = 3 +var current_hex = null +var hex_click_start = null +var stage_timer = 0.0 +var stage_time = 2.0 + +var plant_types = { + "corn": preload("res://src/plants/Corn.tscn").instance(), + "bean": preload("res://src/plants/Bean.tscn").instance(), + "apple": preload("res://src/plants/Apple.tscn").instance(), + "clover": preload("res://src/plants/Clover.tscn").instance(), + "weed": preload("res://src/plants/Weed.tscn").instance(), + "strong_weed": preload("res://src/plants/StrongWeed.tscn").instance(), +} + +func sun_strength(time, season): + return round(self.time_light_strength[time] * self.season_light_mod[season]) + +func update_action_points(value): + emit_signal("action_points_changed", self.action_points, self.action_points + value) + self.action_points += value + +func reset(): + get_tree().call_group("runtime", "queue_free") + self.year = 0 + self.scores = [0] + self.action_points = 3 + self.update_action_points(0) + self.current_season = SEASON.SPRING + self.current_time = TIME.DAWN + self.current_ap = 3 + self.current_hex = null + if self.current_action == "pass_time": + self.current_action = self.last_action + get_node("Ui/Right/VBoxContainer2/ActionMenu").unlock() + self.hex_click_start = null + self.stage_timer = -1.0 + self.grid = null + print("Reset") + self.init_playfield() + +func init_playfield(): + var grid = HexGrid.instance() + grid.add_to_group("runtime") + grid.init_storage(4) + var center = get_viewport().get_visible_rect().size / 2 + var hex_offset = Vector2( + 0, # ((4*2)-1) * hex_width / 2, + ((4*2)-1) * hex_height / 2 + ) + hex_offset.x += center.x + # print(str(center)) + var soil = 0 + var spot = 0 + for q in range(-3, 4): + for r in range(-3, 4): + var s = -q-r + # We don't want some parts of the rhombus on the playfield + if abs((q + r)) >= 4: + continue + var x = null + var pos = Vector2(0, 0) + if abs(q) < 3 and abs(r) < 3 and abs(s) < 3: + # On the inside make Soil + x = Soil.instance() + soil += 1 + else: + # disable structure spots for the moment + continue + # On the outer ring, make a structure spot, except on the + # bottom half + if r >= 0: + continue + x = StructureSpot.instance() + spot += 1 + x.add_to_group("runtime") + x.set_location(Vector2(q, r)) + grid.set_item(q, r, x) + # print("Created at ", q, ",", r, ": ", x) + # Set position + pos.y = hex_offset.y + (r * hex_height * 0.75) + pos.x = hex_offset.x + (q * hex_width) + (r * (hex_size-5)) + #print(str(q), ",", str(r), " ", str(pos)) + x.set_position(pos) + x.connect("mouse_entered", self, "_on_HexHover", [x, true]) + x.connect("mouse_exited", self, "_on_HexHover", [x, false]) + x.connect("input_event", self, "_on_HexInputEvent", [x]) + add_child(x) + for t in range(self.time_light_from.size()): + grid.tag_edge_nodes(self.time_light_from[t], "edge_time_%d" % t) + #print("Created %d soil and %d spot tiles" % [soil, spot]) + self.grid = grid + add_child(grid) + +# Called when the node enters the scene tree for the first time. +func _ready(): + find_node("PlantMenu").set_plants(self.plant_types) + get_node("Ui/Right/VBoxContainer2/ActionMenu").connect("action_changed", self, "_on_action_changed") + self.connect("action_points_changed", get_node("Ui/Right/VBoxContainer2/ActionMenu"), "_on_action_points_changed") + get_node("Ui/Left/VBoxContainer/PlantMenu").connect("plant_type_changed", self, "_on_plant_type_changed") + self.connect("action_points_changed", self, "_on_action_points_changed") + self.connect("day_time_changed", get_node("Sun"), "_on_day_time_changed") + self.connect("day_time_changed", self, "_on_day_time_changed") + self.connect("season_changed", self, "_on_season_changed") + self.connect("year_changed", self, "_on_year_changed") + self.connect("scores_updated", get_node("Ui/Menu"), "_on_scores_updated") + self.reset() + randomize() + +func advance_year(): + emit_signal("year_changed", self.year, self.year + 1) + self.year += 1 + self.scores.append(0) + emit_signal("scores_updated", self.scores) + +func advance_season(): + var t = self.current_season + 1 + var advance_year = false + if t > SEASON.FALL: + t = SEASON.SPRING + advance_year = true + # Do events for the end of the current season + var banner = FadingText.instance() + banner.set_text(self.season_text[t]) + banner.set_scale(Vector2(3.0, 3.0)) + banner.life_cur = 4.0 + var center = get_viewport().get_visible_rect().size / 2 + # Do this to remove some of the visual line splitting + var size = banner.get_text_size() * banner.get_scale() + #print("Banner text size: ", size) + #print("Banner size: ", banner.get_size()) + banner.set_size(Vector2(size.x, size.y)) + size = banner.get_text_size() * banner.get_scale() + banner.set_position(Vector2(center.x - size.x/2.0, 30 - min(10, size.y/2.0))) + #print("Banner position: ", banner.get_position()) + + add_child(banner) + # Plants consume the nutrients and health of soil + Plant effects + #for soil in get_tree().get_nodes_in_group("soil"): + # soil.nourish_plants_and_run_plant_effects(self.current_season, t, self.grid) + get_tree().call_group("soil", "nourish_plants_and_run_plant_effects", self.current_season, t, self.grid) + # Add action points + self.update_action_points(2) + if advance_year: + for soil in get_tree().get_nodes_in_group("soil"): + if soil.stored != null: + var plant_score = soil.stored.get_score() + self.scores[self.year] += plant_score + if plant_score > 0: + var f = FadingText.instance() + f.set_text("%+d points" % plant_score) + f.set_position(Vector2(32, 32)) + f.set_modulate(Color(0.9, 0.1, 0.9)) + soil.add_child(f) + soil.end_of_year(self.grid) + self.advance_year() + self.set_season(t) + # Any events at the start of the new season + +func set_season(season: int): + emit_signal("season_changed", self.current_season, season) + self.current_season = season + +func advance_time(): + var t = self.current_time + 1 + var advance_season = false + print("Advancing time to ", t) + if t > TIME.DUSK: + t = TIME.DAWN + advance_season = true + # Do the things that have to be done for the old time + # Show where light is coming from + var group = "edge_time_%d" % self.current_time + var sun = self.sun_strength(self.current_time, self.current_season) + for node in get_tree().get_nodes_in_group(group): + node.display_arrow(self.time_light_from[self.current_time], + self.hex_height, self.hex_width, self.hex_size) + # Calculate the light that reaches all the tiles + var first = node + var second = null + var light = sun + var last_tallest = 0 + while first != null: + first.apply_light(light) + last_tallest = max(last_tallest, first.get_height()) + var loc = first.pf_location + self.time_light_to[self.current_time] + if self.grid._is_valid_q_r(loc.x, loc.y): + second = self.grid.get_item(loc.x, loc.y) + if second != null: + if last_tallest > second.get_height(): + light = 0 + else: + light = sun + last_tallest = max(last_tallest, second.get_height()) + first = second + second = null + + # Run growth on tiles + # For tiles that have no plants, weed maybe + if advance_season: + self.advance_season() + self.set_time(t) + # Any events at the start of the new time + +func set_time(period: int): + emit_signal("day_time_changed", self.current_time, period) + self.current_time = period + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta): + if self.current_action == "pass_time": + if self.stage_timer > 0.0: + self.stage_timer -= delta + else: + self.advance_time() + if self.current_time != TIME.DAWN: + self.stage_timer = self.stage_time + else: + self.current_action = self.last_action + self.update_current_hex_action_possibility() + # Some other things... + get_node("Ui/Right/VBoxContainer2/ActionMenu").unlock() + + +func _unhandled_input(event): + if Input.is_action_pressed("ui_cancel"): + get_node("Ui/Menu").popup_centered() + if Input.is_action_pressed("ui_help"): + var help = get_node("Ui/Help") + if help.is_visible(): + help.set_visible(false) + else: + help.popup_centered() + var action_menu = get_node("Ui/Right/VBoxContainer2/ActionMenu") + if Input.is_action_pressed("ui_plant"): + action_menu.find_node("Plant").set_pressed(true) + if Input.is_action_pressed("ui_query"): + action_menu.find_node("Query").set_pressed(true) + if Input.is_action_pressed("ui_cull"): + action_menu.find_node("Cull").set_pressed(true) + if Input.is_action_pressed("ui_burn"): + action_menu.find_node("Burn").set_pressed(true) + if Input.is_action_pressed("ui_removerock"): + action_menu.find_node("RemoveRock").set_pressed(true) + if Input.is_action_pressed("ui_fertilize"): + action_menu.find_node("Fertilize").set_pressed(true) + +func _on_Help_pressed(): + get_node("Ui/Help").popup_centered() + + +func _on_MenuButton_pressed(): + get_node("Ui/Menu").popup_centered() + +func _on_HexHover(hex, inside): + #print("Hex ", hex, " at ", hex.pf_location) + if inside: + self.current_hex = hex + hex.start_tooltip_timer() + hex.get_node("Border").set_modulate(Color(0.0, 1.0, 0.0)) + self.update_current_hex_action_possibility() + else: + self.current_hex = null + hex.update_tooltip("") + hex.hide_tooltip() + hex.get_node("Border").set_modulate(Color(1.0, 1.0, 1.0)) + self.update_current_hex_action_possibility() + + +func update_current_hex_action_possibility(): + if self.current_hex == null: + # Reset mouse pointer + Input.set_default_cursor_shape(Input.CURSOR_ARROW) + return + # Need to check if current action be done on the hex + # Show user why not + var action_compat = self.current_hex.can_do_action(self.current_action) + var applicable = action_compat[0] + var possible = action_compat[1] + var reason = action_compat[2] + var cost = action_compat[3] + if cost > self.action_points: + possible = false + reason = "Too few action points. Have %d, need %d" % [self.action_points, cost] + if applicable: + if not possible: + Input.set_default_cursor_shape(Input.CURSOR_FORBIDDEN) + self.current_hex.get_node("Border").set_modulate(Color(1.0, 0.0, 0.0)) + self.current_hex.update_tooltip(reason) + else: + Input.set_default_cursor_shape(Input.CURSOR_CAN_DROP) + else: + self.current_hex.get_node("Border").set_modulate(Color(0.25, 0.25, 0.25)) + +func _on_HexInputEvent(viewport, event, shape, hex): + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT: + if event.pressed: + self.hex_click_start = hex + else: + if self.hex_click_start == hex: + self.do_action(hex, self.current_action) + else: + self.hex_click_start = null + +func do_action(hex, action): + # Recheck if action is possible on hex + var action_compat = hex.can_do_action(action) + var cost = action_compat[3] + if not action_compat[0] or not action_compat[1]: + return + if cost > self.action_points: + return + print(action, " on ", hex) + if action == "query": + get_node("Ui/Right/VBoxContainer2/Details/Panel").set_text(hex.query_details()) + get_node("AudioQuery").play() + elif action == "plant": + print(self.current_plant) + hex.do_action(action, + {"plant": self.plant_types[self.current_plant].duplicate()}) + get_node("AudioPlant").play() + elif action == "cull": + var r = hex.do_action(action, null) + if r != null and r > 0: + self.scores[self.current_year] += r + print("Got %+d from culling plant", r) + emit_signal("scores_updated", self.scores) + get_node("AudioCull").play() + elif action == "burn": + hex.do_action(action, null) + get_node("AudioBurn").play() + elif action == "removerock": + hex.do_action(action, null) + get_node("AudioRemoveRock").play() + elif action == "fertilize": + hex.do_action(action, null) + get_node("AudioFertilize").play() + else: + print("UNKNOWN ACTION ", action) + if (cost > 0): + var f = FadingText.instance() + f.set_text("%+d AP" % -cost) + f.set_position(Vector2(32, 0)) + f.move_towards = Vector2(64, -32) + f.set_modulate(Color(0.9, 0.1, 0.1)) + hex.add_child(f) + self.update_action_points(-cost) + + +func _on_action_changed(action): + self.last_action = self.current_action + self.current_action = action + self.update_current_hex_action_possibility() + if action == "pass_time": + self.advance_time() + self.stage_timer = self.stage_time + +func _on_day_time_changed(old, new): + get_node("Ui/Left/VBoxContainer/TimeLabel").set_text("Time: %s" % self.time_text[new]) + # Show a banner of the stage + var banner = FadingText.instance() + banner.set_text(self.time_text[old]) + banner.set_scale(Vector2(2.0, 2.0)) + var center = get_viewport().get_visible_rect().size / 2 + var size = banner.get_text_size() + banner.set_position(Vector2(center.x - size.x/2.0, center.y*2.0 - 20 - size.y/2.0)) + add_child(banner) + if new == TIME.DAWN: + get_node("AudioDawn").play() + +func _on_season_changed(old, new): + get_node("Ui/Left/VBoxContainer/SeasonLabel").set_text("Season: %s" % self.season_text[new]) + +func _on_year_changed(old, new): + get_node("Ui/Left/VBoxContainer/YearLabel").set_text("Year: %d" % self.year) + +func _on_action_points_changed(old, new): + self.update_current_hex_action_possibility() + +func _on_plant_type_changed(value): + self.current_plant = value diff --git a/src/Game.tscn b/src/Game.tscn new file mode 100644 index 0000000..07b3873 --- /dev/null +++ b/src/Game.tscn @@ -0,0 +1,171 @@ +[gd_scene load_steps=15 format=2] + +[ext_resource path="res://src/Game.gd" type="Script" id=1] +[ext_resource path="res://src/Menu.tscn" type="PackedScene" id=2] +[ext_resource path="res://src/Help.tscn" type="PackedScene" id=3] +[ext_resource path="res://src/Sun.tscn" type="PackedScene" id=4] +[ext_resource path="res://src/ui/PlantMenu.tscn" type="PackedScene" id=5] +[ext_resource path="res://src/ui/ActionMenu.tscn" type="PackedScene" id=6] +[ext_resource path="res://assets/bg.png" type="Texture" id=7] +[ext_resource path="res://assets/Tweet.wav" type="AudioStream" id=8] +[ext_resource path="res://assets/Plant.wav" type="AudioStream" id=9] +[ext_resource path="res://assets/Rock.wav" type="AudioStream" id=10] +[ext_resource path="res://assets/Query.wav" type="AudioStream" id=11] +[ext_resource path="res://assets/Cull.wav" type="AudioStream" id=12] +[ext_resource path="res://assets/Fertilize.wav" type="AudioStream" id=13] +[ext_resource path="res://assets/Burn.wav" type="AudioStream" id=14] + +[node name="Game" type="Node2D"] +script = ExtResource( 1 ) + +[node name="Ui" type="Control" parent="."] +margin_right = 40.0 +margin_bottom = 40.0 + +[node name="Menu" parent="Ui" instance=ExtResource( 2 )] + +[node name="Help" parent="Ui" instance=ExtResource( 3 )] + +[node name="Left" type="Panel" parent="Ui"] +margin_right = 160.0 +margin_bottom = 600.0 +size_flags_horizontal = 0 +size_flags_vertical = 0 + +[node name="VBoxContainer" type="VBoxContainer" parent="Ui/Left"] +margin_right = 40.0 +margin_bottom = 40.0 + +[node name="TimeLabel" type="Button" parent="Ui/Left/VBoxContainer"] +margin_right = 160.0 +margin_bottom = 20.0 +hint_tooltip = "When you \"Let Time Pass\", the day goes through Dawn, Morning, Afternoon, and Dusk. +Each part of the day shines light from a different direction on to your field. The sun is strongest in the Afternoon. +Tall items block the passage of sunlight to those behind." +focus_mode = 0 +shortcut_in_tooltip = false +enabled_focus_mode = 0 +text = "Time: Dawn" +flat = true + +[node name="SeasonLabel" type="Button" parent="Ui/Left/VBoxContainer"] +margin_top = 24.0 +margin_right = 160.0 +margin_bottom = 44.0 +hint_tooltip = "Each Dawn is the start of a new season. +Each new season gives you more Action Points (AP). +At the end of the Autumn season, all the plants are automatically harvested. +Unless a perennial survives winter, it will also be removed." +shortcut_in_tooltip = false +text = "Season: Spring" +flat = true + +[node name="YearLabel" type="Button" parent="Ui/Left/VBoxContainer"] +margin_top = 48.0 +margin_right = 160.0 +margin_bottom = 68.0 +hint_tooltip = "The in-game year" +shortcut_in_tooltip = false +text = "Year: 0" +flat = true + +[node name="PlantMenu" parent="Ui/Left/VBoxContainer" instance=ExtResource( 5 )] +margin_top = 72.0 +margin_right = 160.0 +margin_bottom = 395.0 + +[node name="Right" type="Panel" parent="Ui"] +margin_left = 864.0 +margin_right = 1024.0 +margin_bottom = 600.0 +__meta__ = { +"_edit_group_": true +} + +[node name="VBoxContainer2" type="VBoxContainer" parent="Ui/Right"] +margin_right = 40.0 +margin_bottom = 40.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="Ui/Right/VBoxContainer2"] +margin_right = 160.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 160, 0 ) +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 1 + +[node name="Help" type="Button" parent="Ui/Right/VBoxContainer2/HBoxContainer"] +margin_left = 33.0 +margin_right = 75.0 +margin_bottom = 20.0 +hint_tooltip = "Help" +text = "Help" +icon_align = 1 +expand_icon = true + +[node name="MenuButton" type="Button" parent="Ui/Right/VBoxContainer2/HBoxContainer"] +margin_left = 79.0 +margin_right = 127.0 +margin_bottom = 20.0 +hint_tooltip = "Menu" +text = "Menu" +align = 0 +icon_align = 1 +expand_icon = true + +[node name="ActionMenu" parent="Ui/Right/VBoxContainer2" instance=ExtResource( 6 )] +margin_bottom = 285.0 + +[node name="Details" type="VBoxContainer" parent="Ui/Right/VBoxContainer2"] +margin_top = 289.0 +margin_right = 160.0 +margin_bottom = 322.0 + +[node name="Label" type="Label" parent="Ui/Right/VBoxContainer2/Details"] +margin_right = 160.0 +margin_bottom = 14.0 +text = "Details" +align = 1 +valign = 1 +autowrap = true +uppercase = true + +[node name="Panel" type="RichTextLabel" parent="Ui/Right/VBoxContainer2/Details"] +margin_top = 18.0 +margin_right = 160.0 +margin_bottom = 33.0 +bbcode_enabled = true +fit_content_height = true + +[node name="Sun" parent="." instance=ExtResource( 4 )] +position = Vector2( 226, 335 ) + +[node name="Background" type="Sprite" parent="."] +z_index = -2 +z_as_relative = false +texture = ExtResource( 7 ) +centered = false + +[node name="AudioDawn" type="AudioStreamPlayer" parent="."] +stream = ExtResource( 8 ) + +[node name="AudioPlant" type="AudioStreamPlayer" parent="."] +stream = ExtResource( 9 ) + +[node name="AudioQuery" type="AudioStreamPlayer" parent="."] +stream = ExtResource( 11 ) + +[node name="AudioCull" type="AudioStreamPlayer" parent="."] +stream = ExtResource( 12 ) + +[node name="AudioRemoveRock" type="AudioStreamPlayer" parent="."] +stream = ExtResource( 10 ) + +[node name="AudioBurn" type="AudioStreamPlayer" parent="."] +stream = ExtResource( 14 ) + +[node name="AudioFertilize" type="AudioStreamPlayer" parent="."] +stream = ExtResource( 13 ) + +[connection signal="pressed" from="Ui/Right/VBoxContainer2/HBoxContainer/Help" to="." method="_on_Help_pressed"] +[connection signal="pressed" from="Ui/Right/VBoxContainer2/HBoxContainer/MenuButton" to="." method="_on_MenuButton_pressed"] diff --git a/src/Help.gd b/src/Help.gd new file mode 100644 index 0000000..2dda235 --- /dev/null +++ b/src/Help.gd @@ -0,0 +1,16 @@ +extends PopupPanel + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/Help.tscn b/src/Help.tscn new file mode 100644 index 0000000..862e0ed --- /dev/null +++ b/src/Help.tscn @@ -0,0 +1,87 @@ +[gd_scene load_steps=6 format=2] + +[ext_resource path="res://src/Help.gd" type="Script" id=1] +[ext_resource path="res://assets/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf" type="DynamicFontData" id=2] +[ext_resource path="res://assets/screenshots/tile.png" type="Texture" id=3] +[ext_resource path="res://assets/screenshots/light.png" type="Texture" id=4] + +[sub_resource type="DynamicFont" id=1] +size = 40 +outline_size = 1 +font_data = ExtResource( 2 ) + +[node name="Help" type="PopupPanel"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 72.0 +margin_right = 72.0 +script = ExtResource( 1 ) + +[node name="HBoxContainer" type="VBoxContainer" parent="."] +margin_right = 40.0 +margin_bottom = 40.0 + +[node name="Label" type="Label" parent="HBoxContainer"] +margin_right = 965.0 +margin_bottom = 48.0 +size_flags_horizontal = 3 +custom_colors/font_color = Color( 0.996078, 1, 0.258824, 1 ) +custom_colors/font_outline_modulate = Color( 1, 0, 0.972549, 1 ) +custom_fonts/font = SubResource( 1 ) +text = "Da 'Lil Patch" +align = 1 + +[node name="VBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +margin_top = 52.0 +margin_right = 965.0 +margin_bottom = 508.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/VBoxContainer"] +margin_right = 965.0 +margin_bottom = 456.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +margin_right = 160.0 +margin_bottom = 456.0 +rect_min_size = Vector2( 160, 0 ) + +[node name="Sprite" type="Sprite" parent="HBoxContainer/VBoxContainer/HBoxContainer/VBoxContainer"] +position = Vector2( 84, 63 ) +texture = ExtResource( 3 ) + +[node name="Sprite2" type="Sprite" parent="HBoxContainer/VBoxContainer/HBoxContainer/VBoxContainer"] +position = Vector2( 78, 223 ) +scale = Vector2( 0.623711, 0.617424 ) +texture = ExtResource( 4 ) + +[node name="Label2" type="Label" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +margin_left = 164.0 +margin_right = 965.0 +margin_bottom = 456.0 +text = "In \"Da 'Lil Patch\", the goal is to make the best use of the small plot of land you have. + +Choose plants from the left-hand side menu, and select which actions you want to do from the right-hand side menu. + +1. The first thing you will want to do is place some seeds down. +2. Click pass time to see how the plants get sunlight and grow + +At the end of each \"Autumn\" plants are harvested and give you score based on how ripe they are. Some plants, like Weeds +and Clover, don't give any points. Some plants can take a long time to bear fruit. + +Each plant changes the soil it's own, and potentially affects the tiles around it it. + +The sunlight comes from four (4) different directions each time you click on \"Pass Time\": left, top-left, top-right, and right. +The strength of the sunlight varies with the time of day and the current season. As each growth tick happens, you'll see \"+X\" +over the plants in green for how much growth they received. + +Some tiles also turn dark, to show that they haven't received any sunlight. When there is a plant in the tile that's taller than +the adjacent tiles in the sunlight's path, it will shade the next tiles until a taller plant is encountered. + +As each season passes, the plants consume nutrients and health from the soil. Most soil also accumulates rocks as the +harvests happen. Eventually there might be big boulders on some of the tiles! Each season also gives you some more Action +Points, which can be used to Cull (remove) plants early, Burn plants off the land, Remove Rocks, or Fertilize a tile. Each action +has a different cost and effect explained by the tooltips. + +You can check the scores for the years that have passed in the menu by clicking on the Menu button or hitting Escape. + +You can press escape to close this pane, and Shift+Slash to show it again." diff --git a/src/Hex.gd b/src/Hex.gd new file mode 100644 index 0000000..762edd9 --- /dev/null +++ b/src/Hex.gd @@ -0,0 +1,106 @@ +extends Node2D + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +var pf_location = Vector2(-1, -1) +var stored = null +var tooltip_timer = -1.0 +var last_light_received = 0 +var last_light_timer = 0.0 +var last_light_timer_max = 2.0 +var arrow_sprite_life_max = 2.0 +var arrow_sprite_life = 0.0 +var arrow_sprite = preload("res://assets/small arrow.png") + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +func _process(delta): + if tooltip_timer != -1.0: + if tooltip_timer >= 0.0: + tooltip_timer -= delta + if tooltip_timer <= 0.0 and not get_node("Tooltip").is_visible(): + get_node("Tooltip").set_visible(true) + if self.arrow_sprite_life > 0.0: + self.arrow_sprite_life -= delta + if self.arrow_sprite_life <= 0.0: + get_node("Arrow").queue_free() + if self.last_light_timer >= 0.0: + self.last_light_timer -= delta + if self.last_light_timer <= 0.0: + get_node("Light").set_visible(false) + if get_node("Sprite") != null: + get_node("Sprite").set_modulate(self.get_default_modulate()) + +func start_tooltip_timer(): + self.tooltip_timer = 0.5 + +func hide_tooltip(): + get_node("Tooltip").set_visible(false) + self.tooltip_timer = -1.0 + +func set_location(x: Vector2): + self.pf_location = x + self.update_tooltip("") + +func update_tooltip(tooltip): + if tooltip: + tooltip += "\n" + tooltip += "Location: " + str(pf_location.x) + "," + str(pf_location.y) + get_node("Tooltip").set_text(tooltip) + +func query_details(): + return "Location: " + str(pf_location.x) + "," + str(pf_location.y) + +func can_do_action(action): + if action == "query": + return [true, true, "", 0] + else: + return [false, false, "Action not applicable: " + action, 0] + +func do_action(action, args): + pass + +func get_height(): + if self.stored == null: + return 0; + return self.stored.height + +func display_arrow(direction: Vector2, height, width, size): + var s = Sprite.new() + s.set_texture(self.arrow_sprite) + s.set_name("Arrow") + self.arrow_sprite_life = self.arrow_sprite_life_max + var pos = Vector2( + (direction.x * height * 0.75) + (direction.y * width * 0.6), + (direction.y * size * 1.25) + ) + s.set_position(pos) + var angle = PI * float(-direction.x) * 0.5 + angle += PI * float(direction.y) * 0.33 + if direction.y != 0 and direction.x == 0: + angle += PI + s.rotate(angle) + add_child(s) + +func apply_light(value): + # print("[%s] Received light: %s" % [self, value]) + self.last_light_received = value + get_node("Light").set_text(str(self.last_light_received)) + get_node("Light").set_visible(true) + self.last_light_timer = self.last_light_timer_max + if get_node("Sprite") != null and value <= 0: + get_node("Sprite").set_modulate(Color(0, 0, 0, 0.50)) + +func get_neighbours(grid, include_storage = false): + var r = [] + var neighbours = grid.get_neighbours(self.pf_location.x, self.pf_location.y) + if include_storage: + return neighbours + +func get_default_modulate(): + return Color(1.0, 1.0, 1.0, 1.0) diff --git a/src/Hex.tscn b/src/Hex.tscn new file mode 100644 index 0000000..ec0a05e --- /dev/null +++ b/src/Hex.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://assets/hex.png" type="Texture" id=1] +[ext_resource path="res://src/Hex.gd" type="Script" id=2] + +[node name="Hex" type="Area2D"] +script = ExtResource( 2 ) + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="."] +polygon = PoolVector2Array( 34, -21, 0, -41, -37, -19, -37, 22, -1, 42, 34, 22 ) + +[node name="Border" type="Sprite" parent="."] +scale = Vector2( 1.5, 1.5 ) +texture = ExtResource( 1 ) + +[node name="Tooltip" type="RichTextLabel" parent="."] +visible = false +margin_left = -39.0 +margin_top = 5.0 +margin_right = 101.0 +margin_bottom = 51.0 +text = "Lorem Ipsum" +fit_content_height = true + +[node name="Light" type="RichTextLabel" parent="."] +visible = false +margin_left = -38.0 +margin_top = -21.0 +margin_right = 2.0 +margin_bottom = 19.0 +text = "0" +fit_content_height = true + +[node name="Growth" type="RichTextLabel" parent="."] +visible = false +margin_left = 29.0 +margin_top = -20.0 +margin_right = 69.0 +margin_bottom = 20.0 +mouse_filter = 2 +text = "0" +fit_content_height = true diff --git a/src/HexGrid.tscn b/src/HexGrid.tscn new file mode 100644 index 0000000..520f886 --- /dev/null +++ b/src/HexGrid.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://HexGrid.gd" type="Script" id=1] + +[node name="HexGrid" type="Node2D"] +script = ExtResource( 1 ) diff --git a/src/Menu.tscn b/src/Menu.tscn new file mode 100644 index 0000000..4dd29a6 --- /dev/null +++ b/src/Menu.tscn @@ -0,0 +1,83 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://Menu.gd" type="Script" id=1] +[ext_resource path="res://assets/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf" type="DynamicFontData" id=2] + +[sub_resource type="DynamicFont" id=1] +size = 40 +outline_size = 1 +font_data = ExtResource( 2 ) + +[node name="Menu" type="PopupPanel"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_right = -484.0 +margin_bottom = -354.0 +size_flags_horizontal = 0 +size_flags_vertical = 0 +script = ExtResource( 1 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +margin_left = 4.0 +margin_top = 4.0 +margin_right = 536.0 +margin_bottom = 242.0 + +[node name="Label" type="Label" parent="VBoxContainer"] +margin_right = 532.0 +margin_bottom = 48.0 +size_flags_horizontal = 3 +custom_colors/font_color = Color( 0.996078, 1, 0.258824, 1 ) +custom_colors/font_outline_modulate = Color( 1, 0, 0.972549, 1 ) +custom_fonts/font = SubResource( 1 ) +text = "Da 'Lil Patch" +align = 1 + +[node name="Score" type="RichTextLabel" parent="VBoxContainer"] +margin_top = 52.0 +margin_right = 532.0 +margin_bottom = 67.0 +bbcode_enabled = true +bbcode_text = "[center]Score: 0[/center]" +text = "Score: 0" +fit_content_height = true + +[node name="ScoreByYear" type="RichTextLabel" parent="VBoxContainer"] +margin_top = 71.0 +margin_right = 532.0 +margin_bottom = 86.0 +bbcode_enabled = true +fit_content_height = true + +[node name="Continue" type="Button" parent="VBoxContainer"] +margin_top = 90.0 +margin_right = 532.0 +margin_bottom = 124.0 +size_flags_vertical = 3 +text = "Continue" + +[node name="Restart" type="Button" parent="VBoxContainer"] +margin_top = 128.0 +margin_right = 532.0 +margin_bottom = 162.0 +size_flags_vertical = 3 +text = "Restart" + +[node name="Help" type="Button" parent="VBoxContainer"] +margin_top = 166.0 +margin_right = 532.0 +margin_bottom = 200.0 +size_flags_vertical = 3 +text = "Help" + +[node name="Quit" type="Button" parent="VBoxContainer"] +margin_top = 204.0 +margin_right = 532.0 +margin_bottom = 238.0 +size_flags_vertical = 3 +text = "Quit" + +[connection signal="pressed" from="VBoxContainer/Continue" to="." method="_on_Continue_pressed"] +[connection signal="pressed" from="VBoxContainer/Restart" to="." method="_on_Restart_pressed"] +[connection signal="pressed" from="VBoxContainer/Help" to="." method="_on_Help_pressed"] +[connection signal="pressed" from="VBoxContainer/Quit" to="." method="_on_Quit_pressed"] diff --git a/src/Plant.gd b/src/Plant.gd new file mode 100644 index 0000000..6fb0fcf --- /dev/null +++ b/src/Plant.gd @@ -0,0 +1,150 @@ +extends Node2D + + +const FadingText = preload("res://src/ui/FadingText.tscn") + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" +enum STAGE {SEED, SPROUT, GROWTH, FRUIT, RIPE} +const default_sprites = [ + preload("res://assets/seeds.png"), + preload("res://assets/sprouts.png"), + preload("res://assets/plant.png"), + preload("res://assets/plant.png"), + preload("res://assets/plant.png"), + preload("res://assets/plant.png") +] +var sprites = [] +var icon = preload("res://assets/hex.png") +var icon_tooltip = "Plaaaant me" +var description = "A plant" +# run time +var growth = 0 +var height = 0 + +# per-type stats +# each stat contributes to growth during each section of the day +# there are 4 sections to the day, and 4 growing periods +var light_range = [15, 85] # below x too shady, above y too sunny +var growth_mod_by_light = [2, 10, -1] # shady, ok, sunny + +var rockiness_range = [5, 50] +var growth_mod_by_rockiness = [-1, 10, -5] + +var nutrient_range = [10, 100] +var growth_mod_by_nutrition = [0, 10, 15] + +var soil_health_range = [25, 75] +var growth_mod_by_soil_health = [0, 5, 10] + +var base_score = 100 +var score_mod_by_growth = [0.0, 0.0, 0.0, 0.1, 1.2, 1.5] +var growth_thresholds = [100, 175, 250, 300, 400] # for each stage above +var heights = [0, 0, 1, 1, 1, 1] + +var plantable = true +var survives_winter = false +var season_rockiness_mod = 0 +var season_nutrient_mod = -10 +var season_health_mod = -5 +var harvest_nutrient_mod = 5 +var harvest_health_mod = 5 +var harvest_rockiness_mod = 5 + +# @TODO adjacency effects + +static func find_by_range_area(value, ranges, mods): + var v = 0 + for x in ranges: + if value > x: + v += 1 + continue + break + if v >= mods.size(): + v = mods.size()-1 + return mods[v] + +# Called when the node enters the scene tree for the first time. +func _ready(): + get_node("Sprite").set_texture(self.sprites[self.get_stage()]) + +func get_description(): + var s = "%s\n\n" % self.description + s += "Base score: %d\nScore mods by growth stage: %s\n\n" % [self.base_score, self.score_mod_by_growth] + s += "At the end of each season\n\tRockiness: %d\n\tSoil health: %d\n\tSoil nutrients: %d\n\n" %[self.season_rockiness_mod, self.season_health_mod, self.season_nutrient_mod] + s += "When harvested:\n\tRockiness: %d\n\tSoil health: %d\n\tSoil nutrients: %d\n" %[self.harvest_rockiness_mod, self.harvest_health_mod, self.harvest_nutrient_mod] + return s + +func _init(): + self.sprites.resize(self.default_sprites.size()) + for x in range(self.default_sprites.size()): + if self.sprites[x] == null: + self.sprites[x] = self.default_sprites[x] + +func query_details(): + var stage = self.get_stage() + var next = "N/A" + if stage < self.growth_thresholds.size(): + next = str(self.growth_thresholds[stage]) + var s = "Growth: %d\nHeight: %d\nNext stage at: %s\n\n" % [self.growth, self.height, next] + return s + +func get_stage(): + var stage = 0 + for x in self.growth_thresholds: + if self.growth >= x: + stage += 1 + else: + break + return stage + +func get_icon_tooltip(): + return self.icon_tooltip + +func apply_light(light, soil): + var growth_light = self.find_by_range_area(light, self.light_range, self.growth_mod_by_light) + var growth_rockiness = self.find_by_range_area(soil.rockiness, self.rockiness_range, self.growth_mod_by_rockiness) + var growth_health = self.find_by_range_area(soil.misc_health, self.soil_health_range, self.growth_mod_by_soil_health) + var growth_nutrients = self.find_by_range_area(soil.nutrients, self.nutrient_range, self.growth_mod_by_nutrition) + var growth = growth_light + growth_rockiness + growth_health + growth_nutrients + #print("Grew %d = %d + %d + %d + %d" %[growth, growth_light, growth_rockiness, growth_health, growth_nutrients]) + self.grow(growth) + +func grow(value): + var index = self.get_stage() + if index >= self.heights.size(): + index = self.heights.size() - 1 + self.growth += value + self.height = self.heights[index] + get_node("Height").set_text(str(self.height)) + get_node("Sprite").set_texture(self.sprites[index]) + var t = FadingText.instance() + t.set_position(Vector2(32, -24)) + t.move_towards = Vector2(50, -60) + t.set_text("%+d🌱🌱" % value) + t.set_modulate(Color(0.1, 0.85, 0.1)) + t.set_scale(Vector2(1.5, 1.5)) + add_child(t) + +func get_score(): + var mod = self.find_by_range_area(self.growth, self.growth_thresholds, self.score_mod_by_growth) + var score = int(round(float(self.base_score) * mod)) + return score + +func use_nutrients_and_run_plant_effects(soil, old_season, new_season, grid): + print("plant use nitrients ", self) + soil.update_stat("rockiness", self.season_rockiness_mod) + soil.update_stat("nutrients", self.season_nutrient_mod) + soil.update_stat("health", self.season_health_mod) + +func end_of_year(soil, grid): + soil.update_stat("nutrients", self.harvest_nutrient_mod) + soil.update_stat("health", self.harvest_health_mod) + if not self.survives_winter: + soil.update_stat("rockiness", self.harvest_rockiness_mod) + self.queue_free() + soil.stored = null +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/Plant.tscn b/src/Plant.tscn new file mode 100644 index 0000000..a9e7ee8 --- /dev/null +++ b/src/Plant.tscn @@ -0,0 +1,19 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/Plant.gd" type="Script" id=1] + +[node name="Plant" type="Node2D"] +script = ExtResource( 1 ) + +[node name="Sprite" type="Sprite" parent="."] +scale = Vector2( 1.5, 1.5 ) + +[node name="Height" type="RichTextLabel" parent="."] +margin_left = -4.0 +margin_top = 26.0 +margin_right = 36.0 +margin_bottom = 66.0 +hint_tooltip = "Height" +mouse_filter = 1 +text = "0" +fit_content_height = true diff --git a/src/Soil.gd b/src/Soil.gd new file mode 100644 index 0000000..48bc010 --- /dev/null +++ b/src/Soil.gd @@ -0,0 +1,160 @@ +extends "res://src/Hex.gd" + +const Plant = preload("res://src/Plant.tscn") + +signal soil_stat_changed(name, old, new) +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +var weed_rockiness_range = [20, 60] +var weed_probability_from_rockiness = [0.05, 0.1, 0.15] +var weed_health_range = [25, 50, 75] +var weed_probability_from_health = [0.2, 0.15, 0.1, 0.05] +var weed_nutrient_range = [33, 66] +var weed_probability_from_nutrient = [0.1, 0.2, 0.3] +var strong_weed_probability = 0.5 + +var rockiness = 0 +var nutrients = 50 +var misc_health = 50 # pH, moisture, aeration + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +static func find_by_range_area(value, ranges, mods): + var v = 0 + for x in ranges: + if value > x: + v += 1 + continue + break + if v >= mods.size(): + v = mods.size()-1 + return mods[v] + +func can_do_action(action): + if action == "plant": + return [true, self.stored == null, "", 0] + elif action == "cull": + return [true, self.stored != null, "You can only cull on soil tiles that have plants", 1] + elif action == "burn": + return [true, self.stored != null, "You can only burn soil tiles that have plants", 2] + elif action == "removerock": + return [true, self.rockiness >= 20, "You can only remove rocks on soil that have rocks >= 20", 3] + elif action == "fertilize": + return [true, true, "", 4] + return .can_do_action(action) + +func query_details(): + var details = "Rockiness: %d\nNutrients %d\nHealth %d\n\nPlant: %s\n" % [self.rockiness, self.nutrients, self.misc_health, str(self.stored)] + if self.stored != null and self.stored: + details += self.stored.query_details() + details += "Soil gains rockiness and loses nutrients and health over time based on which plants are sown.\n\n" + details += "If there are no plants, there's a chance that weeds grow.\n\n" + details += .query_details() + return details + +func do_action(action, args): + if action == "cull": + assert(self.stored != null) + var plant = self.stored + self.stored = null + var score = plant.get_score() + self.update_stat("rockiness", plant.harvest_rockiness_mod) + # @TODO do plant removal effects + plant.queue_free() + return score + elif action == "plant": + self.stored = args["plant"] + add_child(self.stored) + self.stored.add_to_group("runtime") + elif action == "burn": + assert(self.stored != null) + var plant = self.stored + self.stored = null + self.update_stat("nutrients", 15) + self.update_stat("health", -5) + plant.queue_free() + elif action == "removerock": + self.update_stat("rockiness", -self.rockiness) + elif action == "fertilize": + self.update_stat("nutrients", 50) + self.update_stat("health", 50) + +func apply_light(value): + .apply_light(value) + if self.stored != null: + self.stored.apply_light(value, self) +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + +func nourish_plants_and_run_plant_effects(old_season, new_season, grid): + print("soil nourish") + if self.stored: + self.stored.use_nutrients_and_run_plant_effects(self, old_season, new_season, grid) + else: + # Increase the health of the soil slightly from not being used + self.update_stat("misc_health", 2) + # Chance of generating a weed + var p_weed = 0.0 + p_weed += find_by_range_area(self.rockiness, self.weed_rockiness_range, self.weed_probability_from_rockiness) + p_weed += find_by_range_area(self.nutrients, self.weed_nutrient_range, self.weed_probability_from_nutrient) + p_weed += find_by_range_area(self.misc_health, self.weed_health_range, self.weed_probability_from_health) + if randf() <= p_weed: + var weed_name = "weed" + if randf() > self.strong_weed_probability: + weed_name = "strong_weed" + var game = get_tree().current_scene + self.do_action("plant", {"plant": game.plant_types[weed_name].duplicate()}) + + +func end_of_year(grid): + if self.stored: + self.stored.end_of_year(self, grid) + # + +func update_stat(name, value): + var old + var new + if name == "rockiness": + old = self.rockiness + new = self.rockiness + value + new = min(100, max(0, new)) + self.rockiness = new + var rock_sprite = null + if self.rockiness >= 75: + rock_sprite = load("res://assets/rocky 3.png") + elif self.rockiness >= 50: + rock_sprite = load("res://assets/rocky 2.png") + elif self.rockiness >= 20: + rock_sprite = load("res://assets/rocky 1.png") + if rock_sprite != null: + get_node("Rocks").set_texture(rock_sprite) + get_node("Rocks").set_visible(rock_sprite != null) + elif name == "health": + old = self.misc_health + new = self.misc_health + value + new = min(100, max(0, new)) + self.misc_health = new + elif name == "nutrients": + old = self.nutrients + new = self.nutrients + value + new = min(100, max(0, new)) + self.nutrients = new + else: + print("Unknown stat: %s" % name) + return + if old != new: + emit_signal("soil_stat_changed", name, old, new) + +func get_default_modulate(): + if self.misc_health >= 75: + return Color("#b27308") + elif self.misc_health >= 50: + return Color("#da8d09") + elif self.misc_health >= 25: + return Color("#c49911") + return Color("#faaf2f") diff --git a/src/Soil.tscn b/src/Soil.tscn new file mode 100644 index 0000000..5863bc5 --- /dev/null +++ b/src/Soil.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://src/Soil.gd" type="Script" id=1] +[ext_resource path="res://src/Hex.tscn" type="PackedScene" id=2] +[ext_resource path="res://assets/soil.png" type="Texture" id=3] + +[node name="Soil" groups=["soil"] instance=ExtResource( 2 )] +script = ExtResource( 1 ) + +[node name="Rocks" type="Sprite" parent="." index="2"] + +[node name="Sprite" type="Sprite" parent="." index="3"] +modulate = Color( 0.909804, 0.588235, 0.0352941, 1 ) +scale = Vector2( 1.5, 1.5 ) +z_index = -1 +texture = ExtResource( 3 ) diff --git a/src/Spot.gd b/src/Spot.gd new file mode 100644 index 0000000..df7ceb6 --- /dev/null +++ b/src/Spot.gd @@ -0,0 +1,22 @@ +extends "res://src/Hex.gd" + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + #get_node("Border").set_modulate(Color(1.0, 0.0, 0.0)) + pass # Replace with function body. + +func query_details(): + var details = "Structure spots are tiles in which various objects may be built.\n\n" + details += "Object: %s\n\n" % self.stored + details += .query_details() + return details + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/Spot.tscn b/src/Spot.tscn new file mode 100644 index 0000000..01ea26d --- /dev/null +++ b/src/Spot.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/Hex.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/Spot.gd" type="Script" id=2] + +[node name="Spot" groups=["spot"] instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/src/Sun.gd b/src/Sun.gd new file mode 100644 index 0000000..a7e78a1 --- /dev/null +++ b/src/Sun.gd @@ -0,0 +1,25 @@ +extends Node2D + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +var goal = 0.0 +var goals = [0.0, 0.35, 0.75, 1.0] +var speed = 0.3 +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +func _on_day_time_changed(old, new): + #print("Sun time: ", new) + self.goal = goals[new] + +func _process(delta): + if abs(self.goal - get_node("Path2D/PathFollow2D").get_unit_offset()) > 0.1: + var offset = get_node("Path2D/PathFollow2D").get_unit_offset() + offset += self.speed * delta + if offset >= self.goal: + offset = self.goal + get_node("Path2D/PathFollow2D").set_unit_offset(offset) diff --git a/src/Sun.tscn b/src/Sun.tscn new file mode 100644 index 0000000..0d27350 --- /dev/null +++ b/src/Sun.tscn @@ -0,0 +1,26 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://assets/sun.png" type="Texture" id=1] +[ext_resource path="res://src/Sun.gd" type="Script" id=2] + +[sub_resource type="Curve2D" id=1] +_data = { +"points": PoolVector2Array( -0.840896, -10.0908, 0.840896, 10.0908, -3, -11, 0, 0, 0, 0, 9, -74, 0, 0, 0, 0, 27, -132, 0, 0, 0, 0, 45, -164, 0, 0, 0, 0, 71, -199, 0, 0, 0, 0, 100, -222, 0, 0, 0, 0, 136, -236, 0, 0, 0, 0, 172, -247, 0, 0, 0, 0, 208, -257, 0, 0, 0, 0, 243, -265, 0, 0, 0, 0, 272, -266, 0, 0, 0, 0, 317, -265, 0, 0, 0, 0, 355, -259, 0, 0, 0, 0, 389, -251, 0, 0, 0, 0, 429, -238, 0, 0, 0, 0, 455, -224, 0, 0, 0, 0, 478, -206, 0, 0, 0, 0, 506, -184, 0, 0, 0, 0, 543, -146, 0, 0, 0, 0, 559, -119, 0, 0, 0, 0, 568, -97, 0, 0, 0, 0, 579, -63, 0, 0, 0, 0, 584, -17, 0, 0, 0, 0, 589, 78 ) +} + +[node name="Sun" type="Node2D"] +script = ExtResource( 2 ) + +[node name="Path2D" type="Path2D" parent="."] +curve = SubResource( 1 ) + +[node name="PathFollow2D" type="PathFollow2D" parent="Path2D"] +position = Vector2( -3, -11 ) +rotation = -1.3641 +rotate = false +lookahead = 128.411 + +[node name="Sprite" type="Sprite" parent="Path2D/PathFollow2D"] +rotation = -0.244346 +scale = Vector2( 2, 2 ) +texture = ExtResource( 1 ) diff --git a/src/plants/Apple.gd b/src/plants/Apple.gd new file mode 100644 index 0000000..b47a575 --- /dev/null +++ b/src/plants/Apple.gd @@ -0,0 +1,35 @@ +extends "res://src/Plant.gd" + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +func _init(): + self.icon = preload("res://assets/apple icon.png") + self.icon_tooltip = "A slow growing tree that survives over winter" + self.description = "Delicious, but you have to plan ahead" + self.light_range = [25, 75] + self.season_nutrient_mod = -1 + self.season_health_mod = -1 + self.harvest_nutrient_mod = 0 + self.harvest_health_mod = 0 + self.base_score = 300 + self.sprites[2] = preload("res://assets/apple plant.png") + self.sprites[3] = preload("res://assets/apple plant.png") + self.sprites[4] = preload("res://assets/apple tree.png") + self.sprites[5] = preload("res://assets/apple fruit.png") + self.heights = [0, 1, 2, 3, 4, 5] + self.score_mod_by_growth = [0.0, 0.0, 0.0, 0.0, 2, 3] + self.growth_thresholds = [200, 400, 600, 800, 1000] + self.survives_winter = true + self.harvest_rockiness_mod = 100 + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/plants/Apple.tscn b/src/plants/Apple.tscn new file mode 100644 index 0000000..bd9b7c8 --- /dev/null +++ b/src/plants/Apple.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/Plant.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/plants/Apple.gd" type="Script" id=2] + +[node name="Apple" instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/src/plants/Bean.gd b/src/plants/Bean.gd new file mode 100644 index 0000000..b59b594 --- /dev/null +++ b/src/plants/Bean.gd @@ -0,0 +1,30 @@ +extends "res://src/Plant.gd" + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +func _init(): + self.icon = preload("res://assets/bean icon.png") + self.icon_tooltip = "Beans help replenish nutrients of neighbouring tiles" + self.description = "A staple that is good at replenishing soil nutrients" + self.light_range = [15, 75] + self.base_score = 75 + self.season_nutrient_mod = -5 + self.harvest_nutrient_mod = 50 + self.harvest_health_mod = 0 + self.sprites[3] = preload("res://assets/bean plant.png") + self.sprites[4] = preload("res://assets/bean plant.png") + self.sprites[5] = preload("res://assets/bean plant.png") + self.heights = [0, 1, 2, 2, 2, 3] + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/plants/Bean.tscn b/src/plants/Bean.tscn new file mode 100644 index 0000000..2fe1d62 --- /dev/null +++ b/src/plants/Bean.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/Plant.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/plants/Bean.gd" type="Script" id=2] + +[node name="Bean" instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/src/plants/Clover.gd b/src/plants/Clover.gd new file mode 100644 index 0000000..3d7e114 --- /dev/null +++ b/src/plants/Clover.gd @@ -0,0 +1,31 @@ +extends "res://src/Plant.gd" + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +func _init(): + self.icon = preload("res://assets/clover icon.png") + self.icon_tooltip = "Clover helps replenish the health of the soil on the tile" + self.description = "Good for the soil, and bees like it too" + self.light_range = [10, 90] + self.season_nutrient_mod = -1 + self.season_health_mod = 5 + self.harvest_health_mod = 10 + self.harvest_rockiness_mod = 0 + self.base_score = 0 + self.sprites[2] = preload("res://assets/clover plant.png") + self.sprites[3] = preload("res://assets/clover plant.png") + self.sprites[4] = preload("res://assets/clover flower.png") + self.sprites[5] = preload("res://assets/clover flower.png") + self.heights = [0, 1, 1, 1, 1, 1] + self.growth_thresholds = [25, 50, 75, 100, 110, 125] +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/plants/Clover.tscn b/src/plants/Clover.tscn new file mode 100644 index 0000000..8d2fd6f --- /dev/null +++ b/src/plants/Clover.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/Plant.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/plants/Clover.gd" type="Script" id=2] + +[node name="Clover" instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/src/plants/Corn.gd b/src/plants/Corn.gd new file mode 100644 index 0000000..da85736 --- /dev/null +++ b/src/plants/Corn.gd @@ -0,0 +1,23 @@ +extends "res://src/Plant.gd" + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" +func _init(): + self.icon = preload("res://assets/icon corn.png") + self.icon_tooltip = "Corn needs lots of nutrients and light, but can be very productive" + self.description = "A staple crop that grows well in sun" + self.light_range = [25, 98] + self.sprites[3] = preload("res://assets/corn fruit.png") + self.sprites[4] = preload("res://assets/corn ripe.png") + self.sprites[5] = preload("res://assets/corn ripe.png") + self.heights = [0, 1, 2, 3, 3, 3] + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/plants/Corn.tscn b/src/plants/Corn.tscn new file mode 100644 index 0000000..eff8723 --- /dev/null +++ b/src/plants/Corn.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/Plant.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/plants/Corn.gd" type="Script" id=2] + +[node name="Corn" instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/src/plants/StrongWeed.gd b/src/plants/StrongWeed.gd new file mode 100644 index 0000000..c27bcac --- /dev/null +++ b/src/plants/StrongWeed.gd @@ -0,0 +1,31 @@ +extends "res://src/Plant.gd" + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +# grows tall and saps the nutrients from adjoining soil +func _init(): + self.light_range = [5, 95] + self.base_score = 0 + self.harvest_rockiness_mod = 25 + self.season_nutrient_mod = -10 + self.growth_thresholds = [75, 100, 140, 175, 20000] + self.heights = [0, 1, 2, 3, 3, 3] + self.survives_winter = true + self.plantable = false + self.icon = preload("res://assets/strong weed icon.png") + self.sprites[3] = preload("res://assets/strong weed plant.png") + self.sprites[4] = preload("res://assets/strong weed plant.png") + self.sprites[5] = preload("res://assets/strong weed plant.png") + self.description = "Ouch, prickly!" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/plants/StrongWeed.tscn b/src/plants/StrongWeed.tscn new file mode 100644 index 0000000..bc62ad4 --- /dev/null +++ b/src/plants/StrongWeed.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/Plant.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/plants/StrongWeed.gd" type="Script" id=2] + +[node name="StrongWeed" instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/src/plants/Weed.gd b/src/plants/Weed.gd new file mode 100644 index 0000000..c60850e --- /dev/null +++ b/src/plants/Weed.gd @@ -0,0 +1,33 @@ +extends "res://src/Plant.gd" + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +# Grows fast, but short and it's tough roots drag rocks up when removed + +func _init(): + self.light_range = [20, 80] + self.base_score = 0 + self.harvest_rockiness_mod = 15 + self.season_nutrient_mod = -15 + self.growth_thresholds = [50, 75, 100, 125, 150] + self.heights = [0, 1, 1, 1, 2, 2] + self.plantable = false + self.icon = preload("res://assets/weed icon.png") + self.sprites[3] = preload("res://assets/weed plant.png") + self.sprites[4] = preload("res://assets/weed plant.png") + self.sprites[5] = preload("res://assets/weed plant.png") + self.description = "It noms nutrients and its roots pull up lots of rocks" + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +func use_nutrients_and_run_plant_effects(soil, old_season, new_season, grid): + # For each soil neighbour, use it's nutrients + .use_nutrients_and_run_plant_effects(soil, old_season, new_season, grid) +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/plants/Weed.tscn b/src/plants/Weed.tscn new file mode 100644 index 0000000..28b5e46 --- /dev/null +++ b/src/plants/Weed.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/plants/Weed.gd" type="Script" id=1] +[ext_resource path="res://src/Plant.tscn" type="PackedScene" id=2] + +[node name="Weed" instance=ExtResource( 2 )] +script = ExtResource( 1 ) diff --git a/src/plants/test.tscn b/src/plants/test.tscn new file mode 100644 index 0000000..b2910f6 --- /dev/null +++ b/src/plants/test.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://test.gd" type="Script" id=1] + +[node name="Area2D" type="Area2D"] +position = Vector2( -4, -2 ) +script = ExtResource( 1 ) + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="."] +position = Vector2( 14, 14 ) +polygon = PoolVector2Array( 9, -10, -8, -10, -9, 2, 0, 0, 0, 0, 0, 0, 0, 0 ) + +[connection signal="mouse_entered" from="." to="." method="_on_Area2D_mouse_entered"] diff --git a/src/ui/ActionMenu.gd b/src/ui/ActionMenu.gd new file mode 100644 index 0000000..b501675 --- /dev/null +++ b/src/ui/ActionMenu.gd @@ -0,0 +1,55 @@ +extends VBoxContainer + +const FadingText = preload("res://src/ui/FadingText.tscn") + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" +signal action_changed(new_value) + +# Called when the node enters the scene tree for the first time. +func _ready(): + for c in get_node("Grid").get_children(): + c.connect("toggled", self, "_on_ActionButton_toggled", [c.get_name().to_lower()]) + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + +func _on_ActionButton_toggled(pressed, action_name): + var another_pressed = false + for child in get_node("Grid").get_children(): + if child.get_name().to_lower() != action_name: + if child.is_pressed(): + another_pressed = true + child.set_pressed(false) + break; + if not another_pressed and not pressed: + for child in get_node("Grid").get_children(): + if child.get_name().to_lower() == action_name: + child.set_pressed(true) + return + if pressed: + emit_signal("action_changed", action_name) + +func _on_PassTime_pressed(): + get_node("PassTime").set_disabled(true) + for c in get_node("Grid").get_children(): + c.set_disabled(true) + emit_signal("action_changed", "pass_time") + + +func unlock(): + get_node("PassTime").set_disabled(false) + for c in get_node("Grid").get_children(): + c.set_disabled(false) + +func _on_action_points_changed(old, new): + get_node("ActionPoints").set_text("Action Points: %d" % new) + if new > old: + var f = FadingText.instance() + f.set_text("%+d AP" % (new - old)) + f.set_modulate(Color(0.0, 0.9, 0.1)) + add_child(f) diff --git a/src/ui/ActionMenu.tscn b/src/ui/ActionMenu.tscn new file mode 100644 index 0000000..c5d6f7d --- /dev/null +++ b/src/ui/ActionMenu.tscn @@ -0,0 +1,102 @@ +[gd_scene load_steps=8 format=2] + +[ext_resource path="res://assets/icon plant.png" type="Texture" id=1] +[ext_resource path="res://assets/icon cull.png" type="Texture" id=2] +[ext_resource path="res://src/ui/ActionMenu.gd" type="Script" id=3] +[ext_resource path="res://assets/icon query.png" type="Texture" id=4] +[ext_resource path="res://assets/icon remove rock.png" type="Texture" id=5] +[ext_resource path="res://assets/icon burn.png" type="Texture" id=6] +[ext_resource path="res://assets/icon fertilize.png" type="Texture" id=7] + +[node name="ActionMenu" type="VBoxContainer"] +margin_top = 24.0 +margin_right = 160.0 +margin_bottom = 87.0 +script = ExtResource( 3 ) + +[node name="ActionPoints" type="RichTextLabel" parent="."] +margin_right = 160.0 +margin_bottom = 15.0 +text = "Action Points: 3" +fit_content_height = true + +[node name="Grid" type="GridContainer" parent="."] +margin_top = 19.0 +margin_right = 160.0 +margin_bottom = 237.0 +columns = 2 + +[node name="Plant" type="Button" parent="Grid"] +margin_right = 76.0 +margin_bottom = 70.0 +hint_tooltip = "Plant (a) +Cost: 0 AP +Select a plant from the plant menu on the left, and click a soil tile to plant seeds there." +toggle_mode = true +shortcut_in_tooltip = false +pressed = true +icon = ExtResource( 1 ) +icon_align = 1 + +[node name="Query" type="Button" parent="Grid"] +margin_left = 80.0 +margin_right = 156.0 +margin_bottom = 70.0 +hint_tooltip = "Query (s) +Click on a tile to show more detail information" +toggle_mode = true +icon = ExtResource( 4 ) + +[node name="Cull" type="Button" parent="Grid"] +margin_top = 74.0 +margin_right = 76.0 +margin_bottom = 144.0 +hint_tooltip = "Cull / Harvest (d) +Cost: 1 AP +Select a tile to remove any of the plants on it." +toggle_mode = true +icon = ExtResource( 2 ) +icon_align = 1 + +[node name="Burn" type="Button" parent="Grid"] +margin_left = 80.0 +margin_top = 74.0 +margin_right = 156.0 +margin_bottom = 144.0 +hint_tooltip = "Burn (f) +Cost: 2 AP +Select a tile to remove any of the plants on it with fire. Doing so does not increase rockiness, and adds nutrients but reduces soil health." +toggle_mode = true +icon = ExtResource( 6 ) +icon_align = 1 + +[node name="RemoveRock" type="Button" parent="Grid"] +margin_top = 148.0 +margin_right = 76.0 +margin_bottom = 218.0 +hint_tooltip = "Remove Rock (g) +Cost: 3 AP +Select a tile to a reduce it's rockiness to 0" +toggle_mode = true +icon = ExtResource( 5 ) +icon_align = 1 + +[node name="Fertilize" type="Button" parent="Grid"] +margin_left = 80.0 +margin_top = 148.0 +margin_right = 156.0 +margin_bottom = 218.0 +hint_tooltip = "Fertilize (h) +Cost: 4 AP +Greatly increase the nutirents and health of soil" +toggle_mode = true +icon = ExtResource( 7 ) +icon_align = 1 + +[node name="PassTime" type="Button" parent="."] +margin_top = 241.0 +margin_right = 160.0 +margin_bottom = 261.0 +text = "Let time pass" + +[connection signal="pressed" from="PassTime" to="." method="_on_PassTime_pressed"] diff --git a/src/ui/FadingText.gd b/src/ui/FadingText.gd new file mode 100644 index 0000000..34d61b9 --- /dev/null +++ b/src/ui/FadingText.gd @@ -0,0 +1,44 @@ +extends RichTextLabel + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +var life_max = 1.5 +var life_cur = life_max +var autostart = true +var started = false +var move_towards = false +var move_speed = 10 + +func get_text_size(): + var f = self.get_theme_default_font() + return f.get_string_size(self.get_text()) + +# Called when the node enters the scene tree for the first time. +func _ready(): + if self.autostart: + self.started = true + print(self.get_position()) + +func _process(delta): + if not started: + return + self.life_cur -= delta + if self.life_cur <= 0.0: + self.set_visible(false) + self.started = false + self.queue_free() + else: + var m = self.get_modulate() + var a = self.life_cur / self.life_max + m = Color(m.r, m.g, m.b, a) + self.set_modulate(m) + if self.move_towards is Vector2: + var new_pos = self.get_position().move_toward(self.move_towards, delta * self.move_speed) + self.set_position(new_pos) + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/ui/FadingText.tscn b/src/ui/FadingText.tscn new file mode 100644 index 0000000..71a6919 --- /dev/null +++ b/src/ui/FadingText.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/ui/FadingText.gd" type="Script" id=1] +[ext_resource path="res://src/ui/ThemeWithFontOutline.tres" type="Theme" id=2] + +[node name="FadingText" type="RichTextLabel"] +margin_bottom = 75.0 +grow_horizontal = 2 +grow_vertical = 2 +rect_min_size = Vector2( 100, 100 ) +rect_clip_content = false +mouse_filter = 2 +size_flags_horizontal = 3 +theme = ExtResource( 2 ) +bbcode_enabled = true +fit_content_height = true +scroll_active = false +script = ExtResource( 1 ) diff --git a/src/ui/FontOutline.tres b/src/ui/FontOutline.tres new file mode 100644 index 0000000..88c0b97 --- /dev/null +++ b/src/ui/FontOutline.tres @@ -0,0 +1,9 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://assets/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf" type="DynamicFontData" id=1] + +[resource] +size = 18 +outline_size = 1 +outline_color = Color( 0, 0, 0, 1 ) +font_data = ExtResource( 1 ) diff --git a/src/ui/PlantMenu.gd b/src/ui/PlantMenu.gd new file mode 100644 index 0000000..84e17ab --- /dev/null +++ b/src/ui/PlantMenu.gd @@ -0,0 +1,63 @@ +extends VBoxContainer + +signal plant_type_changed(name) +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +func set_plants(plant_types): + var i = 1 + for x in plant_types: + if not plant_types[x].plantable and false: + continue + var button = Button.new() + #button.set_normal_texture(plant_types[x].icon) + button.set_button_icon(plant_types[x].icon) + button.set_toggle_mode(true) + if i <= 10: + var short = ShortCut.new() + var ip = InputEventKey.new() + ip.set_scancode(KEY_0 + (i % 10)) + short.set_shortcut(ip) + button.set_shortcut(short) + button.connect("toggled", self, "_on_plant_icon_toggled", [button, x]) + get_node("Plants").add_child(button) + button.set_tooltip(plant_types[x].get_icon_tooltip()) + # Drag and drop + if i == 1: + self._on_plant_icon_toggled(true, button, x) + i += 1 + +func _on_plant_icon_toggled(pressed, button, plant_type_name): + var another_pressed = false + for child in get_node("Plants").get_children(): + if child != button: + if child.is_pressed(): + another_pressed = true + break; + if not another_pressed and not pressed: + button.set_pressed(true) + return + if pressed: + for child in get_node("Plants").get_children(): + if child == button: + continue + child.set_pressed(false) + else: + get_node("Details").set_bbcode("") + if (pressed): + var game = get_tree().current_scene + if game.plant_types[plant_type_name] != null: + get_node("Details").set_bbcode("%s\n\n%s" %[plant_type_name.capitalize(), game.plant_types[plant_type_name].get_description()]) + emit_signal("plant_type_changed", plant_type_name) + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + diff --git a/src/ui/PlantMenu.tscn b/src/ui/PlantMenu.tscn new file mode 100644 index 0000000..568ab1a --- /dev/null +++ b/src/ui/PlantMenu.tscn @@ -0,0 +1,34 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://src/ui/PlantMenu.gd" type="Script" id=1] + +[node name="VBoxContainer" type="VBoxContainer"] +margin_bottom = 23.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource( 1 ) + +[node name="RichTextLabel" type="RichTextLabel" parent="."] +margin_right = 160.0 +margin_bottom = 15.0 +bbcode_enabled = true +bbcode_text = "[center]Plants[/center]" +text = "Plants" +fit_content_height = true + +[node name="Plants" type="GridContainer" parent="."] +margin_top = 19.0 +margin_right = 160.0 +margin_bottom = 19.0 +columns = 2 + +[node name="Details" type="RichTextLabel" parent="."] +margin_top = 23.0 +margin_right = 160.0 +margin_bottom = 323.0 +rect_min_size = Vector2( 160, 300 ) +size_flags_horizontal = 3 +size_flags_vertical = 3 +bbcode_enabled = true +bbcode_text = "Lorem Ipsum" +text = "Lorem Ipsum" diff --git a/src/ui/ThemeWithFontOutline.tres b/src/ui/ThemeWithFontOutline.tres new file mode 100644 index 0000000..af48b2b --- /dev/null +++ b/src/ui/ThemeWithFontOutline.tres @@ -0,0 +1,6 @@ +[gd_resource type="Theme" load_steps=2 format=2] + +[ext_resource path="res://src/ui/FontOutline.tres" type="DynamicFont" id=1] + +[resource] +default_font = ExtResource( 1 ) diff --git a/test.gd b/test.gd new file mode 100644 index 0000000..d11446b --- /dev/null +++ b/test.gd @@ -0,0 +1,20 @@ +extends Area2D + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + + +func _on_Area2D_mouse_entered(): + print("IN!")