Add generator buffs (additional test required)
This commit is contained in:
@@ -13,6 +13,10 @@ signal purchase_completed(amount: int, total_owned: int, total_purchased: int, t
|
||||
signal purchase_failed(requested_amount: int, required_cost: BigNumber, available_currency: BigNumber)
|
||||
## Emitted when one or more automatic production cycles complete.
|
||||
signal production_tick(amount: BigNumber, cycle_count: int, total_owned: int)
|
||||
## Emitted after a successful buff purchase.
|
||||
signal buff_purchased(buff_id: StringName, new_level: int, cost: BigNumber, cost_currency_id: StringName)
|
||||
## Emitted when a buff purchase cannot be paid.
|
||||
signal buff_purchase_failed(buff_id: StringName, required_cost: BigNumber, cost_currency_id: StringName)
|
||||
|
||||
## Sentinel exponent used when cost math overflows float range.
|
||||
const HUGE_COST_EXPONENT: int = 1000000
|
||||
@@ -119,7 +123,8 @@ func _grant_cycle_income(cycle_count: int) -> void:
|
||||
if data == null or cycle_count <= 0:
|
||||
return
|
||||
|
||||
var per_cycle: float = data.production_per_cycle(owned, run_multiplier, purchased_count)
|
||||
var effective_run_multiplier: float = run_multiplier * get_automatic_production_multiplier()
|
||||
var per_cycle: float = data.production_per_cycle(owned, effective_run_multiplier, purchased_count)
|
||||
if per_cycle <= 0.0:
|
||||
return
|
||||
|
||||
@@ -195,6 +200,89 @@ func buy_max() -> int:
|
||||
return 0
|
||||
return best if buy(best) else 0
|
||||
|
||||
func get_buffs() -> Array[GeneratorBuffData]:
|
||||
if data == null:
|
||||
return []
|
||||
return data.buffs
|
||||
|
||||
func get_buff_level(buff_id: StringName) -> int:
|
||||
_ensure_registered()
|
||||
return GameState.get_generator_buff_level(_generator_id, buff_id)
|
||||
|
||||
func get_buff_cost(buff_id: StringName) -> BigNumber:
|
||||
var buff: GeneratorBuffData = _find_buff(buff_id)
|
||||
if buff == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
var level: int = get_buff_level(buff.id)
|
||||
return buff.get_cost_for_level(level)
|
||||
|
||||
func get_buff_cost_currency_id(buff_id: StringName) -> StringName:
|
||||
var buff: GeneratorBuffData = _find_buff(buff_id)
|
||||
if buff == null:
|
||||
return &""
|
||||
return _resolve_buff_cost_currency_id(buff)
|
||||
|
||||
func can_buy_buff(buff_id: StringName) -> bool:
|
||||
if not is_available_to_player():
|
||||
return false
|
||||
|
||||
var buff: GeneratorBuffData = _find_buff(buff_id)
|
||||
if buff == null:
|
||||
return false
|
||||
|
||||
var current_level: int = get_buff_level(buff.id)
|
||||
if not buff.can_purchase_next_level(current_level):
|
||||
return false
|
||||
|
||||
var cost_currency_id: StringName = _resolve_buff_cost_currency_id(buff)
|
||||
if cost_currency_id == &"":
|
||||
return false
|
||||
|
||||
var cost: BigNumber = buff.get_cost_for_level(current_level)
|
||||
var current_amount: BigNumber = GameState.get_currency_amount_by_id(cost_currency_id)
|
||||
return current_amount.is_greater_than(cost) or current_amount.is_equal_to(cost)
|
||||
|
||||
func buy_buff(buff_id: StringName) -> bool:
|
||||
if not is_available_to_player():
|
||||
return false
|
||||
|
||||
var buff: GeneratorBuffData = _find_buff(buff_id)
|
||||
if buff == null:
|
||||
return false
|
||||
|
||||
var current_level: int = get_buff_level(buff.id)
|
||||
if not buff.can_purchase_next_level(current_level):
|
||||
return false
|
||||
|
||||
var cost: BigNumber = buff.get_cost_for_level(current_level)
|
||||
var cost_currency_id: StringName = _resolve_buff_cost_currency_id(buff)
|
||||
if cost_currency_id == &"":
|
||||
return false
|
||||
|
||||
if not _spend_currency_by_id(cost_currency_id, cost):
|
||||
buff_purchase_failed.emit(buff.id, cost, cost_currency_id)
|
||||
return false
|
||||
|
||||
var next_level: int = current_level + 1
|
||||
GameState.set_generator_buff_level(_generator_id, buff.id, next_level)
|
||||
_apply_resource_purchase_buff(buff, next_level)
|
||||
buff_purchased.emit(buff.id, next_level, cost, cost_currency_id)
|
||||
return true
|
||||
|
||||
func is_buff_maxed(buff_id: StringName) -> bool:
|
||||
var buff: GeneratorBuffData = _find_buff(buff_id)
|
||||
if buff == null:
|
||||
return true
|
||||
|
||||
return not buff.can_purchase_next_level(get_buff_level(buff.id))
|
||||
|
||||
func get_automatic_production_multiplier() -> float:
|
||||
return _get_multiplier_for_buff_kind(GeneratorBuffData.BuffKind.AUTO_PRODUCTION_MULTIPLIER)
|
||||
|
||||
func get_manual_click_multiplier() -> float:
|
||||
return _get_multiplier_for_buff_kind(GeneratorBuffData.BuffKind.MANUAL_CLICK_MULTIPLIER)
|
||||
|
||||
## Handles external "pressed" interaction: buy if configured, otherwise click-grant.
|
||||
func _on_pressed() -> void:
|
||||
if not is_available_to_player():
|
||||
@@ -235,7 +323,13 @@ func _try_grant_click_currency() -> void:
|
||||
func _get_click_value() -> BigNumber:
|
||||
if data == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
return BigNumber.new(data.click_mantissa, data.click_exponent)
|
||||
|
||||
var click_multiplier: float = get_manual_click_multiplier()
|
||||
if click_multiplier <= 0.0:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
var base_click: BigNumber = BigNumber.new(data.click_mantissa, data.click_exponent)
|
||||
return base_click.multiply(BigNumber.from_float(click_multiplier))
|
||||
|
||||
## Resolves click cooldown from data.
|
||||
func _get_click_cooldown_seconds() -> float:
|
||||
@@ -268,6 +362,12 @@ func _add_currency(amount: BigNumber) -> void:
|
||||
|
||||
GameState.add_currency(currency, amount)
|
||||
|
||||
func _add_currency_by_id(currency_id: StringName, amount: BigNumber) -> void:
|
||||
if currency_id == &"":
|
||||
return
|
||||
|
||||
GameState.add_currency_by_id(currency_id, amount)
|
||||
|
||||
## Attempts to spend target currency; returns false when insufficient.
|
||||
func _spend_currency(cost: BigNumber) -> bool:
|
||||
if currency == null:
|
||||
@@ -276,6 +376,12 @@ func _spend_currency(cost: BigNumber) -> bool:
|
||||
|
||||
return GameState.spend_currency(currency, cost)
|
||||
|
||||
func _spend_currency_by_id(currency_id: StringName, cost: BigNumber) -> bool:
|
||||
if currency_id == &"":
|
||||
return false
|
||||
|
||||
return GameState.spend_currency_by_id(currency_id, cost)
|
||||
|
||||
## Returns the current amount for the configured currency type.
|
||||
func _get_currency_amount() -> BigNumber:
|
||||
if currency == null:
|
||||
@@ -300,6 +406,59 @@ func _big_number_to_float(value: BigNumber) -> float:
|
||||
return 0.0
|
||||
return value.mantissa * pow(10.0, float(value.exponent))
|
||||
|
||||
func _find_buff(buff_id: StringName) -> GeneratorBuffData:
|
||||
if data == null:
|
||||
return null
|
||||
return data.find_buff(buff_id)
|
||||
|
||||
func _resolve_buff_cost_currency_id(buff: GeneratorBuffData) -> StringName:
|
||||
if buff == null:
|
||||
return &""
|
||||
|
||||
var cost_currency: Resource = buff.cost_currency if buff.cost_currency != null else currency
|
||||
if cost_currency == null:
|
||||
return &""
|
||||
|
||||
return GameState.get_currency_id(cost_currency)
|
||||
|
||||
func _resolve_buff_target_currency_id(buff: GeneratorBuffData) -> StringName:
|
||||
if buff == null:
|
||||
return &""
|
||||
|
||||
var target_currency: Resource = buff.resource_target_currency if buff.resource_target_currency != null else currency
|
||||
if target_currency == null:
|
||||
return &""
|
||||
|
||||
return GameState.get_currency_id(target_currency)
|
||||
|
||||
func _get_multiplier_for_buff_kind(kind: GeneratorBuffData.BuffKind) -> float:
|
||||
var multiplier: float = 1.0
|
||||
for buff in get_buffs():
|
||||
if buff == null:
|
||||
continue
|
||||
if buff.kind != kind:
|
||||
continue
|
||||
|
||||
multiplier *= buff.get_effect_multiplier(get_buff_level(buff.id))
|
||||
|
||||
return maxf(multiplier, 0.0)
|
||||
|
||||
func _apply_resource_purchase_buff(buff: GeneratorBuffData, level: int) -> void:
|
||||
if buff == null:
|
||||
return
|
||||
if buff.kind != GeneratorBuffData.BuffKind.RESOURCE_PURCHASE:
|
||||
return
|
||||
|
||||
var target_currency_id: StringName = _resolve_buff_target_currency_id(buff)
|
||||
if target_currency_id == &"":
|
||||
return
|
||||
|
||||
var purchased_amount: BigNumber = buff.get_resource_purchase_amount_for_level(level)
|
||||
if purchased_amount.mantissa <= 0.0:
|
||||
return
|
||||
|
||||
_add_currency_by_id(target_currency_id, purchased_amount)
|
||||
|
||||
## Builds a stable state id from data id, node name, or fallback string.
|
||||
func _resolve_generator_id() -> StringName:
|
||||
if data != null:
|
||||
@@ -323,8 +482,20 @@ func _ensure_registered() -> void:
|
||||
return
|
||||
|
||||
GameState.register_generator(_generator_id, _default_unlocked_state(), _default_available_state())
|
||||
_register_buffs()
|
||||
_is_registered = true
|
||||
|
||||
func _register_buffs() -> void:
|
||||
for buff in get_buffs():
|
||||
if buff == null:
|
||||
continue
|
||||
|
||||
var buff_id_text: String = String(buff.id).strip_edges()
|
||||
if buff_id_text.is_empty():
|
||||
continue
|
||||
|
||||
GameState.register_generator_buff(_generator_id, StringName(buff_id_text), 0)
|
||||
|
||||
## Default unlocked state loaded from generator data.
|
||||
func _default_unlocked_state() -> bool:
|
||||
if data == null:
|
||||
@@ -345,9 +516,6 @@ func _on_area_2d_mouse_entered() -> void:
|
||||
func _on_area_2d_mouse_exited() -> void:
|
||||
_mouse_entered = false
|
||||
|
||||
func _on_generated_state_changed(generator_id: StringName, state: Dictionary) -> void:
|
||||
func _on_generated_state_changed(generator_id: StringName, _state: Dictionary) -> void:
|
||||
if generator_id == _generator_id:
|
||||
print(_generator_id)
|
||||
print(state)
|
||||
visible = true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user