local HEAD_PART = models.model.root .Head --model part of the head (this gets scaled) local DIALOG_NOISE_NAME = "dialog" --audio name for the undertale-y/animal crossing-y sounds local SPEAK_BIND = keybinds:newKeybind("SpeakText", "key.keyboard.h", false) --Keybind for manually removing/starting the text local SPEAKING_SPEED = 1.5 --ticks per character local is_showing_text = false local dialog_noise = sounds[DIALOG_NOISE_NAME] local text_to_speak = "{test text, this gets replaced when actual text gets typed}" if (models.model.BILLBOARD) then --There is a billboard else print( "NO BILLBOARD IN MODEL. ADD A 'BILLBOARD' FOLDER TO YOUR MAIN MODEL.BBMODEL FILE. IT MUST BE EMPTY (OR NOT, but the code does change the pivot of the billboard)") end models.model.BILLBOARD:setPivot(0,50,0) local SpeakTextTask = models.model.BILLBOARD:newText("SpeakTextTask") SpeakTextTask:setAlignment("CENTER"):setScale(0.5) -- SpeakTextTask:setBackground(true) -- SpeakTextTask:setBackgroundColor(255 / 255, 20 / 255, 255 / 255, 50 / 255) SpeakTextTask:setOutline(true) --SpeakTextTask:setOutlineColor(140 / 255, 20 / 255, 200 / 255) SpeakTextTask:setOutlineColor(0.4,0,0.6) SpeakTextTask:setWidth(250) SpeakTextTask:setSeeThrough(true) local starting_speaking_tick = 0 local tick_counter = 0 function events.tick() tick_counter = tick_counter + 1 if is_showing_text then current_max_character = math.floor((tick_counter - starting_speaking_tick) / SPEAKING_SPEED) if current_max_character <= #text_to_speak then SpeakTextTask:setText(string.sub(text_to_speak, 1, math.min(current_max_character, #text_to_speak))) HEAD_PART:setScale(((math.sin(tick_counter * 2 + 1) + 1) / 30) + 0.9, ((math.sin(tick_counter * 2) + 1) / 17) + 0.9, 1) if dialog_noise:isPlaying() == false and math.random() > 0.3 then dialog_noise:play():setPos(player:getPos()):setPitch((math.random() * 0.5) + 0.75) end SpeakTextTask:setRot(0, 0, ((math.sin(tick_counter * 0.5 + 30)) * 2)):setScale((((math.sin(tick_counter * 1 + 14) + 1) / 30) + 0.9) * 0.5) else SpeakTextTask:setScale(0.5) SpeakTextTask:setRot(0, 0, ((math.sin(tick_counter * 0.2 + 30)) * 1)) end local blockLight = world.getLightLevel(player:getPos()) local skyLight = world.getSkyLightLevel(player:getPos()) SpeakTextTask:setLight(math.max(blockLight, 5), skyLight) if (current_max_character - #text_to_speak) * SPEAKING_SPEED > 300 then is_showing_text = false SpeakTextTask:setVisible(false) SpeakTextTask:setText("") end end end local word_list = { -- Red fuck = {color = "§c"}, shit = {color = "§c"}, goddamn = {color = "§c"}, danger = {color = "§c"}, warning = {color = "§c"}, -- Green clipboard = {color = "§a"}, success = {color = "§a"}, enabled = {color = "§a"}, online = {color = "§a"}, -- Light Purple sylva = {color = "§d"}, figura = {color = "§d"}, amethyst = {color = "§d"}, magic = {color = "§d"}, mystical = {color = "§d"}, -- Gold minecraft = {color = "§6"}, legendary = {color = "§6"}, boss = {color = "§6"}, rare = {color = "§6"}, -- Aqua water = {color = "§b"}, ocean = {color = "§b"}, sky = {color = "§b"}, -- Blue ice = {color = "§9"}, frost = {color = "§9"}, -- Yellow gold = {color = "§e"}, sun = {color = "§e"}, bright = {color = "§e"}, trans = {text = "§bt§dr§fa§dn§bs"}, rainbow = {text = "§cr§6a§ei§an§bb§do§cw"}, rainbows = {text = "§cr§6a§ei§an§bb§do§cw§6s"}, doglitch={text="§kglitchy§r"} } basic_text = "§f" local function text_colorifier(text) return text:gsub("%f[%a](%a+)%f[%A]", function(word) local data = word_list[word:lower()] if not data then return word end if data.color then return data.color .. word .. basic_text end return data.text .. basic_text end) end function pings.start_text(text_func) starting_speaking_tick = tick_counter text_to_speak = text_colorifier(text_func) is_showing_text = true SpeakTextTask:setText("") SpeakTextTask:setVisible(true) end function pings.stop_text() is_showing_text = false SpeakTextTask:setVisible(false) SpeakTextTask:setText("") end function events.chat_send_message(msg) pings.start_text(msg) return msg --return nil --Used for if you don't want chat messages to be sent. end local function speak_text() if is_showing_text == false then pings.start_text(host:getClipboard()) else pings.stop_text() end end SPEAK_BIND:setOnPress(speak_text)