From 71abf7e34a1f4838137624e3c67f43c24d742df2 Mon Sep 17 00:00:00 2001 From: Jeremy Baxter Date: Mon, 26 Jan 2026 13:56:49 +1300 Subject: [PATCH 1/3] economy: add class Economy --- economy/economy.gd | 79 ++++++++++++++++++++++++++++++++++++++++++++ economy/economy.tscn | 6 ++++ 2 files changed, 85 insertions(+) create mode 100644 economy/economy.gd create mode 100644 economy/economy.tscn diff --git a/economy/economy.gd b/economy/economy.gd new file mode 100644 index 0000000..7d3b713 --- /dev/null +++ b/economy/economy.gd @@ -0,0 +1,79 @@ +# Economy is a game entity that tracks money. + +# How money is minted, how money changes hands, and which +# money is valid is all controlled by Economy. When an +# in-game item is purchased, the money does not disappear +# but rather goes to the Market, an economic entity which +# can give back to players through investments or other means. + +# Economy also tracks GDP, which is the total amount of +# money that has changed hands so far during the game. +class_name Economy extends Node + +# Participant in the game economy +@abstract class Participant: + var participant_name = "Unnamed participant" + var _tokens = PackedInt32Array() + + func balance(): + return _tokens.size() + + func hold_tokens(tokens): + _tokens.append_array(tokens) + on_balance_update(balance()) + + func pop_tokens(amount): + if balance() < amount: + return [] + + var dropped = [] + for i in range(amount): + dropped.append(_tokens[_tokens.size() - 1]) + _tokens.remove_at(_tokens.size() - 1) + on_balance_update(balance()) + return dropped + + @abstract func message(string) + @abstract func on_balance_update(bal) + +class Market extends Participant: + func _init(): + participant_name = "Market" + func message(_s): + pass + func on_balance_update(_bal): + pass + +const max_money_supply = 1_000_000 + +var _gdp = 0 +var _market = Market.new() +var _participants = [] +var _token_ptr = 0 + +# register a Participant to receive benefits +func register(p: Participant): + _participants.append(p) + +func transfer(amount, sender: Participant, recipient: Participant): + if sender.balance() < amount: + return false + recipient.hold_tokens(sender.pop_tokens(amount)) + _gdp += amount + +func mint(amount): + var tokens = PackedInt32Array() + if _token_ptr + amount > max_money_supply: + return false + for i in range(amount): + tokens.append(_token_ptr) + _token_ptr += 1 + _market.hold_tokens(tokens) + return true + +func _ready(): + while true: + if len(_participants) > 0: + mint(1000) + transfer(1000, _market, _participants[0]) + break diff --git a/economy/economy.tscn b/economy/economy.tscn new file mode 100644 index 0000000..e966432 --- /dev/null +++ b/economy/economy.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://cenj3dcweigwt"] + +[ext_resource type="Script" uid="uid://dl1jbgt83gocy" path="res://economy/economy.gd" id="1_n84lp"] + +[node name="Economy" type="Node"] +script = ExtResource("1_n84lp") From 7a2e4111ac52d7722ba09b912bfe7deafffa6258 Mon Sep 17 00:00:00 2001 From: Jeremy Baxter Date: Mon, 26 Jan 2026 13:57:12 +1300 Subject: [PATCH 2/3] world: add Economy node --- main.tscn | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main.tscn b/main.tscn index ae10ae9..e5af29a 100644 --- a/main.tscn +++ b/main.tscn @@ -1,10 +1,11 @@ -[gd_scene load_steps=9 format=3 uid="uid://eiaw4xbs3suk"] +[gd_scene load_steps=10 format=3 uid="uid://eiaw4xbs3suk"] [ext_resource type="PackedScene" uid="uid://qb8cbljxgnub" path="res://world/killbrick.tscn" id="1_h2yge"] [ext_resource type="PackedScene" uid="uid://cfceg80unq0pe" path="res://player/player.tscn" id="1_ig7tw"] [ext_resource type="PackedScene" uid="uid://bcmrj6qkemrll" path="res://world/radiohead_cube.tscn" id="2_0xm2m"] [ext_resource type="PackedScene" uid="uid://of6tq8gpjxtu" path="res://gears/gear_pickup.tscn" id="3_lquwl"] [ext_resource type="PackedScene" uid="uid://bafl8q0r61xrg" path="res://gears/gear.tscn" id="4_7mycd"] +[ext_resource type="PackedScene" uid="uid://cenj3dcweigwt" path="res://economy/economy.tscn" id="6_7mycd"] [sub_resource type="BoxShape3D" id="BoxShape3D_7dm0k"] size = Vector3(100, 2, 100) @@ -52,3 +53,5 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12, 2, -21) [node name="Gear" parent="GearPickup" instance=ExtResource("4_7mycd")] transform = Transform3D(1, 0, 0, 0, -0.012967386, 0.9999159, 0, -0.9999159, -0.012967386, 0, 0.5, 0) + +[node name="Economy" parent="." instance=ExtResource("6_7mycd")] From 4402a72ce268d3400d96294a7483a1d23c474c5f Mon Sep 17 00:00:00 2001 From: Jeremy Baxter Date: Mon, 26 Jan 2026 13:57:19 +1300 Subject: [PATCH 3/3] player: add Economy integration --- player/player.gd | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/player/player.gd b/player/player.gd index 48f08e0..6e9f274 100644 --- a/player/player.gd +++ b/player/player.gd @@ -10,6 +10,7 @@ const gear_slots = ["1", "2", "3"] var starting_gear = preload("res://gears/ball.tscn") +var ep = PlayerParticipant.new(self) var suspended = false var direction = Vector3.ZERO var target_velocity = Vector3.ZERO @@ -27,13 +28,17 @@ func resize_ui(): $HUD.position.x = 0 $HUD.position.y = size.y - hud_h -func make_hud(): +func make_hud(balance = ep.balance()): + if suspended: # TODO: CHANGE TO DEAD! + return + var text = "" for node in $Backpack.get_children(): if not node is Gear: continue text += "%s (%s)\n" % [node.gear_name(), node.name] text += "Holding " + $Pivot/Container/Gear.gear_name() + "\n" + text += str(balance) + " ₹ (rupees)\n" text += str(health()) + " hp" $HUD.text = text @@ -147,6 +152,18 @@ func equip(gear: Gear): message("Backpack full") return false +# Economy participant definition + +class PlayerParticipant extends Economy.Participant: + var player: Player + func _init(p: Player): + player = p + participant_name = "Player participant" + func message(string): + player.message(string) + func on_balance_update(bal): + player.make_hud(bal) + # Player mechanics func move_player(x, z): @@ -217,6 +234,7 @@ func do_gears(): # Engine callbacks func _ready(): + get_tree().current_scene.get_node("Economy").register(ep) get_viewport().size_changed.connect(resize_ui) resize_ui() respawn()