Add generator logic
This commit is contained in:
@@ -1,20 +1,162 @@
|
||||
class_name CurrencyGenerator
|
||||
extends Node
|
||||
|
||||
@export var currency: GameState.CurrencyType
|
||||
signal purchase_completed(amount: int, total_owned: int, total_purchased: int, total_cost: BigNumber)
|
||||
signal purchase_failed(requested_amount: int, required_cost: BigNumber, available_currency: BigNumber)
|
||||
signal production_tick(amount: BigNumber, cycle_count: int, total_owned: int)
|
||||
|
||||
const HUGE_COST_EXPONENT: int = 1000000
|
||||
|
||||
@export var currency: GameState.CurrencyType = GameState.CurrencyType.gold
|
||||
@export var data: CurrencyGeneratorData
|
||||
@export var is_automatic: bool = true
|
||||
@export var press_buys_generator: bool = true
|
||||
@export var run_multiplier: float = 1.0
|
||||
|
||||
## Manual click fallback when no data is assigned.
|
||||
@export var click_mantissa: float = 1.0
|
||||
@export var click_exponent: int = 0
|
||||
|
||||
var owned: int = 0
|
||||
var purchased_count: int = 0
|
||||
var cycle_progress_seconds: float = 0.0
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
pass # Replace with function body.
|
||||
cycle_progress_seconds = 0.0
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta: float) -> void:
|
||||
pass
|
||||
if not is_automatic:
|
||||
return
|
||||
if data == null or owned <= 0:
|
||||
return
|
||||
|
||||
var cycle_seconds: float = maxf(data.initial_time, 0.0001)
|
||||
cycle_progress_seconds += maxf(delta, 0.0)
|
||||
if cycle_progress_seconds < cycle_seconds:
|
||||
return
|
||||
|
||||
var completed_cycles: int = floori(cycle_progress_seconds / cycle_seconds)
|
||||
cycle_progress_seconds -= cycle_seconds * float(completed_cycles)
|
||||
_grant_cycle_income(completed_cycles)
|
||||
|
||||
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)
|
||||
if per_cycle <= 0.0:
|
||||
return
|
||||
|
||||
var produced: BigNumber = BigNumber.from_float(per_cycle).multiply(BigNumber.from_float(float(cycle_count)))
|
||||
_add_currency(produced)
|
||||
production_tick.emit(produced, cycle_count, owned)
|
||||
|
||||
func get_next_cost() -> BigNumber:
|
||||
return get_cost_for_amount(1)
|
||||
|
||||
func get_cost_for_amount(amount: int = 1) -> BigNumber:
|
||||
if data == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
var safe_amount: int = maxi(amount, 1)
|
||||
var raw_cost: float = data.cost_for_amount(owned, safe_amount)
|
||||
return _float_to_big_number(raw_cost)
|
||||
|
||||
func can_buy(amount: int = 1) -> bool:
|
||||
var cost: BigNumber = get_cost_for_amount(amount)
|
||||
var current: BigNumber = _get_currency_amount()
|
||||
return current.is_greater_than(cost) or current.is_equal_to(cost)
|
||||
|
||||
func buy(amount: int = 1) -> bool:
|
||||
if data == null:
|
||||
return false
|
||||
|
||||
var safe_amount: int = maxi(amount, 1)
|
||||
var total_cost: BigNumber = get_cost_for_amount(safe_amount)
|
||||
if not _spend_currency(total_cost):
|
||||
purchase_failed.emit(safe_amount, total_cost, _get_currency_amount())
|
||||
return false
|
||||
|
||||
owned += safe_amount
|
||||
purchased_count += safe_amount
|
||||
purchase_completed.emit(safe_amount, owned, purchased_count, total_cost)
|
||||
return true
|
||||
|
||||
func buy_max() -> int:
|
||||
if data == null:
|
||||
return 0
|
||||
|
||||
var available_currency: float = _big_number_to_float(_get_currency_amount())
|
||||
var estimated_max: int = data.max_affordable(owned, available_currency)
|
||||
if estimated_max <= 0:
|
||||
return 0
|
||||
|
||||
# Keep max-buy accurate by validating affordability with BigNumber comparisons.
|
||||
var low: int = 1
|
||||
var high: int = estimated_max
|
||||
var best: int = 0
|
||||
while low <= high:
|
||||
var mid: int = floori((float(low) + float(high)) * 0.5)
|
||||
if can_buy(mid):
|
||||
best = mid
|
||||
low = mid + 1
|
||||
else:
|
||||
high = mid - 1
|
||||
|
||||
if best <= 0:
|
||||
return 0
|
||||
return best if buy(best) else 0
|
||||
|
||||
func _on_pressed() -> void:
|
||||
if data != null and press_buys_generator:
|
||||
buy(1)
|
||||
return
|
||||
|
||||
_add_currency(BigNumber.new(click_mantissa, click_exponent))
|
||||
|
||||
func grant_currency(amount: BigNumber) -> void:
|
||||
_add_currency(amount)
|
||||
|
||||
func _add_currency(amount: BigNumber) -> void:
|
||||
match currency:
|
||||
GameState.CurrencyType.gold: GameState.add_gold(BigNumber.new(1, 0))
|
||||
GameState.CurrencyType.gems: GameState.add_gems(BigNumber.new(1, 0))
|
||||
_: print("c")
|
||||
pass
|
||||
GameState.CurrencyType.gold:
|
||||
GameState.add_gold(amount)
|
||||
GameState.CurrencyType.gems:
|
||||
GameState.add_gems(amount)
|
||||
_:
|
||||
push_error("Unknown currency type in CurrencyGenerator._add_currency")
|
||||
|
||||
func _spend_currency(cost: BigNumber) -> bool:
|
||||
match currency:
|
||||
GameState.CurrencyType.gold:
|
||||
return GameState.spend_gold(cost)
|
||||
GameState.CurrencyType.gems:
|
||||
return GameState.spend_gems(cost)
|
||||
_:
|
||||
push_error("Unknown currency type in CurrencyGenerator._spend_currency")
|
||||
return false
|
||||
|
||||
func _get_currency_amount() -> BigNumber:
|
||||
match currency:
|
||||
GameState.CurrencyType.gold:
|
||||
return GameState.gold
|
||||
GameState.CurrencyType.gems:
|
||||
return GameState.gems
|
||||
_:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
func _float_to_big_number(value: float) -> BigNumber:
|
||||
if value <= 0.0:
|
||||
return BigNumber.from_float(0.0)
|
||||
if not is_finite(value):
|
||||
return BigNumber.new(1.0, HUGE_COST_EXPONENT)
|
||||
return BigNumber.from_float(value)
|
||||
|
||||
func _big_number_to_float(value: BigNumber) -> float:
|
||||
if value.mantissa <= 0.0:
|
||||
return 0.0
|
||||
if value.exponent > 308:
|
||||
return INF
|
||||
if value.exponent < -308:
|
||||
return 0.0
|
||||
return value.mantissa * pow(10.0, float(value.exponent))
|
||||
|
||||
Reference in New Issue
Block a user