File size: 4,622 Bytes
0712d5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
-- src/ServerScriptService/MarketManager.server.lua

local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local EconomyConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("EconomyConfig"))
local NotificationEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("NotificationEvent")
local MarketUpdateEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("MarketUpdateEvent")
local SoundEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("SoundEvent")

-- Global current market multipliers
local currentMarketRates = {}

-- Initialize base rates for all wood types
for woodType, _ in pairs(EconomyConfig.WoodBaseValues) do
	currentMarketRates[woodType] = 1.0
end

local function updateMarketRates()
	for woodType, _ in pairs(currentMarketRates) do
		local randShift = (math.random(-10, 10) / 100)
		local newRate = currentMarketRates[woodType] + randShift

		currentMarketRates[woodType] = math.clamp(
			newRate,
			EconomyConfig.MarketFluctuations.MaxDecrease,
			EconomyConfig.MarketFluctuations.MaxIncrease
		)
	end

	-- Broadcast updated rates to all clients
	for _, player in ipairs(Players:GetPlayers()) do
		MarketUpdateEvent:FireClient(player, currentMarketRates)
	end
end

-- Start Market Cycle
task.spawn(function()
	if EconomyConfig.MarketFluctuations.Enabled then
		while true do
			task.wait(EconomyConfig.MarketFluctuations.UpdateInterval)
			updateMarketRates()
		end
	end
end)

local function getPartVolume(part)
	return part.Size.X * part.Size.Y * part.Size.Z
end

local function calculateWoodValue(logPart)
	local treeType = logPart:GetAttribute("TreeType")
	local state = logPart:GetAttribute("ProcessState") or "Raw"

	if not treeType or not EconomyConfig.WoodBaseValues[treeType] then return 0 end

	local baseValue = EconomyConfig.WoodBaseValues[treeType]
	local marketMult = currentMarketRates[treeType] or 1.0
	local processMult = EconomyConfig.ProcessingMultipliers[state] or 1.0
	local degradedMult = logPart:GetAttribute("DegradedMult") or 1.0
	local volume = getPartVolume(logPart)

	-- Formula: Volume * BaseValue * ProcessingState * MarketDemand * Degradation
	return math.floor(volume * baseValue * processMult * marketMult * degradedMult)
end

local function rewardPlayer(player, amount)
	if not player then return end
	local leaderstats = player:FindFirstChild("leaderstats")
	if leaderstats then
		local cash = leaderstats:FindFirstChild("Cash")
		if cash then
			cash.Value = cash.Value + amount
		end
	end

	-- Track total earned
	if _G.IncrementStat then
		_G.IncrementStat(player, "TotalEarned", amount)
	end

	-- Progress quests
	if _G.ProgressQuest then
		_G.ProgressQuest(player, "Sell", 1)
		_G.ProgressQuest(player, "EarnCash", amount)
	end

	-- Check achievements
	if _G.CheckAchievements then
		task.defer(function() _G.CheckAchievements(player) end)
	end
end

local function bindDropoffZone(zonePart)
	local debounce = {}

	zonePart.Touched:Connect(function(hit)
		if CollectionService:HasTag(hit, "TreeSegment") then
			if not debounce[hit] then
				debounce[hit] = true

				local woodValue = calculateWoodValue(hit)
				local ownerId = hit:GetAttribute("OwnerId")
				local playerToReward = nil

				if ownerId then
					playerToReward = Players:GetPlayerByUserId(ownerId)
				else
					pcall(function()
						playerToReward = hit:GetNetworkOwner()
					end)
				end

				if playerToReward and woodValue > 0 then
					rewardPlayer(playerToReward, woodValue)

					-- Notification with value
					local treeType = hit:GetAttribute("TreeType") or "Unknown"
					local state = hit:GetAttribute("ProcessState") or "Raw"
					NotificationEvent:FireClient(playerToReward, "Sale", "Sold " .. state .. " " .. treeType .. " for $" .. tostring(woodValue))
					SoundEvent:FireClient(playerToReward, "CashRegister", nil)
				end

				hit:Destroy()
			end
		end
	end)
end

CollectionService:GetInstanceAddedSignal("MarketDropoff"):Connect(bindDropoffZone)
for _, zone in pairs(CollectionService:GetTagged("MarketDropoff")) do
	bindDropoffZone(zone)
end

-- Expose market rates for billboard GUI
_G.GetMarketRates = function()
	return currentMarketRates
end

-- Send initial market rates to new players
Players.PlayerAdded:Connect(function(player)
	task.delay(5, function()
		if player.Parent then
			MarketUpdateEvent:FireClient(player, currentMarketRates)
		end
	end)
end)