So I’m a new developer, currently with 3 months of experience. Recently I made this:
Basically it randomly spawns ‘hampters’ based on rarity. Just a proof of concept to test my skills, Idk if imma make something out of it.
Here’s the code:
Module1
--Type Declaration
export type HampterTemplate = {
Name: string,
Type: string,
Price: number,
Size: NumberRange,
Mass: number,
LifeSpan: number,
Color: Color3,
Transparency: number,
Reflectance: number,
Material: Enum.Material,
Rarity: Rarity,
MeshId: Content,
TextureID: Content?,
Special: typeof(function(hampter: MeshPart, ...: any) end)?,
Variants: {
Main: {
Rarity: Rarity
},
[string]: {
Rarity: Rarity,
Modification: HampterTemplate
}
}?
}
export type RarityLevel = {
Label: string,
Threshold: number,
Color: Color3
}
export type Rarity = {
RarityLevel: RarityLevel,
Probability: number,
}
--Main Module
local hampterLib = {}
--Supplemental Functions
local function defineRarityLevel(probability: number): RarityLevel
local currRarityLvl: RarityLevel
for _, rarityLvl in hampterLib.Rarity_Levels :: {RarityLevel} do
if not currRarityLvl or (probability >= currRarityLvl.Threshold and currRarityLvl.Threshold < rarityLvl.Threshold) then
currRarityLvl = rarityLvl
end
end
return currRarityLvl
end
hampterLib.Default_Assets = {
MeshId = Content.fromUri("rbxassetid://6648328063"),
TextureID = Content.fromUri("rbxassetid://6648330426")
}
hampterLib.Size_Standards = {
Micro = NumberRange.new(0.15, 0.15),
Tiny = NumberRange.new(0.16, 0.20),
Very_Small = NumberRange.new(0.21, 0.30),
Small = NumberRange.new(0.31, 0.65),
Below_Average = NumberRange.new(0.66, 1.5),
Average = NumberRange.new(1.51, 2.80),
Above_Average = NumberRange.new(2.81, 5.5),
Large = NumberRange.new(5.51, 10),
Very_Large = NumberRange.new(10.01, 16.75),
Giant = NumberRange.new(16.76, 26.75),
Huge = NumberRange.new(26.76, 41.25),
}
hampterLib.Hampter_Templates = {
Non_Event = {
Regular_Hampter = {
Name = "Regular Hampter",
Price = 0.5,
Size = hampterLib.Size_Standards.Average,
Mass = 0.15,
Color = Color3.fromRGB(255, 255, 255),
LifeSpan = 60,
Transparency = 0,
Reflectance = 0,
Material = Enum.Material.Plastic,
Rarity = 900,
MeshId = hampterLib.Default_Assets.MeshId,
TextureID = hampterLib.Default_Assets.TextureID,
Variants = {
Main = {
Rarity = 700
},
Bigger = {
Rarity = 100,
Modification = {Size = hampterLib.Size_Standards.Above_Average}
},
Smaller = {
Rarity = 100,
Modification = {Size = hampterLib.Size_Standards.Below_Average}
},
Even_Bigger = {
Rarity = 50,
Modification = {Size = hampterLib.Size_Standards.Large}
},
Even_Smaller = {
Rarity = 50,
Modification = {Size = hampterLib.Size_Standards.Small}
}
}
} :: HampterTemplate,
--[[
Bigger_Hampter = {
Name = "Bigger Hampter",
Price = 0.5,
Size = hampterLib.Size_Standards.Above_Average,
Mass = 0.15,
Color = Color3.fromRGB(255, 255, 255),
LifeSpan = 60,
Transparency = 0,
Reflectance = 0,
Material = Enum.Material.Plastic,
Rarity = 90,
MeshId = hampterLib.Default_Assets.MeshId,
TextureID = hampterLib.Default_Assets.TextureID
} :: HampterTemplate,
Even_Bigger_Hampter = {
Name = "Even Bigger Hampter",
Price = 0.5,
Size = hampterLib.Size_Standards.Large,
Mass = 0.15,
Color = Color3.fromRGB(255, 255, 255),
LifeSpan = 60,
Transparency = 0,
Reflectance = 0,
Material = Enum.Material.Plastic,
Rarity = 9,
MeshId = hampterLib.Default_Assets.MeshId,
TextureID = hampterLib.Default_Assets.TextureID
} :: HampterTemplate,
Even_Biggerer_Hampter = {
Name = "Even Biggerer Hampter",
Price = 0.5,
Size = hampterLib.Size_Standards.Very_Large,
Mass = 0.15,
Color = Color3.fromRGB(255, 255, 255),
LifeSpan = 60,
Transparency = 0,
Reflectance = 0,
Material = Enum.Material.Plastic,
Rarity = 1,
MeshId = hampterLib.Default_Assets.MeshId,
TextureID = hampterLib.Default_Assets.TextureID
} :: HampterTemplate
]]
}
}
hampterLib.Rarity_Levels = {
Common = {Label = "Common", Threshold = 50, Color = Color3.fromRGB(0, 255, 0)} :: RarityLevel,
Uncommon = {Label = "Uncommon", Threshold = 5, Color = Color3.fromRGB(0, 85, 0)} :: RarityLevel,
Rare = {Label = "Rare", Threshold = 1, Color = Color3.fromRGB(0, 255, 255)} :: RarityLevel,
Very_Rare = {Label = "Very Rare", Threshold = 0.1, Color = Color3.fromRGB(0, 85, 127)} :: RarityLevel,
Legendary = {Label = "Legendary", Threshold = 0.01, Color = Color3.fromRGB(255, 255, 0)} :: RarityLevel,
Mythical = {Label = "Mythical", Threshold = 0.001, Color = Color3.fromRGB(255, 255, 255)} :: RarityLevel,
Unique = {Label = "Unique", Threshold = 0, Color = Color3.fromRGB(0, 0, 0)} :: RarityLevel
}
for typeName, hampterTypes in hampterLib.Hampter_Templates do
local totalWeight = 0
for n = 1, 2 do
for _, hampter in hampterTypes :: {HampterTemplate} do
if n == 1 then
hampter.Type = typeName
totalWeight += hampter.Rarity
if hampter.Variants then
local totalWeight = 0
for n = 1, 2 do
for _, variant in hampter.Variants do
if n == 1 then
totalWeight += variant.Rarity
else
local weight = variant.Rarity
variant.Rarity = {}
variant.Rarity.Probability = math.round(weight / totalWeight * 100 * 1000) / 1000
variant.Rarity.RarityLevel = defineRarityLevel(variant.Rarity.Probability)
end
end
end
end
else
local weight = hampter.Rarity
hampter.Rarity = {}
hampter.Rarity.Probability = math.round(weight / totalWeight * 100 * 1000) / 1000
hampter.Rarity.RarityLevel = defineRarityLevel(hampter.Rarity.Probability)
end
end --Yea yea this looks horrible ik
end
end -- 8 end chain new record woo!
print("HampterLib initialised!")
return hampterLib
Module2
--Services
local AS = game:GetService("AssetService")
local TweenService = game:GetService("TweenService")
--Modules
local HampterLib = require(script.Parent)
--Settings
local ACTIVE_KEYS = {
HampterLib.Hampter_Templates.Non_Event
}
--Supplemental Functions
local function cloneTable<T>(original: {T}): {T}
local clone = {}
for i, v in original do
if typeof(v) ~= "table" then
clone[i] = v
else
clone[i] = cloneTable(v)
end
end
return clone
end
--MetaTable
local MT = {}
--Type Declarations
export type Hampter = typeof(setmetatable({} :: {
Name: string,
Type: string,
Variant: {
Name: string,
Rarity: HampterLib.Rarity
}?,
Price: number,
Size: number,
Mass: number,
LifeSpan: number,
Color: Color3,
Transparency: number,
Reflectance: number,
Material: Enum.Material,
Rarity: HampterLib.RarityLevel,
MeshId: Content,
TextureID: Content?,
Special: typeof(function(hampter: MeshPart) end)?
}, MT))
--Main Module
local hampterFuncs = {}
--Constructors
function hampterFuncs.new(hampterTemplate: HampterLib.HampterTemplate): Hampter
local hampter = cloneTable(hampterTemplate) :: HampterLib.HampterTemplate
if hampter.Variants then
local randNum = math.random(1, 100 * 1000) / 1000
local variantName: string
local variantRarity: HampterLib.Rarity
local variantModifications
repeat
for name, variant in hampter.Variants do
local prob = variant.Rarity.Probability
if prob > randNum and (not variantName or variant.Rarity.Probability > prob or (variant.Rarity.Probability == prob and math.random(0, 1) == 1)) then
variantName = name
variantRarity = variant.Rarity
if variant.Modification then
variantModifications = variant.Modification
end
end
end
if not variantName then
randNum = math.random(1, 100 * 1000) / 1000
end
task.wait()
until variantName
hampter.Variant = {
Name = variantName,
Rarity = variantRarity
}
if variantModifications then
for prop, val in variantModifications do
hampter[prop] = val
end
end
hampter.Variants = nil
end
hampter.Size = math.random(hampter.Size.Min * 100, hampter.Size.Max * 100) / 100
hampter.Mass = math.round(4/3 * math.pi * (hampter.Size / 2) ^ 3 * hampter.Mass * 100) / 100
hampter.Price = math.round(hampter.Price * (4/3 * math.pi * (hampter.Size / 2) ^ 3) * (1.24 * hampter.Size ^ -0.25) * 100) / 100
return setmetatable(hampter, MT) :: Hampter
end
function hampterFuncs.randomized(): Hampter
local randType = ACTIVE_KEYS[math.random(1, #ACTIVE_KEYS)]
local randNum = math.random(1, 100 * 1000) / 1000
local hampter: HampterLib.HampterTemplate
repeat
for _, hampterTemp in randType :: {HampterLib.HampterTemplate} do
local prob = hampterTemp.Rarity.Probability
if prob > randNum and (not hampter or hampter.Rarity.Probability > prob or (hampter.Rarity.Probability == prob and math.random(0, 1) == 1)) then
hampter = hampterTemp
end
end
if not hampter then
randNum = math.random(1, 100 * 1000) / 1000
end
until hampter
return hampterFuncs.new(hampter)
end
--Methods
MT.Methods = {}
MT.__index = MT.Methods
function MT.Methods:Create(position: Vector3, parent: Instance?): MeshPart
local self = self :: Hampter
local mesh = AS:CreateMeshPartAsync(self.MeshId)
local click = Instance.new("ClickDetector")
local TweenFo = TweenInfo.new(2)
mesh.Anchored = true
mesh.Name = self.Name
mesh.Size = Vector3.new(self.Size, self.Size, self.Size)
mesh.Color = self.Color
mesh.Transparency = 1
mesh.Reflectance = self.Reflectance
mesh.Material = self.Material
if self.TextureID then mesh.TextureID = self.TextureID.Uri end
mesh.Position = position
mesh.Parent = parent or nil
--Tween In
local Sparks = Instance.new("Sparkles")
Sparks.SparkleColor = self.Color
Sparks.Parent = mesh
local TweenIn = TweenService:Create(mesh, TweenFo, {Transparency = self.Transparency})
TweenIn:Play()
task.wait(2)
mesh.Anchored = false
Sparks:Destroy()
click.Parent = mesh
task.spawn(function()
local isClicked = false
local eT = os.clock() + self.LifeSpan
if self.Special then task.spawn(self.Special(mesh)) end
click.MouseClick:Once(function()
isClicked = true
print(self.Price)
end)
while os.clock() < eT and not isClicked do task.wait() end
local Sound = Instance.new("Sound")
Sound.Parent = mesh
if not isClicked then
click:Destroy()
Sound.SoundId = "rbxassetid://8090403894"
local Smoke = Instance.new("Smoke")
Smoke.Color = self.Color
Smoke.Parent = mesh
while not Sound.IsLoaded do task.wait() end
local TweenOut = TweenService:Create(mesh, TweenFo, {Transparency = 1})
TweenOut:Play()
Sound:Play()
task.wait(2 + 0.5)
else
Sound.SoundId = "rbxassetid://8973091827"
while not Sound.IsLoaded do task.wait() end
Sound:Play()
task.wait(Sound.TimeLength + 0.5)
end
mesh:Destroy()
end)
return mesh
end
print("HampterFuncs Initialised!")
return hampterFuncs
Here are my main issues/concerns about my code:
- Module1 - the variants section seems fishy to me.
- Module1 - the crazy for loops which I still don’t know how to deal with.
- Module2 - ineffecient randomizer (in both of the constructors).
- Both - I feel like the type declarations could also be cleaned up as well.
Overall it works, but I believe there’s somehow a better way to do it. So if you have any insight/tip/anything, feel free to share .