mirror of
https://github.com/TemujinCalidius/SurvivorCore.git
synced 2026-08-14 09:02:29 +00:00
Promote CHANGELOG Unreleased → 0.10.0 (the schema-driven Build page for world objects, #11) and bump wally.toml + SurvivorCore.VERSION. Demo: new demo/server/Stage.luau — one switch for what the demo places in the world (gather field + quest post, mobs, starting inventory, hand-test props). The test-station prop rows now default OFF: they're scaffolding for working ON the engine and crowded the spawn area for everyone else. Collateral: the Build demo video on the docs Demos line and as an 8th site video tile; the landing page's Studio card now tells the Build story; version surfaces bumped across site, README and getting-started. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
160 lines
4.8 KiB
Luau
160 lines
4.8 KiB
Luau
--!nonstrict
|
|
--[[
|
|
DEMO ONLY — a row of interactable parts to exercise the survival systems by hand.
|
|
|
|
Each part has a ProximityPrompt (walk up, press E) that calls a SurvivorCore stat API on
|
|
the triggering player — a live demonstration of the effects layer:
|
|
DAMAGE → real Humanoid damage (death + Roblox respawn)
|
|
FEED → Hunger down DRINK → Thirst down
|
|
POISON → start Poison ticking ANTIDOTE → stop it
|
|
BLEED → start Blood draining BANDAGE → stop it
|
|
|
|
This is demo scaffolding, not engine code — it shows how a game would drive the API.
|
|
]]
|
|
|
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
local Workspace = game:GetService("Workspace")
|
|
|
|
local SurvivorCore = require(ReplicatedStorage:WaitForChild("SurvivorCore"))
|
|
local Stage = require(script.Parent.Stage)
|
|
|
|
local POISON_SOURCE = "TestStation:poison"
|
|
local BLEED_SOURCE = "TestStation:bleed"
|
|
|
|
-- Exaggerated rates so effects are visible in seconds — the realistic ~1h defaults live in the
|
|
-- Consequences config for real gameplay. STARVE/DEHYDRATE jump the need to max so you can test
|
|
-- the starving/dehydrated consequences without waiting the real 8 hours.
|
|
local TEST_POISON_RATE = 25 -- Poison/s → ~100% in ~4s
|
|
local TEST_BLEED_RATE = 10 -- Blood/s → bled out in ~10s
|
|
|
|
local function stats()
|
|
return SurvivorCore.Stats
|
|
end
|
|
|
|
local STATIONS = {
|
|
{
|
|
label = "DAMAGE -25 HP",
|
|
color = Color3.fromRGB(200, 60, 60),
|
|
action = function(_player, humanoid)
|
|
if humanoid then
|
|
humanoid:TakeDamage(25) -- repeated hits → death → Roblox respawn
|
|
end
|
|
end,
|
|
},
|
|
{
|
|
label = "FEED (Hunger -40)",
|
|
color = Color3.fromRGB(225, 150, 60),
|
|
action = function(player)
|
|
stats().adjust(player, "Hunger", -40)
|
|
end,
|
|
},
|
|
{
|
|
label = "STARVE (Hunger -> max)",
|
|
color = Color3.fromRGB(150, 90, 40),
|
|
action = function(player)
|
|
stats().adjust(player, "Hunger", 100) -- clamps to max → starving
|
|
end,
|
|
},
|
|
{
|
|
label = "DRINK (Thirst -40)",
|
|
color = Color3.fromRGB(70, 140, 220),
|
|
action = function(player)
|
|
stats().adjust(player, "Thirst", -40)
|
|
end,
|
|
},
|
|
{
|
|
label = "DEHYDRATE (Thirst -> max)",
|
|
color = Color3.fromRGB(40, 80, 140),
|
|
action = function(player)
|
|
stats().adjust(player, "Thirst", 100) -- clamps to max → dehydrated
|
|
end,
|
|
},
|
|
{
|
|
label = "POISON (fast)",
|
|
color = Color3.fromRGB(120, 190, 70),
|
|
action = function(player)
|
|
stats().addModifier(player, "Poison", { ratePerSecond = TEST_POISON_RATE, source = POISON_SOURCE })
|
|
end,
|
|
},
|
|
{
|
|
label = "ANTIDOTE (stop poison)",
|
|
color = Color3.fromRGB(190, 235, 170),
|
|
action = function(player)
|
|
stats().removeModifier(player, "Poison", POISON_SOURCE)
|
|
end,
|
|
},
|
|
{
|
|
label = "BLEED (fast)",
|
|
color = Color3.fromRGB(130, 20, 20),
|
|
action = function(player)
|
|
stats().addModifier(player, "Blood", { ratePerSecond = -TEST_BLEED_RATE, source = BLEED_SOURCE })
|
|
end,
|
|
},
|
|
{
|
|
label = "BANDAGE (stop bleed)",
|
|
color = Color3.fromRGB(235, 235, 235),
|
|
action = function(player)
|
|
stats().removeModifier(player, "Blood", BLEED_SOURCE)
|
|
end,
|
|
},
|
|
}
|
|
|
|
local function humanoidOf(player: Player): Humanoid?
|
|
local character = player.Character
|
|
return character and character:FindFirstChildOfClass("Humanoid") or nil
|
|
end
|
|
|
|
local function buildStation(def: any, position: Vector3)
|
|
local part = Instance.new("Part")
|
|
part.Name = "TestStation"
|
|
part.Size = Vector3.new(3, 3, 3)
|
|
part.Anchored = true
|
|
part.Color = def.color
|
|
part.Material = Enum.Material.SmoothPlastic
|
|
part.Position = position
|
|
part.Parent = Workspace
|
|
|
|
local billboard = Instance.new("BillboardGui")
|
|
billboard.Size = UDim2.fromOffset(220, 44)
|
|
billboard.StudsOffset = Vector3.new(0, 2.5, 0)
|
|
billboard.AlwaysOnTop = true
|
|
billboard.Parent = part
|
|
|
|
local label = Instance.new("TextLabel")
|
|
label.Size = UDim2.fromScale(1, 1)
|
|
label.BackgroundTransparency = 1
|
|
label.Text = def.label
|
|
label.TextColor3 = Color3.fromRGB(255, 255, 255)
|
|
label.TextStrokeTransparency = 0.4
|
|
label.TextScaled = true
|
|
label.Font = Enum.Font.GothamBold
|
|
label.Parent = billboard
|
|
|
|
local prompt = Instance.new("ProximityPrompt")
|
|
prompt.ActionText = "Use"
|
|
prompt.ObjectText = def.label
|
|
prompt.HoldDuration = 0
|
|
prompt.RequiresLineOfSight = false
|
|
prompt.MaxActivationDistance = 10
|
|
prompt.Parent = part
|
|
|
|
prompt.Triggered:Connect(function(player)
|
|
if typeof(stats().adjust) ~= "function" then
|
|
warn("[SurvivorCore demo] stat runtime not ready — has SurvivorCore.start() run?")
|
|
return
|
|
end
|
|
def.action(player, humanoidOf(player))
|
|
end)
|
|
end
|
|
|
|
-- (The engine syncs the "Health" stat to the Humanoid + resets stats on respawn now, so the
|
|
-- DAMAGE part's real damage shows on the HUD and death/respawn comes out clean on its own.)
|
|
|
|
if Stage.TestStations then
|
|
local BASE = Vector3.new(0, 4, -16)
|
|
for i, def in STATIONS do
|
|
local x = (i - (#STATIONS + 1) / 2) * 4
|
|
buildStation(def, BASE + Vector3.new(x, 0, 0))
|
|
end
|
|
end
|