Compare commits

...
12 Commits
Author SHA1 Message Date
tangent 5c592d5010 end state of first stream 2026-09-29 03:48:59 -06:00
tangent 55c565845b pre-stream state, ready to go for temporary version 2026-09-29 03:48:41 -06:00
tangent 4209ad2618 I forgot to commit changes a few days ago? 2026-09-28 23:14:51 -06:00
tangent 7b8e45b6be extracted character code 2026-09-26 21:38:11 -06:00
tangent a0ea5d71c5 labeling temporary code 2026-09-26 21:33:31 -06:00
tangent 68d9bec872 tiles can be drawn now 2026-09-26 21:29:19 -06:00
tangent a96b58adf2 fuck macOS 2026-09-26 21:09:52 -06:00
tangent 1f9c0c527a reorganization 2026-09-26 21:09:45 -06:00
tangent 3498275bf0 PQ name gen, level up
I got interrupted while doing this days ago and forgot to commit
2026-09-26 21:05:33 -06:00
tangent 83b6ba1f72 abstracted data loading better 2026-09-22 21:30:05 -06:00
tangent d176ef90f8 say in own library 2026-09-22 21:19:18 -06:00
tangent e40ffb91da testing character creation 2026-09-22 21:03:45 -06:00
15 changed files with 300 additions and 174 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
.DS_Store
+10
View File
@@ -4,6 +4,8 @@ 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.
Tileset from [OpenGameArt.org](https://opengameart.org/content/dungeon-crawl-32x32-tiles).
## Brainstroming
Name the Race. Motto.
Level Class (xp bar)
@@ -50,6 +52,14 @@ special characters:
- Anti Juandez, who is made-up
- Zargon
I want exploration, generated or discovered areas. And a map.
- [ ] fishing
- [ ] Sims elements / life sim elements
- [ ] mining
- [ ] construction
- [ ] agriculture
###### Prefixes
Sick modifiers: dead, comatose, crippled, sick, undernourished
Young: foetal, baby, preadolescent, teenage, underage
+1 -1
View File
@@ -53,7 +53,7 @@
[12, "Recharging"]
]
},
"Runeloremaster":{
"Rune-Lore Master":{
"stats":["wisdom"],
"tasks":[
"Enthusiastically explaining the applications of runes on trains"
+42
View File
@@ -0,0 +1,42 @@
{
"cthulhu":{
"x":23,
"y":6
},
"grass":{
"x":56,
"y":15
},
"kobold_female_green":{
"x":50,
"y":31
},
"orc_male":{
"x":40,
"y":32
},
"stick":{
"x":64,
"y":46
},
"tent":{
"x":4,
"y":22
},
"todo":{
"x":64,
"y":1
},
"tree":{
"x":13,
"y":19
},
"machine":{
"x":56,
"y":16
},
"centaur_female_brown":{
"x":22,
"y":31
}
}
File renamed without changes.
+4
View File
@@ -51,6 +51,7 @@
]
},
"Half Orc":{
"icon":"orc_male",
"stats":["health"]
},
"Hob-Nobbit":{
@@ -60,6 +61,7 @@
]
},
"Land Squid":{
"icon":"cthulhu",
"stats":["health","strength"],
"tasks":[
"Drinking plenty of water"
@@ -81,12 +83,14 @@
]
},
"Talking Pony":{
"icon":"centaur_female_brown",
"stats":["intelligence","magic"],
"tasks":[
[4, "Singing their theme song"]
]
},
"Trans-Kobold":{
"icon":"kobold_female_green",
"stats":["wisdom"],
"tasks":[
[10, "#TransRights"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

+2 -2
View File
@@ -1,4 +1,4 @@
{
"current_page":0,
"total_pages":500
"current_page":147,
"total_pages":449
}
+2 -33
View File
@@ -1,37 +1,6 @@
local constants = require "data.constants"
local utility = require "lib.utility"
local classes = utility.load_data("classes.json")
local classes = utility.load_data("./assets/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
return constants.fix_stats_tasks(classes)
+42 -2
View File
@@ -1,4 +1,44 @@
return {
local utility = require "lib.utility"
local constants = {
progress_bar_height = 30,
reading_time_multiplier = 1 / 12,
reading_time_multiplier = 1 / 9,
tile_size = 32,
}
constants.fix_stats_tasks = function(data)
local result = {}
for name, data in pairs(data) do
result[name] = data
result[#result + 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(result)
return result
end
return constants
+21
View File
@@ -0,0 +1,21 @@
local constants = require "data.constants"
local utility = require "lib.utility"
local file = io.open("./assets/tileset.png", "rb")
local raw_data = file:read("*all")
file:close()
local file_data = love.filesystem.newFileData(raw_data, "./assets/tileset.png")
local love_image = love.graphics.newImage(file_data)
local tile_data = utility.load_data("./assets/images.json")
local images = {
love_image = love_image,
}
for name, data in pairs(tile_data) do
images[name] = love.graphics.newQuad( (data.x - 1) * constants.tile_size, (data.y - 1) * constants.tile_size, constants.tile_size, constants.tile_size, love_image )
end
return images
+2 -33
View File
@@ -1,37 +1,6 @@
local constants = require "data.constants"
local utility = require "lib.utility"
local races = utility.load_data("races.json")
local races = utility.load_data("./assets/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
return constants.fix_stats_tasks(races)
+109
View File
@@ -0,0 +1,109 @@
local classes = require "data.classes"
local constants = require "data.constants"
local images = require "data.images"
local races = require "data.races"
local characters = {}
local base_stat_roll = function()
return 3 + math.random(1, 6) + math.random(1, 6) + math.random(1, 6)
end
local naive_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
local progress_quest_random_name = function()
local parts = {
("br|cr|dr|fr|gr|j|kr|l|m|n|pr||||r|sh|tr|v|wh|x|y|z"):split("|"),
("a|a|e|e|i|i|o|o|u|u|ae|ie|oo|ou"):split("|"),
("b|ck|d|g|k|m|n|p|t|v|x|z"):split("|"),
}
local name = ""
for i = 0, 5 do
local part = parts[i % 3 + 1]
name = name .. part[math.random(1, #part)]
end
return name
end
local random_stat_up = function(character)
local core_stats = {
"charisma", "constitution", "dexterity", "intelligence", "strength", "wisdom",
}
local selected_stat = core_stats[math.random(1, #core_stats)]
character[selected_stat] = character[selected_stat] + 1
end
characters.new = function(name)
name = name or progress_quest_random_name() -- name not affected by seed
local seed = math.random()
math.randomseed(seed)
local character = {
seed = seed,
name = name,
race = races[math.random(1, #races)],
class = classes[math.random(1, #classes)],
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)
for _, stat_name in ipairs(races[character.race].stats) do
character[stat_name] = character[stat_name] + math.random(1, 3)
end
for _, stat_name in ipairs(classes[character.class].stats) do
character[stat_name] = character[stat_name] + math.random(1, 3)
end
character.max_encumberance = character.strength + 10
character.inventory = {}
character.x = 1
character.y = 1
return setmetatable(character, { __index = characters, })
end
characters.level_up = function(character)
character.health = character.health + 1 + math.floor(character.constitution / 3) + math.random(1, 4)
character.magic = character.magic + 1 + math.floor(character.intelligence / 3) + math.random(1, 4)
random_stat_up(character)
random_stat_up(character)
character.max_encumberance = character.strength + 10
-- TODO this is where a spell could be added, and
end
characters.draw = function(self)
local icon = races[self.race].icon or "todo"
love.graphics.draw(images.love_image, images[icon], self.x * constants.tile_size, self.y * constants.tile_size)
end
return characters
+36
View File
@@ -0,0 +1,36 @@
local log = require "lib.log"
local utility = require "lib.utility"
local voices = utility.load_data("./assets/macos_say-en.json")
local say_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
]])
say_thread:start()
return setmetatable({
update = function()
local thread_error = say_thread:getError()
if thread_error then
log("error", thread_error)
end
end,
}, {
__call = function(self, line)
local selected_voice = voices[math.random(1, #voices)]
local say_channel = love.thread.getChannel("say")
line = line or "Hello, my name is " .. selected_voice .. "."
say_channel:push({
voice = selected_voice:enquote(),
line = line:enquote(),
})
log("say", selected_voice, line)
end,
})
+28 -103
View File
@@ -1,123 +1,45 @@
local window_width, window_height = love.graphics.getDimensions()
-- local filament = require "lib.filament"
local characters = require "lib.characters"
local log = require "lib.log"
local lovebird = require "lib.lovebird"
local macOS_say = require "lib.macOS_say"
local progress_bar = require "lib.progress_bar"
local timer = require "lib.timer"
local utility = require "lib.utility"
lovebird.whitelist[#lovebird.whitelist + 1] = "192.168.*.*" -- LAN access
lovebird.whitelist[#lovebird.whitelist + 1] = "192.168.*.*" -- WARNING LAN has full user access through this
log{
debug = true,
error = true,
say = true,
}
local constants = require "data.constants"
local classes, class_names = require "data.classes"
local races, race_names = require "data.races"
local images = require "data.images"
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())
-- TEMP
local test_new_character = function()
local character = characters.new()
local message = "My name is " .. character.name .. ", and I am a " .. character.class .. " " .. character.race .. "!"
macOS_say(message)
return character
end
local test_character = test_new_character()
-- for i = 1, 100 do
-- print(new_character())
-- end
-- os.exit(1)
-- test progress_bar
-- TEMP test progress_bar
local test_bar = progress_bar(0, window_height - constants.progress_bar_height * 2, window_width, constants.progress_bar_height)
local test_message = "This is a test text string of significant length. It exists to test printing over a progress bar."
test_bar:set_text(test_message)
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 test_timer = timer.every(#test_message * constants.reading_time_multiplier, function()
-- macOS_say(test_message)
end)
-- I started this too soon and it needs deletion or massive change
local task_queue
task_queue = {
pending_tasks = {},
@@ -140,15 +62,16 @@ love.update = function(dt)
lovebird.update()
timer.update(dt)
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
test_bar:set_progress(test_timer.run_time / test_timer:get_interval()) -- TEMP
macOS_say:update()
end
love.draw = function()
test_bar:draw()
love.graphics.draw(images.love_image, images.grass, 50, 50) -- TEMP
love.graphics.draw(images.love_image, images.centaur_female_brown, 50, 50) -- TEMP
test_character:draw() -- TEMP
-- test_bar:draw() -- TEMP
book_progress:draw()
end
@@ -162,7 +85,9 @@ love.keypressed = function(key)
update_book_progress(-1)
elseif key == "right" then
update_book_progress(1)
elseif key == "v" then
send_test_message()
elseif key == "v" then -- TEMP testing voices
macOS_say()
elseif key == "c" then -- TEMP gen character and say introduction
test_new_character()
end
end