From 22d732656580a455e5d84b42750036605e4c643d Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 28 Jan 2026 20:18:44 +0000 Subject: [PATCH] Balancing --- resources/UnlockData.tres | 94 +++++++++++++++++++----------- resources/UnlockDataResource.gd | 54 ++++++----------- scripts/globals.gd | 7 ++- scripts/tick_process.gd | 7 +++ scripts/unlock_data_lightweight.gd | 44 +++++--------- scripts/unlocks.gd | 15 ++++- 6 files changed, 116 insertions(+), 105 deletions(-) diff --git a/resources/UnlockData.tres b/resources/UnlockData.tres index 660ca88..87baba5 100644 --- a/resources/UnlockData.tres +++ b/resources/UnlockData.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" script_class="UnlockDataCollection" load_steps=10 format=3 uid="uid://b4c01yrmp1wf2"] +[gd_resource type="Resource" script_class="UnlockDataCollection" load_steps=12 format=3 uid="uid://b4c01yrmp1wf2"] [ext_resource type="Script" uid="uid://bg1ymgbdcwc0j" path="res://resources/UnlockDataCollection.gd" id="1_gdehu"] [ext_resource type="Script" uid="uid://biqqffne7dd8r" path="res://resources/UnlockDataResource.gd" id="2_1js7i"] @@ -8,13 +8,13 @@ script = ExtResource("2_1js7i") unlock_id = 1 unlock_name = "Marketing" unlock_description = "Affects the amount people are willing to pay for your whittling" -base_cost = 200 +base_cost = 100 is_scaling = true -max_rank = 5 -cost_ladder = [200, 1200, 6000, 25000, 80000] -effect_scaling_multiplier = 1.6 +max_rank = 8 +cost_ladder = [100, 350, 1000, 3000, 9000, 28000, 80000, 220000] +effect_ladder = [1.08, 1.18, 1.3, 1.45, 1.65, 1.9, 2.3, 3.0] base_modifiers = { -"sale_price_modifier": 1.5 +"sale_price_modifier": 1.08 } metadata/_custom_type_script = "uid://biqqffne7dd8r" @@ -23,14 +23,13 @@ script = ExtResource("2_1js7i") unlock_id = 2 unlock_name = "Wood" unlock_description = "Increases the amount of wood produced per click" -base_cost = 100 +base_cost = 30 is_scaling = true -max_rank = 4 -cost_ladder = [100, 400, 2000, 8000] -effect_scaling_type = 0 -effect_linear_increase = 5.0 +max_rank = 5 +cost_ladder = [30, 100, 300, 900, 2500] +effect_ladder = [2.0, 3.0, 5.0, 7.0, 10.0] base_modifiers = { -"wood_per_click_modifier": 5.0 +"wood_per_click_modifier": 2.0 } metadata/_custom_type_script = "uid://biqqffne7dd8r" @@ -39,11 +38,11 @@ script = ExtResource("2_1js7i") unlock_id = 3 unlock_name = "Demand" unlock_description = "How many whittled products can be purchased per tick" -base_cost = 300 +base_cost = 120 is_scaling = true -max_rank = 4 -cost_ladder = [300, 1500, 8000, 35000] -effect_scaling_multiplier = 2.0 +max_rank = 7 +cost_ladder = [120, 400, 1200, 4000, 12000, 38000, 110000] +effect_ladder = [2.0, 3.0, 5.0, 7.0, 10.0, 14.0, 18.0] base_modifiers = { "purchase_rate_modifier": 2.0 } @@ -54,12 +53,11 @@ script = ExtResource("2_1js7i") unlock_id = 4 unlock_name = "Efficiency" unlock_description = "How many things you can produce per whittle" -base_cost = 150 +base_cost = 60 is_scaling = true -max_rank = 5 -cost_ladder = [150, 800, 4000, 18000, 60000] -effect_scaling_type = 0 -effect_linear_increase = 1.0 +max_rank = 6 +cost_ladder = [60, 400, 1800, 8000, 35000, 140000] +effect_ladder = [2.0, 3.0, 4.0, 5.0, 6.0, 8.0] base_modifiers = { "efficiency_modifier": 2.0 } @@ -69,8 +67,8 @@ metadata/_custom_type_script = "uid://biqqffne7dd8r" script = ExtResource("2_1js7i") unlock_id = 5 unlock_name = "Wholesale" -unlock_description = "Sell multiples of 100 at 20% extra income" -base_cost = 18000 +unlock_description = "Sell multiples of 100 at 20% less income" +base_cost = 35000 base_modifiers = { "UNLOCK_ONESHOT_WHOLESALE": 1.0 } @@ -81,12 +79,11 @@ script = ExtResource("2_1js7i") unlock_id = 6 unlock_name = "Multicraft" unlock_description = "Just craft more stuff" -base_cost = 30000 +base_cost = 6000 is_scaling = true -max_rank = 2 -cost_ladder = [30000, 100000] -effect_scaling_type = 0 -effect_linear_increase = 1.0 +max_rank = 5 +cost_ladder = [6000, 20000, 55000, 140000, 320000] +effect_ladder = [1.0, 2.0, 3.0, 4.0, 5.0] base_modifiers = { "multicraft_increase_modifier": 1.0 } @@ -97,18 +94,47 @@ script = ExtResource("2_1js7i") unlock_id = 7 unlock_name = "Autowood" unlock_description = "Automatically gather a percent of a clicks wood per tick" -base_cost = 500 +base_cost = 150 is_scaling = true max_rank = 5 -cost_ladder = [500, 2000, 8000, 25000, 70000] -effect_scaling_type = 0 -effect_linear_increase = 0.15 +cost_ladder = [150, 600, 2000, 6500, 20000] +effect_ladder = [0.1, 0.2, 0.35, 0.55, 0.8] base_modifiers = { -"autowood_modifier": 0.15 +"autowood_modifier": 0.1 +} +metadata/_custom_type_script = "uid://biqqffne7dd8r" + +[sub_resource type="Resource" id="Resource_premium"] +script = ExtResource("2_1js7i") +unlock_id = 8 +unlock_name = "Premium Crafts" +unlock_description = "Your reputation for quality allows higher prices" +base_cost = 8000 +is_scaling = true +max_rank = 5 +cost_ladder = [8000, 25000, 70000, 160000, 350000] +effect_ladder = [1.08, 1.18, 1.3, 1.45, 1.65] +base_modifiers = { +"premium_price_modifier": 1.08 +} +metadata/_custom_type_script = "uid://biqqffne7dd8r" + +[sub_resource type="Resource" id="Resource_reputation"] +script = ExtResource("2_1js7i") +unlock_id = 9 +unlock_name = "Reputation" +unlock_description = "Loyal customers provide steady passive income" +base_cost = 4000 +is_scaling = true +max_rank = 5 +cost_ladder = [4000, 12000, 35000, 90000, 200000] +effect_ladder = [4.0, 10.0, 22.0, 42.0, 75.0] +base_modifiers = { +"reputation_income": 4.0 } metadata/_custom_type_script = "uid://biqqffne7dd8r" [resource] script = ExtResource("1_gdehu") -unlocks = Array[ExtResource("2_1js7i")]([SubResource("Resource_gdehu"), SubResource("Resource_1js7i"), SubResource("Resource_xbpe0"), SubResource("Resource_nbe0w"), SubResource("Resource_ppuju"), SubResource("Resource_chx6j"), SubResource("Resource_f82ch")]) +unlocks = Array[ExtResource("2_1js7i")]([SubResource("Resource_gdehu"), SubResource("Resource_1js7i"), SubResource("Resource_xbpe0"), SubResource("Resource_nbe0w"), SubResource("Resource_ppuju"), SubResource("Resource_chx6j"), SubResource("Resource_f82ch"), SubResource("Resource_premium"), SubResource("Resource_reputation")]) metadata/_custom_type_script = "uid://bg1ymgbdcwc0j" diff --git a/resources/UnlockDataResource.gd b/resources/UnlockDataResource.gd index 3b5bdab..8ec132e 100644 --- a/resources/UnlockDataResource.gd +++ b/resources/UnlockDataResource.gd @@ -18,10 +18,7 @@ extends Resource @export var cost_linear_increase: int = 100 # Only used if cost_scaling_type is Linear @export var cost_ladder: Array[int] = [] # Fixed costs per rank (overrides scaling if defined) -@export_subgroup("Effect Scaling") -@export_enum("Linear", "Exponential") var effect_scaling_type: int = 1 # Default to Exponential -@export var effect_scaling_multiplier: float = 1.2 # Exponential: multiplier per rank -@export var effect_linear_increase: float = 0.1 # Linear: flat increase per rank (e.g., 0.1 = +10% per rank) +@export var effect_ladder: Array[float] = [] # Effect values per rank @export_group("Base Modifiers") @export var base_modifiers: Dictionary = {} @@ -44,44 +41,27 @@ func get_next_cost() -> int: ## Returns the current modifiers based on rank func get_current_modifiers() -> Dictionary: - # If not unlocked yet, return empty modifiers if not is_unlocked or current_rank == 0: return {} - - # Rank 1 should give base modifiers without scaling - if current_rank == 1: - return base_modifiers.duplicate() - - # Rank 2+ applies scaling return get_modifiers_at_rank(current_rank) ## Returns modifiers for a specific rank (useful for preview) func get_modifiers_at_rank(rank: int) -> Dictionary: - if not is_scaling or rank == 0: + if rank == 0: + return {} + + # For one-shot unlocks or empty ladder, return base_modifiers + if effect_ladder.size() == 0: return base_modifiers.duplicate() - - # Rank 1 returns base modifiers without scaling - if rank == 1: - return base_modifiers.duplicate() - - var scaled_modifiers = {} + + var ladder_index = rank - 1 + if ladder_index >= effect_ladder.size(): + ladder_index = effect_ladder.size() - 1 # Use last value if rank exceeds ladder + + var result = {} for key in base_modifiers.keys(): - var base_value = base_modifiers[key] - - if effect_scaling_type == 0: # Linear scaling - # Linear: add flat increase per rank above 1 - # e.g., base 1.5 (+50%), linear 0.1 (+10%), rank 2 = 1.6 (+60%), rank 3 = 1.7 (+70%) - var additional_ranks = rank - 1 - scaled_modifiers[key] = base_value + (effect_linear_increase * additional_ranks) - else: # Exponential scaling - # Exponential: scale the bonus part from rank 1 - # The bonus at rank 1 is (base_value - 1.0) - # At higher ranks, multiply this bonus by multiplier^(rank-1) - var base_bonus = base_value - 1.0 - var scaled_bonus = base_bonus * pow(effect_scaling_multiplier, rank - 1) - scaled_modifiers[key] = 1.0 + scaled_bonus - - return scaled_modifiers + result[key] = effect_ladder[ladder_index] + return result ## Convert a modifier value to a percentage string func _modifier_to_percentage(value: float) -> String: @@ -132,17 +112,17 @@ func get_modifiers_comparison_string() -> String: var current = get_current_modifiers() var next_rank = get_next_rank() var next = get_modifiers_at_rank(next_rank) - + + var lines = [] + # If no current modifiers (not unlocked yet), show next only if current.is_empty(): - var lines = [] for key in next.keys(): var display_name = key.replace("_", " ").capitalize() var next_pct = _modifier_to_percentage(next[key]) lines.append("%s: %s" % [display_name, next_pct]) return "\n".join(lines) - var lines = [] for key in current.keys(): var display_name = key.replace("_", " ").capitalize() var current_pct = _modifier_to_percentage(current[key]) diff --git a/scripts/globals.gd b/scripts/globals.gd index 80a6041..b58e330 100644 --- a/scripts/globals.gd +++ b/scripts/globals.gd @@ -13,7 +13,7 @@ var wood_color: Color = Color(0.95, 0.6, 0.35) # Light pumpkin orange (autumn le var stock_color: Color = Color(0.6, 0.75, 0.95) # Light periwinkle blue (clear autumn sky) # GAMEPLAY VALUES -var target_currency: float = 1000 +var target_currency: float = 1000000 var base_sale_price: float = 30 var base_wood_respawn: float = 5 # seconds var wood_per_click: float = 5 @@ -22,8 +22,11 @@ var base_purchase_rate: float = 1 var wholesale_unlock_id: int = 5 var wholesale_bundle_size: int = 100 -var wholesale_discount_multiplier: float = 1.2 +var wholesale_discount_multiplier: float = 0.8 var multicraft_unlock_id: int = 6 var autowood_unlock_id: int = 7 + +var premium_crafts_unlock_id: int = 8 +var reputation_unlock_id: int = 9 diff --git a/scripts/tick_process.gd b/scripts/tick_process.gd index debd128..6e1eb9f 100644 --- a/scripts/tick_process.gd +++ b/scripts/tick_process.gd @@ -28,6 +28,7 @@ func tick(): do_autowood() do_whittling() do_selling() + do_reputation_income() func do_autowood(): # If the autowood unlock is unlocked then automatically gain wood based on the modifier @@ -93,3 +94,9 @@ func whittle_max_wood_possible(): inventory_provider.spend_wood(wood_to_whittle) inventory_provider.add_stock(actual_items_produced) # Log.pr("Whittled", str(wood_to_whittle), "wood into", str(actual_items_produced), "whittle wood.") + +func do_reputation_income(): + # Add passive income from reputation unlock + var reputation_income = unlocks_provider.get_modifier_value("reputation_income") + if reputation_income > 0: + inventory_provider.add_currency(reputation_income) diff --git a/scripts/unlock_data_lightweight.gd b/scripts/unlock_data_lightweight.gd index af1e799..0aeca12 100644 --- a/scripts/unlock_data_lightweight.gd +++ b/scripts/unlock_data_lightweight.gd @@ -18,10 +18,8 @@ var cost_scaling_multiplier: float = 1.5 var cost_linear_increase: int = 100 var cost_ladder: Array[int] = [] -# Effect scaling -var effect_scaling_type: int = 1 # 0=Linear, 1=Exponential -var effect_scaling_multiplier: float = 1.2 -var effect_linear_increase: float = 0.1 +# Effect ladder +var effect_ladder: Array[float] = [] # Base modifiers var base_modifiers: Dictionary = {} @@ -38,9 +36,7 @@ static func from_resource(resource: UnlockDataResource) -> UnlockDataLightweight data.cost_scaling_multiplier = resource.cost_scaling_multiplier data.cost_linear_increase = resource.cost_linear_increase data.cost_ladder = resource.cost_ladder.duplicate() - data.effect_scaling_type = resource.effect_scaling_type - data.effect_scaling_multiplier = resource.effect_scaling_multiplier - data.effect_linear_increase = resource.effect_linear_increase + data.effect_ladder = resource.effect_ladder.duplicate() data.base_modifiers = resource.base_modifiers.duplicate(true) # Start fresh data.is_unlocked = false @@ -59,9 +55,7 @@ func clone() -> UnlockDataLightweight: copy.cost_scaling_multiplier = cost_scaling_multiplier copy.cost_linear_increase = cost_linear_increase copy.cost_ladder = cost_ladder # Shared - read-only - copy.effect_scaling_type = effect_scaling_type - copy.effect_scaling_multiplier = effect_scaling_multiplier - copy.effect_linear_increase = effect_linear_increase + copy.effect_ladder = effect_ladder # Shared - read-only copy.base_modifiers = base_modifiers # Shared - read-only # Mutable state copy.is_unlocked = false @@ -85,33 +79,25 @@ func get_next_cost() -> int: func get_current_modifiers() -> Dictionary: if not is_unlocked or current_rank == 0: return {} - - if current_rank == 1: - return base_modifiers.duplicate() - return get_modifiers_at_rank(current_rank) ## Same logic as UnlockDataResource.get_modifiers_at_rank() func get_modifiers_at_rank(rank: int) -> Dictionary: - if not is_scaling or rank == 0: + if rank == 0: + return {} + + # For one-shot unlocks or empty ladder, return base_modifiers + if effect_ladder.size() == 0: return base_modifiers.duplicate() - if rank == 1: - return base_modifiers.duplicate() + var ladder_index = rank - 1 + if ladder_index >= effect_ladder.size(): + ladder_index = effect_ladder.size() - 1 # Use last value if rank exceeds ladder - var scaled_modifiers = {} + var result = {} for key in base_modifiers.keys(): - var base_value = base_modifiers[key] - - if effect_scaling_type == 0: # Linear - var additional_ranks = rank - 1 - scaled_modifiers[key] = base_value + (effect_linear_increase * additional_ranks) - else: # Exponential - var base_bonus = base_value - 1.0 - var scaled_bonus = base_bonus * pow(effect_scaling_multiplier, rank - 1) - scaled_modifiers[key] = 1.0 + scaled_bonus - - return scaled_modifiers + result[key] = effect_ladder[ladder_index] + return result ## Same logic as UnlockDataResource.can_rank_up() func can_rank_up() -> bool: diff --git a/scripts/unlocks.gd b/scripts/unlocks.gd index 48bd041..5199275 100644 --- a/scripts/unlocks.gd +++ b/scripts/unlocks.gd @@ -10,7 +10,9 @@ var base_modifiers: Dictionary = { "wood_respawn_modifier": 1.0, "wood_per_click_modifier": 1.0, "purchase_rate_modifier": 1.0, - "autowood_modifier": 1.0 + "autowood_modifier": 1.0, + "premium_price_modifier": 1.0, + "reputation_income": 0.0 } var current_modifiers: Dictionary = base_modifiers.duplicate() @@ -31,7 +33,11 @@ func apply_modifiers(): for key in apply_unlock_modifiers.keys(): if current_modifiers.has(key): Log.pr(" - Current", key, "modifier before:", current_modifiers[key]) - current_modifiers[key] *= apply_unlock_modifiers[key] + # Reputation income is additive, not multiplicative + if key == "reputation_income": + current_modifiers[key] = apply_unlock_modifiers[key] + else: + current_modifiers[key] *= apply_unlock_modifiers[key] Log.pr(" - Applied", key, "modifier:", apply_unlock_modifiers[key], "New value:", current_modifiers[key]) else: Log.pr(" - Warning: Unknown modifier key:", key) @@ -88,7 +94,7 @@ func unlock_item(unlock_id: int) -> bool: return false func get_sale_price_per_item(): - return Global.base_sale_price * get_modifier_value("sale_price_modifier") + return Global.base_sale_price * get_modifier_value("sale_price_modifier") * get_modifier_value("premium_price_modifier") func get_wood_per_click(): return Global.wood_per_click * get_modifier_value("wood_per_click_modifier") @@ -102,5 +108,8 @@ func get_items_produced_per_tick(): func get_sale_demand(): return Global.base_purchase_rate * get_modifier_value("purchase_rate_modifier") +func get_reputation_income(): + return get_modifier_value("reputation_income") + func _refresh_ui(): item_unlocked.emit()