Hello!
I’ve decided I would open-source a couple modules people might find useful which are included in my game
Let me know if you encounter any issues or have any questions with any of the modules.
Chat Fork
Main features:
- RichText in system messages (allows for fake speakers and just overall more customization)
- Coloured chat bubbles (the old ones) based on the player’s ChatColor, which comes from their ExtraData
- Text colour goes from black/white dynamically based on the saturation and value (you might have to mess around with it to get it to fit your liking, particularly lines 621-625 in the BubbleChat script)
- Text colour goes from black/white dynamically based on the saturation and value (you might have to mess around with it to get it to fit your liking, particularly lines 621-625 in the BubbleChat script)
- Easy to implement command usage
- Fake command bot for successful and unsuccessful command usage
local fakeCommandBot = require(commandModules.FakeServerBot) fakeCommandBot:CreateUnsuccessfulMessage('Oh no, the command failed!') fakeCommandBot:CreateSuccessfulMessage('Yay, the command worked!')
Get the chat fork here:
CDCOChat.rbxm (119.1 KB)
String/number utility module:
local module = {
['Lerp'] = function(self, lBound, uBound, alpha) -- linear interpolation
return lBound + (uBound - lBound) * alpha
end;
['Round'] = function(self, number) -- kinda redundant now that we have math.round but I wrote this function probably back in May
if type(number) == 'number' then
return math.floor(number + 0.5)
else
return number
end
end;
['RoundToThousandth'] = function(self, number) -- self-explanatory
if type(number) == 'number' then
return self:Round(number * 1000) / 1000
else
return number
end
end;
['Abbreviations'] = {
'K';
'M';
'B';
'T';
'Q';
'Qn';
'Sx';
'Sp';
'O';
'N';
'D';
};
['FormatNumberToBeDisplayed'] = function(self, number: number, abbreviate: boolean) -- inserts commas or letters and abbreviates the number
number = type(number) == 'number' and number or tonumber(number)
assert(number, string.format('Invalid number entry: %s is type %s, expected number!', tostring(number), type(number)))
local numberIsToBeAbbreviated = number >= 1000000 and abbreviate
if numberIsToBeAbbreviated then
local logged = (math.floor(math.log10(number)))
local suffix = math.floor(logged / 3)
local mod = ((math.log10(number)) % 3) + 1
local stringNumber = tostring(number)
local preComma = stringNumber:sub(1,mod)
local postComma = stringNumber:sub(mod + 1, mod + 1)
return string.format('%s.%s%s+',preComma, postComma, self.Abbreviations[suffix])
else
local numberString = tostring(number)
local amountOfCommas = math.round(numberString:len() / 3)
local splitString = numberString:split('')
for i = numberString:len() - 2, 1, -3 do
if i ~= 1 then
table.insert(splitString, i, ',')
end
end
return table.concat(splitString)
end
end;
['StringPatterns'] = {
['Integer'] = function(str: string) -- removes any characters that aren't periods and numbers, then rounds the number
local subbed = str:gsub('[^%d%.]+', '')
print(subbed)
local numeric = tonumber(subbed)
if numeric then
return true, math.round(numeric)
end
return false
end;
['Number'] = function(str: string) -- removes non-numeric and non-period characters
local subbed = str:gsub('[^%d%.]+', '')
local numeric = tonumber(subbed)
if numeric then
return true, numeric
end
return false
end;
['Underscores'] = function(str: string) -- replaces non-whitespace characters with underscores (which I use for text that has yet to be filtered)
return true, str:gsub('[^%s]', '_')
end,
};
['FormatString'] = function(self, stringToBeFormatted, stringType) -- formats a string based on the type specified in the above table
if self.StringPatterns[stringType] then
local success, result = self.StringPatterns[stringType](stringToBeFormatted)
return success, result
end
return false
end;
['UTF8Sub'] = function(self, stringToSub, i, j) -- string.sub but a single grapheme is worth 1 character (ex, if I wanted to do string.sub('≠≠≠≠', 1, 3), it would return ≠ instead of ≠≠≠, UTF8Sub returns the expected ≠≠≠
local number = 0
local result = ''
for startOfGrapheme, endOfGrapheme in utf8.graphemes(stringToSub) do
number += 1
if math.clamp(number, i, j) == number then
result ..= stringToSub:sub(startOfGrapheme,endOfGrapheme)
end
if number == j then
break
end
end
return result
end;
}
return module


