Compare commits

..
15 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
tangent 8834269fee testing with voices! 2026-09-22 20:36:03 -06:00
tangent 1fac678a79 progress towards character creation 2026-09-22 19:59:54 -06:00
tangent 97b9205954 starting to add data 2026-09-22 19:07:39 -06:00
15 changed files with 560 additions and 28 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
.DS_Store
+14 -4
View File
@@ -1,13 +1,18 @@
# 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.
Tileset from [OpenGameArt.org](https://opengameart.org/content/dungeon-crawl-32x32-tiles).
## 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,13 +47,19 @@ 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
- Zargon - Zargon
I want exploration, generated or discovered areas. And a map.
- [ ] fishing
- [ ] Sims elements / life sim elements
- [ ] mining
- [ ] construction
- [ ] agriculture
###### Prefixes ###### Prefixes
Sick modifiers: dead, comatose, crippled, sick, undernourished Sick modifiers: dead, comatose, crippled, sick, undernourished
Young: foetal, baby, preadolescent, teenage, underage Young: foetal, baby, preadolescent, teenage, underage
@@ -70,7 +81,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.
+86
View File
@@ -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"]
]
},
"Rune-Lore Master":{
"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"]
}
}
+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
}
}
+34
View File
@@ -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"
]
+105
View File
@@ -0,0 +1,105 @@
{
"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":{
"icon":"orc_male",
"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":{
"icon":"cthulhu",
"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":{
"icon":"centaur_female_brown",
"stats":["intelligence","magic"],
"tasks":[
[4, "Singing their theme song"]
]
},
"Trans-Kobold":{
"icon":"kobold_female_green",
"stats":["wisdom"],
"tasks":[
[10, "#TransRights"]
]
},
"Will o' the Wisp":{
"stats":["wisdom"],
"tasks":[
"Looking for lamp oil"
]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

+4
View File
@@ -0,0 +1,4 @@
{
"current_page":147,
"total_pages":449
}
+6
View File
@@ -0,0 +1,6 @@
local constants = require "data.constants"
local utility = require "lib.utility"
local classes = utility.load_data("./assets/classes.json")
return constants.fix_stats_tasks(classes)
+44
View File
@@ -0,0 +1,44 @@
local utility = require "lib.utility"
local constants = {
progress_bar_height = 30,
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
+6
View File
@@ -0,0 +1,6 @@
local constants = require "data.constants"
local utility = require "lib.utility"
local races = utility.load_data("./assets/races.json")
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,
})
+52 -24
View File
@@ -1,30 +1,45 @@
local window_width, window_height = love.graphics.getDimensions()
local characters = require "lib.characters"
local log = require "lib.log" local log = require "lib.log"
local lovebird = require "lib.lovebird" local lovebird = require "lib.lovebird"
local macOS_say = require "lib.macOS_say"
local progress_bar = require "lib.progress_bar" local progress_bar = require "lib.progress_bar"
local timer = require "lib.timer" local timer = require "lib.timer"
local utility = require "lib.utility" 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{ log{
testing = true, debug = true,
error = true,
say = true,
} }
-- local json_load_test = utility.load_data("test.json") local constants = require "data.constants"
-- utility.print_table(json_load_test) local images = require "data.images"
-- test progress_bar
local window_width, window_height = love.graphics.getDimensions()
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)
-- 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()
-- 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." 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()
-- macOS_say(test_message)
end)
-- I started this too soon and it needs deletion or massive change
local task_queue local task_queue
task_queue = { task_queue = {
pending_tasks = {}, pending_tasks = {},
@@ -32,34 +47,47 @@ 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()) -- TEMP
macOS_say:update()
end end
love.draw = function() love.draw = function()
test_bar:draw() love.graphics.draw(images.love_image, images.grass, 50, 50) -- TEMP
pages_progress_bar:draw() 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 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 -- TEMP testing voices
macOS_say()
elseif key == "c" then -- TEMP gen character and say introduction
test_new_character()
end end
end end