diff --git a/Mods/Core/Furniture/Furniture.json b/Mods/Core/Furniture/Furniture.json index a827c26f..f6fdf57e 100644 --- a/Mods/Core/Furniture/Furniture.json +++ b/Mods/Core/Furniture/Furniture.json @@ -68,6 +68,11 @@ "weight": 1 }, { + "Function": { + "container_group": "tree_forage", + "container_regeneration_time": 10, + "is_container": true + }, "categories": [ "Nature" ], @@ -91,6 +96,11 @@ "weight": 1 }, { + "Function": { + "container_group": "tree_forage", + "container_regeneration_time": 10, + "is_container": true + }, "categories": [ "Nature" ], @@ -114,6 +124,11 @@ "weight": 1 }, { + "Function": { + "container_group": "tree_forage", + "container_regeneration_time": 10, + "is_container": true + }, "categories": [ "Nature" ], diff --git a/Mods/Core/Itemgroups/Itemgroups.json b/Mods/Core/Itemgroups/Itemgroups.json index 3a5bb910..d2b7d7d7 100644 --- a/Mods/Core/Itemgroups/Itemgroups.json +++ b/Mods/Core/Itemgroups/Itemgroups.json @@ -60,20 +60,6 @@ ], "mode": "Collection", "name": "Kitchen cupboard", - "references": { - "core": { - "furniture": [ - "countertop_wood" - ], - "maps": [ - "store_groceries", - "office_building_00" - ], - "mobs": [ - "scrapwalker" - ] - } - }, "sprite": "canned_food_32.png", "use_sprite": false }, @@ -108,13 +94,6 @@ ], "mode": "Collection", "name": "Mob loot", - "references": { - "core": { - "mobs": [ - "rust_sentinel" - ] - } - }, "sprite": "machete_32.png", "use_sprite": false }, @@ -203,20 +182,6 @@ ], "mode": "Collection", "name": "General cabinet contents", - "references": { - "core": { - "furniture": [ - "cabinet_wood_00", - "wall_shelf" - ], - "maps": [ - "store_groceries", - "generichouse_end", - "office_building_00", - "police_station" - ] - } - }, "sprite": "flashlight_32.png", "use_sprite": false }, @@ -245,46 +210,6 @@ ], "mode": "Collection", "name": "Medium destroyed furniture", - "references": { - "core": { - "furniture": [ - "countertop_wood", - "table_round_wood", - "chair_wood", - "bench_wood", - "bed_wood_single_00", - "cabinet_wood_00", - "bookcase_wood_00", - "door_wood", - "bench_garden", - "wardrobe", - "table_picknic", - "standing_mirror", - "chair_office", - "table_metal", - "lamp_standing", - "desk", - "bathtub", - "stove", - "sofa", - "cash_register", - "shopping_cart", - "display_case", - "vending_machine", - "toilet_00", - "damaged_shelves", - "destroyed_fence", - "railroad_midsection" - ], - "maps": [ - "abandoned_building", - "subway_station", - "city_square", - "skyscraper", - "neighborhood_school" - ] - } - }, "sprite": "wreck_wood_generic_32.png", "use_sprite": true }, @@ -307,13 +232,6 @@ ], "mode": "Collection", "name": "Medium disassembled furniture", - "references": { - "core": { - "furniture": [ - "countertop_wood" - ] - } - }, "sprite": "plank.png", "use_sprite": false }, @@ -420,17 +338,6 @@ ], "mode": "Collection", "name": "Refridgerator", - "references": { - "core": { - "furniture": [ - "refrigerator_00", - "display_case" - ], - "maps": [ - "store_groceries" - ] - } - }, "sprite": "bottle_empty_32.png", "use_sprite": false }, @@ -519,14 +426,6 @@ ], "mode": "Collection", "name": "General clothing", - "references": { - "core": { - "furniture": [ - "wardrobe", - "clothing_rack" - ] - } - }, "sprite": "jacket_32.png", "use_sprite": false }, @@ -573,13 +472,6 @@ ], "mode": "Collection", "name": "Electronics store (medium appliances)", - "references": { - "core": { - "maps": [ - "store_electronic_clothing" - ] - } - }, "sprite": "microwave_oven_32.png", "use_sprite": false }, @@ -632,14 +524,6 @@ ], "mode": "Collection", "name": "Electronics store (small products)", - "references": { - "core": { - "maps": [ - "store_electronic_clothing", - "radio_tower" - ] - } - }, "sprite": "screwdriver_32.png", "use_sprite": false }, @@ -722,13 +606,6 @@ ], "mode": "Collection", "name": "Electronics store (mixed products)", - "references": { - "core": { - "maps": [ - "store_electronic_clothing" - ] - } - }, "sprite": "electrical_components_32.png", "use_sprite": false }, @@ -763,21 +640,6 @@ ], "mode": "Collection", "name": "Vending machine (drinks)", - "references": { - "core": { - "furniture": [ - "vending_machine" - ], - "maps": [ - "store_electronic_clothing", - "store_groceries", - "subway_station", - "city_square", - "neighborhood_school", - "police_station" - ] - } - }, "sprite": "can_beer_32.png", "use_sprite": false }, @@ -800,18 +662,6 @@ ], "mode": "Collection", "name": "Vending machine (snacks)", - "references": { - "core": { - "maps": [ - "store_groceries", - "subway_station", - "city_square", - "office_building_00", - "neighborhood_school", - "police_station" - ] - } - }, "sprite": "chocolate_32.png", "use_sprite": false }, @@ -852,15 +702,6 @@ ], "mode": "Collection", "name": "Destroyed tree", - "references": { - "core": { - "furniture": [ - "Tree_00", - "PineTree_00", - "WillowTree_00" - ] - } - }, "sprite": "log_32.png", "use_sprite": false }, @@ -913,25 +754,6 @@ ], "mode": "Distribution", "name": "Generic field items", - "references": { - "core": { - "maps": [ - "field_grass_basic_00", - "field_grass_flowers_00", - "RockyHill_SE", - "RockyHill_SW", - "field_grass_hill_00", - "field_grass_hole_00", - "RockyHill_NE", - "RockyHill_NW", - "urbanroad_corner", - "urbanroad_cross", - "urbanroad_t", - "urbanroad", - "police_station" - ] - } - }, "sprite": "leaves_32.png", "use_sprite": false }, @@ -1038,17 +860,6 @@ ], "mode": "Distribution", "name": "Generic forest finds", - "references": { - "core": { - "maps": [ - "forest_basic_00", - "forest_road_straight", - "forest_road_corner", - "forest_road_t", - "forest_road_cross" - ] - } - }, "sprite": "branches_32.png", "use_sprite": false }, @@ -1123,13 +934,6 @@ ], "mode": "Collection", "name": "M4A1 Gun and ammo", - "references": { - "core": { - "maps": [ - "RockyHill_SW" - ] - } - }, "sprite": "rifle_64_32.png", "use_sprite": false }, @@ -1170,14 +974,6 @@ ], "mode": "Collection", "name": "Rock debris", - "references": { - "core": { - "maps": [ - "abandoned_building", - "subway_station" - ] - } - }, "sprite": "rock_large_32.png", "use_sprite": false }, @@ -1260,14 +1056,6 @@ ], "mode": "Collection", "name": "Urban debris", - "references": { - "core": { - "maps": [ - "abandoned_building", - "subway_station" - ] - } - }, "sprite": "rusted_metal_sheets_32.png", "use_sprite": false }, @@ -1326,18 +1114,6 @@ ], "mode": "Collection", "name": "Urban litter", - "references": { - "core": { - "maps": [ - "subway_station", - "parking_garage", - "city_square", - "office_building_00", - "skyscraper", - "police_station" - ] - } - }, "sprite": "bottle_empty_32.png", "use_sprite": false }, @@ -1372,14 +1148,6 @@ ], "mode": "Collection", "name": "Damaged electronics", - "references": { - "core": { - "maps": [ - "abandoned_building", - "radio_tower" - ] - } - }, "sprite": "transmitter_broken_32.png", "use_sprite": false }, @@ -1426,18 +1194,6 @@ ], "mode": "Collection", "name": "Electronic Mob loot", - "references": { - "core": { - "maps": [ - "radio_tower" - ], - "mobs": [ - "disruptor_drone", - "scavenger_skitter", - "venom_crawler" - ] - } - }, "sprite": "electrical_components_32.png", "use_sprite": false }, @@ -1478,14 +1234,6 @@ ], "mode": "Collection", "name": "First aid", - "references": { - "core": { - "maps": [ - "radio_tower", - "police_station" - ] - } - }, "sprite": "bandage_32.png", "use_sprite": false }, @@ -1574,13 +1322,6 @@ ], "mode": "Collection", "name": "Police station locker", - "references": { - "core": { - "maps": [ - "police_station" - ] - } - }, "sprite": "pistol_magazine.png", "use_sprite": false }, @@ -1771,21 +1512,47 @@ ], "mode": "Collection", "name": "Mob loot", - "references": { - "core": { - "mobs": [ - "basic_zombie_1", - "basic_zombie_2", - "bloated_zombie", - "rushing_zombie", - "charred_zombie", - "heavy_zombie", - "skeleton_zombie", - "limping_zombie" - ] - } - }, "sprite": "zombie_eye_32.png", "use_sprite": false + }, + { + "description": "The player is looking to the tree and see what can be foraged.", + "id": "tree_forage", + "items": [ + { + "id": "branch", + "max": 5, + "min": 2, + "probability": 80 + }, + { + "id": "leaf", + "max": 25, + "min": 10, + "probability": 95 + }, + { + "id": "long_stick", + "max": 3, + "min": 1, + "probability": 20 + }, + { + "id": "pine_branch", + "max": 1, + "min": 1, + "probability": 20 + }, + { + "id": "stick", + "max": 3, + "min": 1, + "probability": 60 + } + ], + "mode": "Collection", + "name": "Tree foraging", + "sprite": "plant_remnants_32.png", + "use_sprite": false } ] \ No newline at end of file diff --git a/Mods/Core/Itemgroups/references.json b/Mods/Core/Itemgroups/references.json index edcb9bf5..fcb9c3b6 100644 --- a/Mods/Core/Itemgroups/references.json +++ b/Mods/Core/Itemgroups/references.json @@ -108,6 +108,13 @@ "store_groceries" ] }, + "tree_forage": { + "furnitures": [ + "Tree_00", + "PineTree_00", + "WillowTree_00" + ] + }, "urban_litter": { "maps": [ "office_building_00", diff --git a/Mods/Core/Items/references.json b/Mods/Core/Items/references.json new file mode 100644 index 00000000..272e48b4 --- /dev/null +++ b/Mods/Core/Items/references.json @@ -0,0 +1,27 @@ +{ + "branch": { + "itemgroups": [ + "tree_forage" + ] + }, + "leaf": { + "itemgroups": [ + "tree_forage" + ] + }, + "long_stick": { + "itemgroups": [ + "tree_forage" + ] + }, + "pine_branch": { + "itemgroups": [ + "tree_forage" + ] + }, + "stick": { + "itemgroups": [ + "tree_forage" + ] + } +} \ No newline at end of file diff --git a/Scenes/ContentManager/Custom_Editors/FurnitureEditor.tscn b/Scenes/ContentManager/Custom_Editors/FurnitureEditor.tscn index 95b490d7..8800f0ec 100644 --- a/Scenes/ContentManager/Custom_Editors/FurnitureEditor.tscn +++ b/Scenes/ContentManager/Custom_Editors/FurnitureEditor.tscn @@ -7,7 +7,7 @@ [ext_resource type="PackedScene" uid="uid://dsax7il2yggw8" path="res://Scenes/ContentManager/Custom_Widgets/DropEnabledTextEdit.tscn" id="4_fbact"] [ext_resource type="Texture2D" uid="uid://lqavxdrjc078" path="res://Mods/Core/Furniture/wardrobe_80_40.png" id="5_61cds"] -[node name="FurnitureEditor" type="Control" node_paths=PackedStringArray("tab_container", "furnitureImageDisplay", "IDTextLabel", "NameTextEdit", "DescriptionTextEdit", "CategoriesList", "furnitureSelector", "imageNameStringLabel", "moveableCheckboxButton", "weightLabel", "weightSpinBox", "edgeSnappingOptionButton", "doorOptionButton", "containerCheckBox", "containerTextEdit", "destroyHboxContainer", "canDestroyCheckbox", "destructionTextEdit", "destructionImageDisplay", "destructionSpriteNameLabel", "disassemblyHboxContainer", "canDisassembleCheckbox", "disassemblyTextEdit", "disassemblyImageDisplay", "disassemblySpriteNameLabel", "support_shape_option_button", "width_scale_label", "depth_scale_label", "radius_scale_label", "width_scale_spin_box", "depth_scale_spin_box", "radius_scale_spin_box", "heigth_spin_box", "color_picker", "sprite_texture_rect", "transparent_check_box")] +[node name="FurnitureEditor" type="Control" node_paths=PackedStringArray("tab_container", "furnitureImageDisplay", "IDTextLabel", "NameTextEdit", "DescriptionTextEdit", "CategoriesList", "furnitureSelector", "imageNameStringLabel", "moveableCheckboxButton", "weightLabel", "weightSpinBox", "edgeSnappingOptionButton", "doorOptionButton", "containerCheckBox", "containerTextEdit", "regeneration_label", "regeneration_spin_box", "destroyHboxContainer", "canDestroyCheckbox", "destructionTextEdit", "destructionImageDisplay", "destructionSpriteNameLabel", "disassemblyHboxContainer", "canDisassembleCheckbox", "disassemblyTextEdit", "disassemblyImageDisplay", "disassemblySpriteNameLabel", "support_shape_option_button", "width_scale_label", "depth_scale_label", "radius_scale_label", "width_scale_spin_box", "depth_scale_spin_box", "radius_scale_spin_box", "heigth_spin_box", "color_picker", "sprite_texture_rect", "transparent_check_box")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -30,6 +30,8 @@ edgeSnappingOptionButton = NodePath("VBoxContainer/TabContainer/General/Snapping doorOptionButton = NodePath("VBoxContainer/TabContainer/General/FunctionControlContainer/DoorOptionButton") containerCheckBox = NodePath("VBoxContainer/TabContainer/General/FunctionControlContainer/ContainerCheckBox") containerTextEdit = NodePath("VBoxContainer/TabContainer/General/FunctionControlContainer/ContainerTextEdit") +regeneration_label = NodePath("VBoxContainer/TabContainer/General/FunctionControlContainer/RegenerationLabel") +regeneration_spin_box = NodePath("VBoxContainer/TabContainer/General/FunctionControlContainer/RegenerationSpinBox") destroyHboxContainer = NodePath("VBoxContainer/TabContainer/General/DestructionHBoxContainer") canDestroyCheckbox = NodePath("VBoxContainer/TabContainer/General/DestructionHBoxContainer/CanDestroyCheckBox") destructionTextEdit = NodePath("VBoxContainer/TabContainer/General/DestructionHBoxContainer/DestructionTextEdit") @@ -336,6 +338,21 @@ spawned. If container is not checked on, it will not act as a container." myplaceholdertext = "Drag an itemgroup from the left to here" +[node name="RegenerationLabel" type="Label" parent="VBoxContainer/TabContainer/General/FunctionControlContainer"] +layout_mode = 2 +text = "Regeneration time (in-game days)" + +[node name="RegenerationSpinBox" type="SpinBox" parent="VBoxContainer/TabContainer/General/FunctionControlContainer"] +layout_mode = 2 +tooltip_text = "The amount of in-game days that have to pass before the container regenerates the items from the itemgroup. +This is useful for plants that re-grow fruits or nuts. When regenerating, any existing items will disappear. If the +value is -1, the container does not regenerate. Only works for furniture that can't move. If you enter 1, the +container will reset when the player approaches it, no matter how many days have passed (but at least one)." +min_value = -1.0 +max_value = 10000.0 +step = 0.1 +value = -1.0 + [node name="Shape" type="GridContainer" parent="VBoxContainer/TabContainer"] visible = false layout_mode = 2 diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/FurnitureEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/FurnitureEditor.gd index 03a9c0f4..8c999bb7 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/FurnitureEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/FurnitureEditor.gd @@ -21,6 +21,8 @@ extends Control @export var doorOptionButton: OptionButton = null # Maks the furniture as a door @export var containerCheckBox: CheckBox = null # Marks the furniture as a container @export var containerTextEdit: HBoxContainer = null # Might contain the id of a loot group +@export var regeneration_label: Label = null +@export var regeneration_spin_box: SpinBox = null # The time in days before regeneration @export var destroyHboxContainer: HBoxContainer = null # contains destroy controls @export var canDestroyCheckbox: CheckBox = null # If the furniture can be destroyed or not @@ -134,9 +136,16 @@ func load_furniture_data(): containerTextEdit.set_text(itemgroup) else: containerTextEdit.mytextedit.clear() # Clear the text edit if no itemgroup is specified + + # Load regeneration time if applicable + if dfurniture.function.container_regeneration_time >= 0.0: + regeneration_spin_box.value = dfurniture.function.container_regeneration_time + else: + regeneration_spin_box.value = -1.0 # Default to -1.0 if no regeneration time is set else: containerCheckBox.button_pressed = false # Uncheck the container checkbox containerTextEdit.mytextedit.clear() # Clear the text edit as no container data is present + regeneration_spin_box.value = -1.0 # Reset regeneration spin box # Call the function to load the support shape data load_support_shape_option() @@ -256,9 +265,13 @@ func handle_container_option(): if containerCheckBox.is_pressed(): dfurniture.function.is_container = true dfurniture.function.container_group = containerTextEdit.get_text() + # Save the regeneration time + dfurniture.function.container_regeneration_time = regeneration_spin_box.value else: dfurniture.function.is_container = false dfurniture.function.container_group = "" + # Reset the regeneration time + dfurniture.function.container_regeneration_time = -1 func handle_destruction_option(): @@ -437,6 +450,12 @@ func _on_unmoveable_check_box_toggled(toggled_on): if toggled_on: # Hide the second tab in the tab container tab_container.set_tab_hidden(1, true) + # Hide the regeneration controls + regeneration_label.visible = false + regeneration_spin_box.visible = false else: # Show the second tab in the tab container tab_container.set_tab_hidden(1, false) + # Show the regeneration controls + regeneration_label.visible = true + regeneration_spin_box.visible = true diff --git a/Scripts/FurnitureStaticSpawner.gd b/Scripts/FurnitureStaticSpawner.gd index d5d51a28..ec00acdb 100644 --- a/Scripts/FurnitureStaticSpawner.gd +++ b/Scripts/FurnitureStaticSpawner.gd @@ -125,6 +125,7 @@ func _on_body_entered_item_detector(body_rid: RID) -> void: # because that's what the signal will send var furniturenode: Node3D = collider_to_furniture[body_rid] if furniturenode.is_container(): + furniturenode.regenerate() # Check if it needs to regenerate Helper.signal_broker.container_entered_proximity.emit(furniturenode) diff --git a/Scripts/FurnitureStaticSrv.gd b/Scripts/FurnitureStaticSrv.gd index 4bb9de19..57d8c72f 100644 --- a/Scripts/FurnitureStaticSrv.gd +++ b/Scripts/FurnitureStaticSrv.gd @@ -42,6 +42,11 @@ var current_health: float = 100.0 # Default health var is_animating_hit: bool = false # Flag to prevent multiple hit animations var original_material_color: Color = Color(1, 1, 1) # Store the original material color +# Store the container timer state +var last_time_checked: float = 0.0 # To track the last time the container was checked +var regeneration_interval: float = -1.0 # In-game days for regeneration interval + + signal about_to_be_destroyed(me: FurnitureStaticSrv) @@ -134,6 +139,7 @@ func _init(furniturepos: Vector3, newFurnitureJSON: Dictionary, world3d: World3D set_new_rotation(furniture_rotation) # Apply rotation after setting up the shape and visual instance check_door_functionality() # Check if this furniture is a door + check_regeneration_functionality() # Check if this furniture regenerates the items if rfurniture.support_shape.shape == "Box": create_box_shape() @@ -156,6 +162,7 @@ func add_container(): create_loot() else: deserialize_container_data() + set_random_inventory_item_texture() func is_container() -> bool: @@ -413,6 +420,25 @@ func check_door_functionality(): door_state = "Closed" # Default if not found in saved data +# Function to check if this furniture acts as a door +func check_regeneration_functionality(): + if not rfurniture.function: + return + if not rfurniture.function.container_regeneration_time: + return + regeneration_interval = rfurniture.function.container_regeneration_time + + if not is_new_furniture(): + # Ensure the door_state is properly set + if furnitureJSON.has("Function") and furnitureJSON["Function"].has("container"): + if furnitureJSON.Function.container.has("container_last_time_checked"): + last_time_checked = furnitureJSON.Function.container.container_last_time_checked + if furnitureJSON.Function.container.has("container_itemgroup"): + itemgroup = furnitureJSON.Function.container.container_itemgroup + else: + last_time_checked = 0.0 # Default if not found in saved data + + # Function to interact with the furniture (e.g., toggling door state) func interact(): if is_door: @@ -468,7 +494,7 @@ func apply_transform_to_instance(rotation_angle: int, position_offset: Vector3): -# Returns this furniture's data for saving, including door state if applicable +# Returns this furniture's data for saving, including door state, container state, and last checked time func get_data() -> Dictionary: var newfurniturejson = { "id": furnitureJSON.id, @@ -491,6 +517,10 @@ func get_data() -> Dictionary: # If there are no items in the inventory, keep an empty object. Else, # keep an object with the items key and the serialized items var containerobject = {} if containerdata.is_empty() else {"items": containerdata} + + # Add the last_time_checked to the container data + containerobject["container_last_time_checked"] = last_time_checked + containerobject["container_itemgroup"] = itemgroup newfurniturejson["Function"]["container"] = containerobject return newfurniturejson @@ -660,6 +690,7 @@ func get_sprite() -> Texture: func set_random_inventory_item_texture(): var items: Array[InventoryItem] = inventory.get_items() if items.size() == 0: + container_sprite_mesh.material = Gamedata.materials.container # set empty container return # Pick a random item from the inventory @@ -730,3 +761,44 @@ func show_hit_indicator(): # Function to show a miss indicator func show_miss_indicator(): show_indicator("Miss!", Color(1, 0, 0)) # Red for miss + + +# Regenerate the container if the interval is more then -1 +# This function is run by FurnitureStaticSpawner when the player enters proximity +func regenerate(): + # Check if the signal refers to this container and if it regenerates + if regeneration_interval <= -1: + return + + # Get the total days passed and calculate the days since last check + var total_days_passed: float = Helper.time_helper.get_days_since_start() + var days_passed: float = total_days_passed - last_time_checked + + # Check if enough days have passed to regenerate + if days_passed >= regeneration_interval: + # Update the last time checked + last_time_checked = total_days_passed + + # Regenerate items if the container has an itemgroup + _reset_inventory_and_regenerate_items() + + +# Add this function to handle inventory reset and item regeneration +func _reset_inventory_and_regenerate_items(): + if not itemgroup or itemgroup == "": + return # Do nothing if no itemgroup is present + + # Clear existing inventory + inventory.clear() + + # Populate inventory with items from the itemgroup + var ritemgroup: RItemgroup = Runtimedata.itemgroups.by_id(itemgroup) + if ritemgroup: + var group_mode: String = ritemgroup.mode # can be "Collection" or "Distribution" + if group_mode == "Collection": + _add_items_to_inventory_collection_mode(ritemgroup.items) + elif group_mode == "Distribution": + _add_items_to_inventory_distribution_mode(ritemgroup.items) + + # Update container visuals + set_random_inventory_item_texture() diff --git a/Scripts/Gamedata/DFurniture.gd b/Scripts/Gamedata/DFurniture.gd index 0c956f1e..82041c17 100644 --- a/Scripts/Gamedata/DFurniture.gd +++ b/Scripts/Gamedata/DFurniture.gd @@ -5,6 +5,44 @@ extends RefCounted # This script is intended to be used inside the GameData autoload singleton # This script handles the data for one furniture. You can access it through Gamedata.mods.by_id("Core").furnitures +# Example json: +# { +# "id": "countertop_wood", +# "name": "Wooden countertop", +# "description": "One of the central pieces of fruniture that make up a kitchen", +# "sprite": "countertop_100_52.png", +# "Function": { +# "container_group": "kitchen_cupboard", +# "is_container": true, +# "container_regeneration_time": -1 +# }, +# "categories": [ +# "Urban", +# "Kitchen", +# "Indoor" +# ], +# "destruction": { +# "group": "destroyed_furniture_medium", +# "sprite": "wreck_wood_generic_32.png" +# }, +# "disassembly": { +# "group": "disassembled_furniture_medium", +# "sprite": "wreck_wood_generic_32.png" +# }, +# "edgesnapping": "North", +# "moveable": false, +# "support_shape": { +# "color": "8d401bff", +# "depth_scale": 100, +# "height": 0.5, +# "shape": "Box", +# "transparent": false, +# "width_scale": 100 +# }, +# "weight": 1 +# } + + # This class represents a piece of furniture with its properties var id: String var name: String @@ -24,15 +62,17 @@ var parent: DFurnitures # Inner class to handle the Function property class Function: - var door: String # Can be "None", "Open" or "Closed" + var door: String # Can be "None", "Open" or "Closed" var is_container: bool var container_group: String + var container_regeneration_time: float # Time in days for container regeneration (-1.0 if it doesn't regenerate) # Constructor to initialize function properties from a dictionary func _init(data: Dictionary): door = data.get("door", "None") is_container = data.get("is_container", false) container_group = data.get("container_group", "") + container_regeneration_time = data.get("container_regeneration_time", -1.0) # Default to -1.0 # Get data function to return a dictionary with all properties func get_data() -> Dictionary: @@ -41,9 +81,11 @@ class Function: functiondata["is_container"] = is_container if not container_group == "": functiondata["container_group"] = container_group + if container_regeneration_time != -1: # Only include if not the default + functiondata["container_regeneration_time"] = container_regeneration_time if not door == "None": functiondata["door"] = door - return functiondata # Potentially return an empty dictionary + return functiondata # Potentially return an empty dictionary # Inner class to handle the Support Shape property diff --git a/Scripts/Helper/time_helper.gd b/Scripts/Helper/time_helper.gd index 6a780126..ad747c19 100644 --- a/Scripts/Helper/time_helper.gd +++ b/Scripts/Helper/time_helper.gd @@ -11,8 +11,8 @@ var _is_tracking_time: bool = false # Flag to track if we are actively counting var _last_tick_time: int = 0 # The last recorded tick time (in milliseconds) # Time constants -const daytime: int = 20 # Daytime in minutes -const nighttime: int = 15 # Nighttime in minutes +const daytime: int = 20 # Daytime in real-life minutes +const nighttime: int = 15 # Nighttime in real-life minutes const day_duration: int = daytime + nighttime # Total duration of a day in real-life minutes const in_game_day_minutes: int = 24 * 60 # In-game minutes in a full day (1440) @@ -92,14 +92,14 @@ func set_elapsed_time(new_time: float): _last_tick_time = Time.get_ticks_msec() -# Returns the time difference between a given past time and the current time. +# Returns the time difference between a given past time and the current time in seconds. func get_time_difference(past_time: float) -> float: return max(0.0, _elapsed_time - past_time) # Returns the number of in-game days since the start -func get_days_since_start() -> int: - return int(_elapsed_time / (day_duration * 60)) # Convert minutes to seconds +func get_days_since_start() -> float: + return float(_elapsed_time / (day_duration * 60)) # Convert minutes to seconds # The current time string, representing the time of day @@ -108,7 +108,7 @@ func get_current_time() -> String: var current_minutes_of_day = get_current_in_game_minutes() # Calculate hours and minutes - var hours: int = current_minutes_of_day / 60 + var hours: int = current_minutes_of_day / 60.0 var minutes: int = current_minutes_of_day % 60 return "%02d:%02d" % [hours, minutes] diff --git a/Scripts/Runtimedata/RFurniture.gd b/Scripts/Runtimedata/RFurniture.gd index c41398f3..059aa7ad 100644 --- a/Scripts/Runtimedata/RFurniture.gd +++ b/Scripts/Runtimedata/RFurniture.gd @@ -14,7 +14,8 @@ extends RefCounted # "Function": { # "door": "None", # "is_container": true, -# "container_group": "basic_loot" +# "container_group": "basic_loot", +# "container_regeneration_time": -1 # }, # "support_shape": { # "shape": "Box", @@ -39,12 +40,15 @@ class Function: var door: String # Can be "None", "Open" or "Closed" var is_container: bool var container_group: String + var container_regeneration_time: float # Time in minutes for container regeneration (-1 if it doesn't regenerate) + # Constructor to initialize function properties from a dictionary func _init(data: Dictionary): door = data.get("door", "None") is_container = data.get("is_container", false) container_group = data.get("container_group", "") + container_regeneration_time = data.get("container_regeneration_time", -1.0) # Default to -1 # Get data function to return a dictionary with all properties func get_data() -> Dictionary: @@ -53,6 +57,8 @@ class Function: functiondata["is_container"] = is_container if not container_group == "": functiondata["container_group"] = container_group + if container_regeneration_time != -1: # Only include if not the default + functiondata["container_regeneration_time"] = container_regeneration_time if not door == "None": functiondata["door"] = door return functiondata diff --git a/Scripts/Runtimedata/RItemgroup.gd b/Scripts/Runtimedata/RItemgroup.gd index a31fb798..3b645740 100644 --- a/Scripts/Runtimedata/RItemgroup.gd +++ b/Scripts/Runtimedata/RItemgroup.gd @@ -52,6 +52,7 @@ var description: String var mode: String # "Collection" or "Distribution" var items: Array[Item] = [] var use_sprite: bool = false +var spriteid: String var parent: RItemgroups # Reference to the list containing all runtime itemgroups for this mod # Constructor to initialize itemgroup properties @@ -69,6 +70,7 @@ func overwrite_from_ditemgroup(ditemgroup: DItemgroup) -> void: description = ditemgroup.description mode = ditemgroup.mode use_sprite = ditemgroup.use_sprite + spriteid = ditemgroup.spriteid # Convert DItemgroup items to RItemgroup items items.clear() diff --git a/Scripts/Runtimedata/RMobfaction.gd b/Scripts/Runtimedata/RMobfaction.gd index ba3ae609..1b8a74c7 100644 --- a/Scripts/Runtimedata/RMobfaction.gd +++ b/Scripts/Runtimedata/RMobfaction.gd @@ -43,8 +43,8 @@ func overwrite_from_dmobfaction(dmobfaction: DMobfaction) -> void: return name = dmobfaction.name description = dmobfaction.description - relations = dmobfaction.relations - references = dmobfaction.references + #relations = dmobfaction.relations + #references = dmobfaction.references # Get data function to return a dictionary with all properties func get_data() -> Dictionary: diff --git a/Scripts/Runtimedata/RMobgroup.gd b/Scripts/Runtimedata/RMobgroup.gd index 1ae0df31..4d7ac5c5 100644 --- a/Scripts/Runtimedata/RMobgroup.gd +++ b/Scripts/Runtimedata/RMobgroup.gd @@ -63,3 +63,25 @@ func get_data() -> Dictionary: # Function to check if a specific mob ID exists in the "mobs" property func has_mob(mob_id: String) -> bool: return mobs.has(mob_id) + + +func get_random_mob_id() -> String: + # If no mobs are present, return an empty string + if mobs.is_empty(): + return "" + + # Calculate the total weight + var total_weight: int = 0 + for weight in mobs.values(): + total_weight += weight + + # Generate a random number within the total weight + var random_pick: int = randi() % total_weight + + # Iterate through the mobs and select the mob based on the random pick + for mob_id in mobs.keys(): + random_pick -= mobs[mob_id] + if random_pick < 0: + return mob_id # Return the selected mob ID + + return "" # Fallback in case of an error, should not be reached