Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8834269fee | ||
|
|
1fac678a79 | ||
|
|
97b9205954 |
No files matched your search
@@ -1,13 +1,16 @@
|
|||||||
# nasa-tawa
|
# nasa-tawa
|
||||||
Strange motion. Idle toy inspired by Progress Quest.
|
Strange motion. Idle toy inspired by Progress Quest.
|
||||||
|
|
||||||
|
WARNING: Opens a console to LAN which can run *any* code as the user Love2D is
|
||||||
|
running as! There is no security on this.
|
||||||
|
|
||||||
## Brainstroming
|
## Brainstroming
|
||||||
Name the Race. Motto.
|
Name the Race. Motto.
|
||||||
Level Class (xp bar)
|
Level Class (xp bar)
|
||||||
Plot: Description (progress bar)
|
Plot: Description (progress bar)
|
||||||
Quest (progress bar) (quest log?)
|
Quest (progress bar) (quest log?)
|
||||||
|
|
||||||
Stats: strength, constitution, dexterity, intelligence, wisdom, charisma, health/max, magic/max
|
Stats
|
||||||
|
|
||||||
Equipment list and stats.
|
Equipment list and stats.
|
||||||
Spell list and levels.
|
Spell list and levels.
|
||||||
@@ -42,8 +45,6 @@ Equipment is generated based on level, but random, so lots of downgrading.
|
|||||||
- SpecialItem: InterestingItem of ItemOfs
|
- SpecialItem: InterestingItem of ItemOfs
|
||||||
- InterestingItem: ItemAttrib Specials
|
- InterestingItem: ItemAttrib Specials
|
||||||
|
|
||||||
Only 100 quests are kept in the log.
|
|
||||||
|
|
||||||
special characters:
|
special characters:
|
||||||
- Demi, who does 1 backflip
|
- Demi, who does 1 backflip
|
||||||
- Anti Juandez, who is made-up
|
- Anti Juandez, who is made-up
|
||||||
@@ -70,7 +71,6 @@ Young, no modifiers, messianic, Big, Special.
|
|||||||
Quest completion triggers a reward: spell, equipment, stat, item
|
Quest completion triggers a reward: spell, equipment, stat, item
|
||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
- [x] Push the modifications to timer to the GitHub library!
|
|
||||||
- [ ] I have to make a stat called consider
|
- [ ] I have to make a stat called consider
|
||||||
- [ ] Progress bars should be set within a manager (like timers) so one global
|
- [ ] Progress bars should be set within a manager (like timers) so one global
|
||||||
draw function draws them all.
|
draw function draws them all.
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"Bastard Lunatic":{
|
||||||
|
"stats":["constitution"],
|
||||||
|
"tasks":[
|
||||||
|
[6, "Reading the DSM"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Battle-Felon":{
|
||||||
|
"stats":["strength"]
|
||||||
|
},
|
||||||
|
"Birdrider":{
|
||||||
|
"stats":["wisdom"],
|
||||||
|
"tasks":[
|
||||||
|
[10, "Birdwatching"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Fighter/Organist":{
|
||||||
|
"stats":["charisma","strength"]
|
||||||
|
},
|
||||||
|
"Hunter Strangler":{
|
||||||
|
"stats":["dexterity","intelligence"],
|
||||||
|
"tasks":[
|
||||||
|
[10, "Hunting"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Inner Mason":{
|
||||||
|
"stats":["constitution"],
|
||||||
|
"tasks":[
|
||||||
|
[16, "Meditating"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Lowling":{
|
||||||
|
"stats":["wisdom"],
|
||||||
|
"tasks":[
|
||||||
|
"Hiding"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Mage Illusioner":{
|
||||||
|
"stats":["intelligence","magic"]
|
||||||
|
},
|
||||||
|
"Mu-Fu Monk":{
|
||||||
|
"stats":["dexterity"]
|
||||||
|
},
|
||||||
|
"Puma Burgular":{
|
||||||
|
"stats":["dexterity"],
|
||||||
|
"tasks":[
|
||||||
|
[7, "Stalking"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Robot Monk":{
|
||||||
|
"stats":["strength"],
|
||||||
|
"tasks":[
|
||||||
|
[12, "Recharging"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Runeloremaster":{
|
||||||
|
"stats":["wisdom"],
|
||||||
|
"tasks":[
|
||||||
|
"Enthusiastically explaining the applications of runes on trains"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Shiv-Knight":{
|
||||||
|
"stats":["dexterity"],
|
||||||
|
"tasks":[
|
||||||
|
"Restocking on shivs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Slow Poisoner":{
|
||||||
|
"stats":["constitution"]
|
||||||
|
},
|
||||||
|
"Tickle-Mimic":{
|
||||||
|
"stats":["intelligence","wisdom"]
|
||||||
|
},
|
||||||
|
"Ur-Paladin":{
|
||||||
|
"stats":["constitution","wisdom"]
|
||||||
|
},
|
||||||
|
"Vermineer":{
|
||||||
|
"stats":["intelligence"],
|
||||||
|
"tasks":[
|
||||||
|
"Reading capitalist propaganda"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Voodoo Princess":{
|
||||||
|
"stats":["charisma","intelligence"]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
[
|
||||||
|
"Albert",
|
||||||
|
"Bad News",
|
||||||
|
"Bahh",
|
||||||
|
"Boing",
|
||||||
|
"Cellos",
|
||||||
|
"Daniel",
|
||||||
|
"Wobble",
|
||||||
|
"Eddy",
|
||||||
|
"Ellen",
|
||||||
|
"Flo",
|
||||||
|
"Fred",
|
||||||
|
"Good News",
|
||||||
|
"Grandma",
|
||||||
|
"Junior",
|
||||||
|
"Karen",
|
||||||
|
"Kathy",
|
||||||
|
"Moira",
|
||||||
|
"Organ",
|
||||||
|
"Superstar",
|
||||||
|
"Ralph",
|
||||||
|
"Reed",
|
||||||
|
"Rishi",
|
||||||
|
"Rocko",
|
||||||
|
"Samantha",
|
||||||
|
"Sandy",
|
||||||
|
"Shelley",
|
||||||
|
"Tara",
|
||||||
|
"Tessa",
|
||||||
|
"Trinoids",
|
||||||
|
"Whisper",
|
||||||
|
"Yelda",
|
||||||
|
"Zarvox"
|
||||||
|
]
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
"Battle-Finch":{
|
||||||
|
"stats":["dexterity","intelligence"],
|
||||||
|
"tasks":[
|
||||||
|
"Running from Birdrider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Crested Dwarf":{
|
||||||
|
"stats":["charisma"]
|
||||||
|
},
|
||||||
|
"Demicanadian":{
|
||||||
|
"stats":["constitution"],
|
||||||
|
"tasks":[
|
||||||
|
[2, "Drinking maple syrup"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Double Hobbit":{
|
||||||
|
"stats":["strength"]
|
||||||
|
},
|
||||||
|
"Double Wookiee":{
|
||||||
|
"stats":["strength"]
|
||||||
|
},
|
||||||
|
"Dung Elf":{
|
||||||
|
"stats":["wisdom"]
|
||||||
|
},
|
||||||
|
"Eel Man":{
|
||||||
|
"stats":["dexterity"]
|
||||||
|
},
|
||||||
|
"Enchanted Motorcycle":{
|
||||||
|
"stats":["magic"],
|
||||||
|
"tasks":[
|
||||||
|
[8, "Changing oil"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Gyrognome":{
|
||||||
|
"stats":["dexterity"],
|
||||||
|
"tasks":[
|
||||||
|
"Spinning"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Half Halfling":{
|
||||||
|
"stats":["dexterity"],
|
||||||
|
"tasks":[
|
||||||
|
"Protesting how someone renamed their race and then copyrighted it"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Half Man":{
|
||||||
|
"stats":["charisma"],
|
||||||
|
"tasks":[
|
||||||
|
"Searching for their other half"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Half Orc":{
|
||||||
|
"stats":["health"]
|
||||||
|
},
|
||||||
|
"Hob-Nobbit":{
|
||||||
|
"stats":["charisma","dexterity"],
|
||||||
|
"tasks":[
|
||||||
|
"Protesting how asburd it is for a dead human to own the concept of a race"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Land Squid":{
|
||||||
|
"stats":["health","strength"],
|
||||||
|
"tasks":[
|
||||||
|
"Drinking plenty of water"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Lesser Dwarf":{
|
||||||
|
"stats":["constitution"]
|
||||||
|
},
|
||||||
|
"Low Elf":{
|
||||||
|
"stats":["constitution"]
|
||||||
|
},
|
||||||
|
"Panda Man":{
|
||||||
|
"stats":["constitution","strength"]
|
||||||
|
},
|
||||||
|
"Skraeling":{
|
||||||
|
"stats":["wisdom"],
|
||||||
|
"tasks":[
|
||||||
|
[10, "Fighting for native peoples' rights"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Talking Pony":{
|
||||||
|
"stats":["intelligence","magic"],
|
||||||
|
"tasks":[
|
||||||
|
[4, "Singing their theme song"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Trans-Kobold":{
|
||||||
|
"stats":["wisdom"],
|
||||||
|
"tasks":[
|
||||||
|
[10, "#TransRights"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Will o' the Wisp":{
|
||||||
|
"stats":["wisdom"],
|
||||||
|
"tasks":[
|
||||||
|
"Looking for lamp oil"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
local constants = require "data.constants"
|
||||||
|
local utility = require "lib.utility"
|
||||||
|
|
||||||
|
local classes = utility.load_data("classes.json")
|
||||||
|
|
||||||
|
-- TODO abstract out since this is shared between classes and races
|
||||||
|
local class_names = {}
|
||||||
|
for name, data in pairs(classes) do
|
||||||
|
class_names[#class_names + 1] = name
|
||||||
|
|
||||||
|
if type(data.tasks) == "string" then
|
||||||
|
data.tasks = { data.tasks }
|
||||||
|
elseif not data.tasks then
|
||||||
|
data.tasks = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local tasks = data.tasks
|
||||||
|
for index, task in ipairs(tasks) do
|
||||||
|
if type(task) == "string" then
|
||||||
|
local time = #task * constants.reading_time_multiplier
|
||||||
|
-- TODO decide on a random amount of extra time to add
|
||||||
|
tasks[index] = {time, time, task}
|
||||||
|
elseif #task == 1 then
|
||||||
|
local time = #task[1] * constants.reading_time_multiplier
|
||||||
|
-- TODO decide on a random amount of extra time to add
|
||||||
|
tasks[index] = {time, time, task[1]}
|
||||||
|
elseif #task == 2 then
|
||||||
|
local time = tasks[1]
|
||||||
|
-- TODO decide on a random amount of extra time to add
|
||||||
|
tasks[index] = {time, time, task[2]}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(class_names)
|
||||||
|
|
||||||
|
return classes, class_names
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
return {
|
||||||
|
progress_bar_height = 30,
|
||||||
|
reading_time_multiplier = 1 / 12,
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
local constants = require "data.constants"
|
||||||
|
local utility = require "lib.utility"
|
||||||
|
|
||||||
|
local races = utility.load_data("races.json")
|
||||||
|
|
||||||
|
-- TODO abstract out since this is shared between classes and races
|
||||||
|
local race_names = {}
|
||||||
|
for name, data in pairs(races) do
|
||||||
|
race_names[#race_names + 1] = name
|
||||||
|
|
||||||
|
if type(data.tasks) == "string" then
|
||||||
|
data.tasks = { data.tasks }
|
||||||
|
elseif not data.tasks then
|
||||||
|
data.tasks = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local tasks = data.tasks
|
||||||
|
for index, task in ipairs(tasks) do
|
||||||
|
if type(task) == "string" then
|
||||||
|
local time = #task * constants.reading_time_multiplier
|
||||||
|
-- TODO decide on a random amount of extra time to add
|
||||||
|
tasks[index] = {time, time, task}
|
||||||
|
elseif #task == 1 then
|
||||||
|
local time = #task[1] * constants.reading_time_multiplier
|
||||||
|
-- TODO decide on a random amount of extra time to add
|
||||||
|
tasks[index] = {time, time, task[1]}
|
||||||
|
elseif #task == 2 then
|
||||||
|
local time = tasks[1]
|
||||||
|
-- TODO decide on a random amount of extra time to add
|
||||||
|
tasks[index] = {time, time, task[2]}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(race_names)
|
||||||
|
|
||||||
|
return races, race_names
|
||||||
+124
-21
@@ -1,3 +1,6 @@
|
|||||||
|
local window_width, window_height = love.graphics.getDimensions()
|
||||||
|
|
||||||
|
-- local filament = require "lib.filament"
|
||||||
local log = require "lib.log"
|
local log = require "lib.log"
|
||||||
local lovebird = require "lib.lovebird"
|
local lovebird = require "lib.lovebird"
|
||||||
local progress_bar = require "lib.progress_bar"
|
local progress_bar = require "lib.progress_bar"
|
||||||
@@ -7,23 +10,113 @@ local utility = require "lib.utility"
|
|||||||
lovebird.whitelist[#lovebird.whitelist + 1] = "192.168.*.*" -- LAN access
|
lovebird.whitelist[#lovebird.whitelist + 1] = "192.168.*.*" -- LAN access
|
||||||
|
|
||||||
log{
|
log{
|
||||||
testing = true,
|
debug = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- local json_load_test = utility.load_data("test.json")
|
local constants = require "data.constants"
|
||||||
-- utility.print_table(json_load_test)
|
local classes, class_names = require "data.classes"
|
||||||
|
local races, race_names = require "data.races"
|
||||||
|
|
||||||
|
local voices = utility.load_data("macos_say-en.json")
|
||||||
|
local voice_int = 0
|
||||||
|
local send_test_message = function()
|
||||||
|
-- local selected_voice = voices[math.random(1, #voices)]
|
||||||
|
voice_int = voice_int + 1
|
||||||
|
if voice_int > #voices then voice_int = 1 end
|
||||||
|
local selected_voice = voices[voice_int]
|
||||||
|
|
||||||
|
local test_channel = love.thread.getChannel("say")
|
||||||
|
local line = "Hello, my name is " .. selected_voice .. "."
|
||||||
|
test_channel:push({
|
||||||
|
voice = selected_voice:enquote(),
|
||||||
|
line = line:enquote(),
|
||||||
|
})
|
||||||
|
log("debug", selected_voice, line)
|
||||||
|
end
|
||||||
|
send_test_message()
|
||||||
|
|
||||||
|
-- filament.run(function()
|
||||||
|
-- local line = "Hello, my name is " .. selected_voice .. "."
|
||||||
|
-- os.execute("say -v " .. selected_voice:enquote() .. " " .. line:enquote())
|
||||||
|
-- end)
|
||||||
|
-- local test_thread = love.thread.newThread([[
|
||||||
|
-- -- local utility = require "lib.utility"
|
||||||
|
-- -- local voices = utility.load_data("macos_say-en.json")
|
||||||
|
-- -- local selected_voice = voices[math.random(1, #voices)]
|
||||||
|
-- local selected_voice = "Bells"
|
||||||
|
-- local line = "Hello, my name is " .. selected_voice .. "."
|
||||||
|
-- os.execute("say -v \"" .. selected_voice .. "\" \"" .. line .. "\"")
|
||||||
|
-- ]])
|
||||||
|
local test_thread = love.thread.newThread([[
|
||||||
|
local channel = love.thread.getChannel("say")
|
||||||
|
while true do
|
||||||
|
local message = channel:demand()
|
||||||
|
if message then
|
||||||
|
os.execute("say -v " .. message.voice .. " " .. message.line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
]])
|
||||||
|
test_thread:start()
|
||||||
|
|
||||||
|
local new_character = function(name)
|
||||||
|
local base_stat_roll = function()
|
||||||
|
return 3 + math.random(1, 6) + math.random(1, 6) + math.random(1, 6)
|
||||||
|
end
|
||||||
|
|
||||||
|
local random_name = function(length)
|
||||||
|
local vowels = "aaeeeiioouuy"
|
||||||
|
local consonants = "bcdfghjklmnpqrstvwxyz"
|
||||||
|
local text = ""
|
||||||
|
for i = 1, length do
|
||||||
|
local c
|
||||||
|
if i % 2 == 0 then
|
||||||
|
c = math.random(1, #vowels)
|
||||||
|
text = text .. vowels:sub(c, c)
|
||||||
|
else
|
||||||
|
c = math.random(1, #consonants)
|
||||||
|
text = text .. consonants:sub(c, c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
name = name or random_name(math.random(3, 9)) -- name not affected by seed
|
||||||
|
|
||||||
|
local seed = os.time()
|
||||||
|
math.randomseed(seed)
|
||||||
|
|
||||||
|
local character = {
|
||||||
|
seed = seed,
|
||||||
|
name = name,
|
||||||
|
race = race_names[math.random(1, #race_names)],
|
||||||
|
class = class_names[math.random(1, #class_names)],
|
||||||
|
charisma = base_stat_roll(),
|
||||||
|
constitution = base_stat_roll(),
|
||||||
|
dexterity = base_stat_roll(),
|
||||||
|
intelligence = base_stat_roll(),
|
||||||
|
strength = base_stat_roll(),
|
||||||
|
wisdom = base_stat_roll(),
|
||||||
|
level = 1,
|
||||||
|
experience = 0,
|
||||||
|
}
|
||||||
|
character.health = math.random(1, 8) + math.floor(character.constitution / 6)
|
||||||
|
character.magic = math.random(1, 8) + math.floor(character.intelligence / 6)
|
||||||
|
|
||||||
|
math.randomseed(os.time())
|
||||||
|
return character
|
||||||
|
end
|
||||||
|
|
||||||
|
-- for i = 1, 100 do
|
||||||
|
-- print(new_character())
|
||||||
|
-- end
|
||||||
|
-- os.exit(1)
|
||||||
|
|
||||||
-- test progress_bar
|
-- test progress_bar
|
||||||
local window_width, window_height = love.graphics.getDimensions()
|
local test_bar = progress_bar(0, window_height - constants.progress_bar_height * 2, window_width, constants.progress_bar_height)
|
||||||
local progress_bar_height = 30 -- TODO should not be hardcoded
|
|
||||||
local test_bar = progress_bar(0, window_height - progress_bar_height * 2, window_width, progress_bar_height)
|
|
||||||
|
|
||||||
local test_message = "This is a test text string of significant length. It exists to test printing over a progress bar."
|
local test_message = "This is a test text string of significant length. It exists to test printing over a progress bar."
|
||||||
log("testing", #test_message)
|
|
||||||
test_bar:set_text(test_message)
|
test_bar:set_text(test_message)
|
||||||
-- test:set_progress(math.random())
|
|
||||||
|
|
||||||
local test_timer = timer.every(#test_message / 12, function() log("testing", "The timer completed.") end) -- TODO consider making timer not need a function; cause I don't here!
|
local test_timer = timer.every(#test_message * constants.reading_time_multiplier, function() log("debug", "The timer completed.") end) -- TODO consider making timer not need a function; cause I don't here!
|
||||||
|
|
||||||
local task_queue
|
local task_queue
|
||||||
task_queue = {
|
task_queue = {
|
||||||
@@ -32,34 +125,44 @@ task_queue = {
|
|||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
local total_pages = 500
|
|
||||||
local current_page = 0
|
|
||||||
local pages_progress_bar = progress_bar(0, window_height - progress_bar_height, window_width, progress_bar_height, total_pages / current_page)
|
local book = utility.load_data("book.json")
|
||||||
local update_pages_progress_bar = function(increment)
|
local book_progress = progress_bar(0, window_height - constants.progress_bar_height, window_width, constants.progress_bar_height)
|
||||||
current_page = current_page + (increment or 0)
|
local update_book_progress = function(increment)
|
||||||
pages_progress_bar:set_progress(current_page / total_pages)
|
book.current_page = book.current_page + (increment or 0)
|
||||||
pages_progress_bar:set_text("Reading: Page " .. current_page .. "/" .. total_pages .. " (" .. math.floor(current_page / total_pages * 100 * 10) / 10 .. "%)")
|
book_progress:set_progress(book.current_page / book.total_pages)
|
||||||
|
book_progress:set_text("Reading: Page " .. book.current_page .. "/" .. book.total_pages .. " (" .. math.floor(book.current_page / book.total_pages * 100 * 10) / 10 .. "%)")
|
||||||
end
|
end
|
||||||
update_pages_progress_bar()
|
update_book_progress()
|
||||||
|
|
||||||
love.update = function(dt)
|
love.update = function(dt)
|
||||||
lovebird.update()
|
lovebird.update()
|
||||||
timer.update(dt)
|
timer.update(dt)
|
||||||
|
|
||||||
test_bar:set_progress(test_timer.run_time / test_timer:get_interval())
|
test_bar:set_progress(test_timer.run_time / test_timer:get_interval())
|
||||||
|
local thread_error = test_thread:getError()
|
||||||
|
if thread_error then
|
||||||
|
log("debug", thread_error)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
love.draw = function()
|
love.draw = function()
|
||||||
test_bar:draw()
|
test_bar:draw()
|
||||||
pages_progress_bar:draw()
|
|
||||||
|
book_progress:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
love.keypressed = function(key)
|
love.keypressed = function(key)
|
||||||
if key == "escape" then
|
if key == "escape" then
|
||||||
-- TODO save any remaining log
|
-- TODO save any remaining log
|
||||||
|
utility.save_data(book)
|
||||||
love.event.quit()
|
love.event.quit()
|
||||||
elseif key == "left" then
|
elseif key == "left" then
|
||||||
update_pages_progress_bar(-1)
|
update_book_progress(-1)
|
||||||
elseif key == "right" then
|
elseif key == "right" then
|
||||||
update_pages_progress_bar(1)
|
update_book_progress(1)
|
||||||
|
elseif key == "v" then
|
||||||
|
send_test_message()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Reference in new issue
Block a user