From 17da5c2b81f86bece26bfa26bc0b519b4e5ba756 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Thu, 26 Dec 2024 19:40:33 +1100 Subject: [PATCH 01/31] docs: update todo --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fd299b8..06684ef 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,6 @@ Actions - [x] delete to pickup - [x] insert floor on delete - [x] enemies drop loot -- [ ] use registers for inventory - [ ] visuals - [ ] nerd font chars - [ ] animate cursor @@ -111,6 +110,9 @@ Actions - [x] an entity stat for sneakability - [x] yank - search, works in combination with sneaking - [ ] jumplist - ??? + - [ ] use registers for inventory + - [ ] insert to run actions + - [ ] macros - [x] varied entities - [x] item and enemy generation from dictionary - [x] item and enemy variations with different colours From ff06158ff47b2d12d33862b2383151a2b30416c1 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Thu, 26 Dec 2024 19:48:07 +1100 Subject: [PATCH 02/31] feat: add explicit drop action, overwrites if you drop multiple --- lua/neohack/actions.lua | 15 ++++++++++++++- lua/neohack/player.lua | 12 ++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index c4502a5..53e303c 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -75,6 +75,18 @@ M.eat = function() end, 50) end +---comment +M.drop = function() + message.notify("You have:\n" .. player.get_inventory_item_with_index()) + vim.defer_fn(function() + local index = M.prompt("Drop what?") + if index then + player.drop(utils.strings_to_ints(index)) + M.tick() + end + end, 50) +end + ---comment M.say = function() vim.defer_fn(function() @@ -114,7 +126,7 @@ M.help = function() .. M.leader_key .. "' " .. "Actions: " - .. "i to show inventory, w to wear, k to kick, f to fuse, l to look, e to eat, s to say, to wait, ? for help" + .. "i to show inventory, w to wear, k to kick, f to fuse, l to look, e to eat, s to say, d to drop, to wait, ? for help" ) end @@ -136,6 +148,7 @@ M.setup = function(bufnr, tick) map("f", M.fuse, "fuse") map("l", M.look, "look") map("e", M.eat, "eat") + map("d", M.drop, "drop") map("s", M.say, "say") map(" ", M.wait, "wait") map("?", M.help, "help") diff --git a/lua/neohack/player.lua b/lua/neohack/player.lua index 5790f6d..ce84333 100644 --- a/lua/neohack/player.lua +++ b/lua/neohack/player.lua @@ -392,6 +392,18 @@ M.eat = function(indexes) end end +M.drop = function(indexes) + local items = M.retrieve_item_indexes(indexes) + if not items then + return + end + local row, col = buffer.get_under_cursor() + for _, item in ipairs(items) do + -- TODO: allow drop without overwrite + buffer.set_entity_at_cell(row, col, item) + end +end + ---comment ---@param mover Entity M.dodge = function(mover) From 69377ce5f61b578d4e9f9f0c32f68972ba7b8afd Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Thu, 26 Dec 2024 20:48:55 +1100 Subject: [PATCH 03/31] wip: store inserted text as it's entered, then handle_changed on every tick --- lua/neohack/buffer.lua | 6 ++--- lua/neohack/edits.lua | 58 +++++++++++++++++++++++++++--------------- lua/neohack/event.lua | 3 +++ lua/neohack/game.lua | 3 +++ lua/neohack/player.lua | 1 + lua/neohack/state.lua | 3 +++ 6 files changed, 51 insertions(+), 23 deletions(-) diff --git a/lua/neohack/buffer.lua b/lua/neohack/buffer.lua index 659728d..17353c3 100644 --- a/lua/neohack/buffer.lua +++ b/lua/neohack/buffer.lua @@ -132,9 +132,9 @@ M.add_insert_handlers = function(bufnr) buffer = bufnr, callback = function() M.buffers[bufnr].handle_insert() - vim.schedule(function() - M.write_buf(bufnr) - end) + -- vim.schedule(function() + -- M.write_buf(bufnr) + -- end) end, }) end diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index c6a4065..3208890 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -9,33 +9,51 @@ local map = require("neohack.map") local state = require("neohack.state") local utils = require("neohack.utils") local chance = require("neohack.chance") +local event = require("neohack.event") ---comment ---@param char string M.handle_insert = function(char) - -- using inventory happens outside the tick -- message.notify("handle_insert '" .. char .. "'") + -- just store the text as it's inserted + state.inserted = state.inserted .. char - local row, col = buffer.get_under_cursor() - if char ~= defs.floor.char then - local entity = player.retrieve_item_char(char) - if not entity then - -- undo the insert - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", true, false, true), "n", true) - -- not in inventory so overwrite it - -- so force undo the entire change - -- vim.api.nvim_input("u") ends up eating the item - -- vim.cmd("undo") -- activates cmp - -- vim.cmd("normal! u") - -- -- local backspace_key = vim.api.nvim_replace_termcodes("", true, false, true) - -- -- vim.api.nvim_feedkeys(backspace_key, "i", true) - -- vim.cmd("normal! a") -- stay in insert - else - buffer.insert_entity_at_cell(row, col, entity) + -- local row, col = buffer.get_under_cursor() + -- if char ~= defs.floor.char then + -- local entity = player.retrieve_item_char(char) + -- if not entity then + -- -- undo the insert + -- vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", true, false, true), "n", true) + -- -- not in inventory so overwrite it + -- -- so force undo the entire change + -- -- vim.api.nvim_input("u") ends up eating the item + -- -- vim.cmd("undo") -- activates cmp + -- -- vim.cmd("normal! u") + -- -- -- local backspace_key = vim.api.nvim_replace_termcodes("", true, false, true) + -- -- -- vim.api.nvim_feedkeys(backspace_key, "i", true) + -- -- vim.cmd("normal! a") -- stay in insert + -- else + -- buffer.insert_entity_at_cell(row, col, entity) + -- end + -- else + -- -- you can always drop some floor?? + -- buffer.insert_entity_at_cell(row, col, defs.new_floor(row, col)) + -- end +end + +M.handle_inserted = function() + local inserted_chars = state.inserted + state.inserted = "" + if #inserted_chars > 0 then + -- reset cursor position before performing any action + buffer.move_prev_cursor() + + vim.fn.setreg('"', "") + if inserted_chars:sub(1, 1) == "k" then + local dir = inserted_chars:sub(2, 2) + -- message.notify("kicked " .. dir) + event.kick(dir) end - else - -- you can always drop some floor?? - buffer.insert_entity_at_cell(row, col, defs.new_floor(row, col)) end end diff --git a/lua/neohack/event.lua b/lua/neohack/event.lua index 85ce6c1..b9c057f 100644 --- a/lua/neohack/event.lua +++ b/lua/neohack/event.lua @@ -218,6 +218,9 @@ end ---@param direction string hjkl M.kick = function(direction) local move = Move.directions[direction] + if move == nil then + return + end local player_row, player_col = buffer.get_under_cursor() local kick_row, kick_col = player_row + move.row, player_col + move.col local target = buffer.get_entity_at_pos(kick_row, kick_col) diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index cf0ed97..725eaac 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -141,12 +141,15 @@ M.tick = function() -- vim.api.nvim_buf_add_highlight(M.bufnr, vim.api.nvim_create_namespace("NeoHack"), "NeoHackHit", 0, 0, 10) buffer.tick(function() state.turn_counter = state.turn_counter + 1 + -- message.notify("tick") tick_timer.on_tick() -- detect deleted on every turn state.deleted = map.find_deleted(state.current_bufnr) + edits.handle_inserted() + event.player_move() event.move_enemies() diff --git a/lua/neohack/player.lua b/lua/neohack/player.lua index ce84333..4a1fe68 100644 --- a/lua/neohack/player.lua +++ b/lua/neohack/player.lua @@ -81,6 +81,7 @@ M.player_hit_move = function() end M.store_previous_position = function() + -- message.notify("store prev position") local prevRow, prevCol = unpack(vim.api.nvim_win_get_cursor(0)) state.prev_cursor = { row = prevRow, col = prevCol + 1 } end diff --git a/lua/neohack/state.lua b/lua/neohack/state.lua index df884d3..00f1a6b 100644 --- a/lua/neohack/state.lua +++ b/lua/neohack/state.lua @@ -55,6 +55,9 @@ local M = { ---@type Entity[] deleted = nil, + ---@type string + inserted = "", + --- previous player corpse corpse = { ---@type integer From 9453e87b31dd636c713e7d3bcb4df42d76df70ab Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Thu, 26 Dec 2024 21:41:18 +1100 Subject: [PATCH 04/31] wip: actions work via key prompt, or inserting text --- lua/neohack/actions.lua | 177 +++++++++++++++++++++++++++------------- lua/neohack/edits.lua | 8 +- lua/neohack/event.lua | 13 +-- lua/neohack/game.lua | 2 +- lua/neohack/utils.lua | 6 +- 5 files changed, 132 insertions(+), 74 deletions(-) diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index 53e303c..09ab0ed 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -9,125 +9,186 @@ local event = require("neohack.event") local state = require("neohack.state") local utils = require("neohack.utils") ----comment -M.inventory = function() - message.notify("Level " .. state.current_level .. " " .. player.show_inventory()) -end +M.actions = { + ---comment + inventory = function() + message.notify("Level " .. state.current_level .. " " .. player.show_inventory()) + end, + + ---comment + kick = function(words) + event.kick(words[1]) + M.tick() + end, + + ---comment + wear = function(words) + local slot = table.remove(words, 1) + local index = utils.string_to_int(words[1]) + if index then + --- TODO: actions take indexes, which is weird to insert + player.wear(slot, index) + end + end, + + ---comment + fuse = function(words) + player.fuse(utils.strings_to_ints(words)) + M.tick() + end, + + ---comment + look = function(words) + player.look(utils.strings_to_ints(words)) + end, + + ---comment + eat = function(words) + player.eat(utils.strings_to_ints(words)) + M.tick() + end, + + ---comment + drop = function(words) + player.drop(utils.strings_to_ints(words)) + M.tick() + end, + + ---comment + say = function(words) + event.say(words) + M.tick() + end, + + ---comment + wait = function(words) + local count = utils.string_to_int(words[1]) + if count then + message.notify("Waiting " .. count .. " turns") + for _ = 1, count do + M.tick() + end + end + end, + + ---comment + help = function() + message.notify( + ":EndGame to quit.\n" + .. ":StartGame to restart.\n" + .. "Move cursor in normal mode to move and attack. " + .. "Visual mode to sneak. " + .. "Delete to pickup items. " + .. "Insert to drop items. \n" + .. "Actions start with '" + .. M.leader_key + .. "' " + .. "Actions: " + .. "i to show inventory, w to wear, k to kick, f to fuse, l to look, e to eat, s to say, d to drop, to wait, ? for help" + ) + end, +} ---comment -M.kick = function() +M.prompt_kick = function() local direction = M.prompt_one_char("Kick direction? hjkl") if direction then - event.kick(direction) - M.tick() + M.actions.kick({ direction }) end end ---comment -M.wear = function() +M.prompt_wear = function() local slot = M.prompt_one_char("Wear on? h:head r:right hand l:left hand b:body f:feet") if slot then message.notify("You have:\n0:nothing\n" .. player.get_inventory_item_with_index()) vim.defer_fn(function() local index_str = M.prompt_one_word("Wear what?") if index_str then - local index = utils.string_to_int(index_str) - if index then - player.wear(slot, index) - end + M.actions.wear({ slot, index_str }) end end, 50) end end ---comment -M.fuse = function() +M.prompt_fuse = function() message.notify("You have:\n" .. player.get_inventory_item_with_index()) vim.defer_fn(function() local index = M.prompt("Fuse what?") if index then - player.fuse(utils.strings_to_ints(index)) - M.tick() + M.actions.fuse(utils.split_words(index)) end end, 50) end ---comment -M.look = function() +M.prompt_look = function() message.notify("You have:\n0:self\n" .. player.get_inventory_item_with_index()) vim.defer_fn(function() local index = M.prompt("Look at what?") if index then - player.look(utils.strings_to_ints(index)) + M.actions.look(utils.split_words(index)) end end, 50) end ---comment -M.eat = function() +M.prompt_eat = function() message.notify("You have:\n" .. player.get_inventory_item_with_index()) vim.defer_fn(function() local index = M.prompt("Eat what?") if index then - player.eat(utils.strings_to_ints(index)) - M.tick() + M.actions.eat(utils.split_words(index)) end end, 50) end ---comment -M.drop = function() +M.prompt_drop = function() message.notify("You have:\n" .. player.get_inventory_item_with_index()) vim.defer_fn(function() local index = M.prompt("Drop what?") if index then - player.drop(utils.strings_to_ints(index)) - M.tick() + M.actions.drop(utils.split_words(index)) end end, 50) end ---comment -M.say = function() +M.prompt_say = function() vim.defer_fn(function() local words = M.prompt("Say what?") if words then - event.say(words) - M.tick() + M.actions.say(utils.split_words(words)) end end, 50) end ---comment -M.wait = function() +M.prompt_wait = function() vim.defer_fn(function() local str = M.prompt_one_word("Wait how long?") if str then - local count = utils.string_to_int(str) - if count then - for _ = 1, count do - M.tick() - end - end + M.actions.wait({ str }) end end, 50) end ----comment -M.help = function() - message.notify( - ":EndGame to quit.\n" - .. ":StartGame to restart.\n" - .. "Move cursor in normal mode to move and attack. " - .. "Visual mode to sneak. " - .. "Delete to pickup items. " - .. "Insert to drop items. \n" - .. "Actions start with '" - .. M.leader_key - .. "' " - .. "Actions: " - .. "i to show inventory, w to wear, k to kick, f to fuse, l to look, e to eat, s to say, d to drop, to wait, ? for help" - ) +---parse a string into performing an action +---@param inserted_chars string +M.parse_action = function(inserted_chars) + local words = utils.split_words(inserted_chars) + if words == nil or #words == 0 then + return + end + local action_name = table.remove(words, 1) + local action = M.actions[action_name] + if action == nil then + message.notify("Don't know how to " .. action_name .. " " .. table.concat(words, " ")) + else + action(words) + end end ---comment @@ -142,16 +203,16 @@ M.setup = function(bufnr, tick) vim.keymap.set("n", M.leader_key .. key, func, { buffer = bufnr, desc = desc }) end - map("i", M.inventory, "inventory") - map("w", M.wear, "wear") - map("k", M.kick, "kick") - map("f", M.fuse, "fuse") - map("l", M.look, "look") - map("e", M.eat, "eat") - map("d", M.drop, "drop") - map("s", M.say, "say") - map(" ", M.wait, "wait") - map("?", M.help, "help") + map("?", M.actions.help, "help") + map("i", M.actions.inventory, "inventory") + map("w", M.prompt_wear, "wear") + map("k", M.prompt_kick, "kick") + map("f", M.prompt_fuse, "fuse") + map("l", M.prompt_look, "look") + map("e", M.prompt_eat, "eat") + map("d", M.prompt_drop, "drop") + map("s", M.prompt_say, "say") + map(" ", M.prompt_wait, "wait") end ---remove all existing keymaps for the leader diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 3208890..9062df7 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -10,6 +10,7 @@ local state = require("neohack.state") local utils = require("neohack.utils") local chance = require("neohack.chance") local event = require("neohack.event") +local actions = require("neohack.actions") ---comment ---@param char string @@ -48,12 +49,7 @@ M.handle_inserted = function() -- reset cursor position before performing any action buffer.move_prev_cursor() - vim.fn.setreg('"', "") - if inserted_chars:sub(1, 1) == "k" then - local dir = inserted_chars:sub(2, 2) - -- message.notify("kicked " .. dir) - event.kick(dir) - end + actions.parse_action(inserted_chars) end end diff --git a/lua/neohack/event.lua b/lua/neohack/event.lua index b9c057f..764bf72 100644 --- a/lua/neohack/event.lua +++ b/lua/neohack/event.lua @@ -248,13 +248,14 @@ M.kick = function(direction) end M.say = function(words) - message.notify("You said: " .. words) + local word_str = table.concat(words, " ") + message.notify("You said: " .. word_str) local spell_names = "" ---@type Entity[] local casting = {} for _, spell_item in pairs(player.get_spell_items()) do - if string.find(words, spell_item.inscription.inscription) ~= nil then + if string.find(word_str, spell_item.inscription.inscription) ~= nil then table.insert(casting, spell_item) spell_names = spell_names .. spell_item.inscription.inscription .. " " end @@ -268,13 +269,13 @@ M.say = function(words) for _, enemy in ipairs(enemies) do local cast = (#casting > 0 and " cast " .. spell_names) or "" - if string.find(words, string.upper(enemy.name)) ~= nil then + if string.find(word_str, string.upper(enemy.name)) ~= nil then message.notify("The " .. enemy.name .. " HEARD you" .. cast) for _, spell in ipairs(casting) do spell.inscription.effect.cast(enemy, 1) message.notify("Cast " .. string.upper(spell.inscription.effect.name) .. " on " .. enemy.name) end - elseif string.find(words, enemy.name) ~= nil then + elseif string.find(word_str, enemy.name) ~= nil then message.notify("The " .. enemy.name .. " heard you" .. cast) for _, spell in ipairs(casting) do spell.inscription.effect.cast(enemy, 0.6) @@ -284,12 +285,12 @@ M.say = function(words) end for _, item in ipairs(items) do - if string.find(words, string.upper(item.name)) ~= nil then + if string.find(word_str, string.upper(item.name)) ~= nil then for _, spell in ipairs(casting) do spell.inscription.effect.cast(item, 1) message.notify("Cast " .. string.upper(spell.inscription.effect.name) .. " on " .. item.name) end - elseif string.find(words, item.name) ~= nil then + elseif string.find(word_str, item.name) ~= nil then for _, spell in ipairs(casting) do spell.inscription.effect.cast(item, 0.6) message.notify("Cast " .. spell.inscription.effect.name .. " on " .. item.name) diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index 725eaac..23fa3d5 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -36,7 +36,7 @@ M.start_game = function() player.handle_down = M.handle_down player.handle_up = M.handle_up message.notify("New game started.") - actions.help() + actions.actions.help() end M.create_new_buffer = function(lines) diff --git a/lua/neohack/utils.lua b/lua/neohack/utils.lua index dc09f0c..6e22890 100644 --- a/lua/neohack/utils.lua +++ b/lua/neohack/utils.lua @@ -54,11 +54,11 @@ M.split_words = function(str) end ---comment ----@param str string +---@param strings string[] ---@return string[] -M.strings_to_ints = function(str) +M.strings_to_ints = function(strings) local result = {} - for word in string.gmatch(str, "%S+") do + for _, word in ipairs(strings) do local i = M.string_to_int(word) if i then table.insert(result, i) From 137109da338c49634a8ab34512027ab0c65b96f4 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 13:06:33 +1100 Subject: [PATCH 05/31] refactor: keymaps insert actions so they are repeatable --- lua/neohack/actions.lua | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index 09ab0ed..53cfa66 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -89,11 +89,18 @@ M.actions = { end, } +---Insert the action command +---@param action_string string +M.insert_action = function(action_string) + vim.cmd("normal! i" .. action_string) +end + ---comment M.prompt_kick = function() local direction = M.prompt_one_char("Kick direction? hjkl") if direction then - M.actions.kick({ direction }) + M.insert_action("kick " .. direction) + -- M.actions.kick({ direction }) end end @@ -105,7 +112,8 @@ M.prompt_wear = function() vim.defer_fn(function() local index_str = M.prompt_one_word("Wear what?") if index_str then - M.actions.wear({ slot, index_str }) + M.insert_action("wear " .. slot .. " " .. index_str) + -- M.actions.wear({ slot, index_str }) end end, 50) end @@ -117,7 +125,8 @@ M.prompt_fuse = function() vim.defer_fn(function() local index = M.prompt("Fuse what?") if index then - M.actions.fuse(utils.split_words(index)) + M.insert_action("fuse " .. index) + -- M.actions.fuse(utils.split_words(index)) end end, 50) end @@ -128,7 +137,8 @@ M.prompt_look = function() vim.defer_fn(function() local index = M.prompt("Look at what?") if index then - M.actions.look(utils.split_words(index)) + M.insert_action("look " .. index) + -- M.actions.look(utils.split_words(index)) end end, 50) end @@ -139,7 +149,8 @@ M.prompt_eat = function() vim.defer_fn(function() local index = M.prompt("Eat what?") if index then - M.actions.eat(utils.split_words(index)) + M.insert_action("eat " .. index) + -- M.actions.eat(utils.split_words(index)) end end, 50) end @@ -150,7 +161,8 @@ M.prompt_drop = function() vim.defer_fn(function() local index = M.prompt("Drop what?") if index then - M.actions.drop(utils.split_words(index)) + M.insert_action("drop " .. index) + -- M.actions.drop(utils.split_words(index)) end end, 50) end @@ -160,7 +172,8 @@ M.prompt_say = function() vim.defer_fn(function() local words = M.prompt("Say what?") if words then - M.actions.say(utils.split_words(words)) + M.insert_action("say " .. words) + -- M.actions.say(utils.split_words(words)) end end, 50) end @@ -170,7 +183,8 @@ M.prompt_wait = function() vim.defer_fn(function() local str = M.prompt_one_word("Wait how long?") if str then - M.actions.wait({ str }) + M.insert_action("wait " .. str) + -- M.actions.wait({ str }) end end, 50) end @@ -203,8 +217,12 @@ M.setup = function(bufnr, tick) vim.keymap.set("n", M.leader_key .. key, func, { buffer = bufnr, desc = desc }) end - map("?", M.actions.help, "help") - map("i", M.actions.inventory, "inventory") + map("?", function() + M.insert_action("help") + end, "help") + map("i", function() + M.insert_action("inventory") + end, "inventory") map("w", M.prompt_wear, "wear") map("k", M.prompt_kick, "kick") map("f", M.prompt_fuse, "fuse") From 0a56ad08d8edfa0ee5fca408bafeba2ab5ae6f9e Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 13:45:57 +1100 Subject: [PATCH 06/31] feat: actions can be done on item names, not spaces yet --- lua/neohack/actions.lua | 15 +++---- lua/neohack/player.lua | 91 +++++++++++++++++++++++++---------------- lua/neohack/utils.lua | 1 - 3 files changed, 60 insertions(+), 47 deletions(-) diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index 53cfa66..d8e2360 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -23,34 +23,29 @@ M.actions = { ---comment wear = function(words) - local slot = table.remove(words, 1) - local index = utils.string_to_int(words[1]) - if index then - --- TODO: actions take indexes, which is weird to insert - player.wear(slot, index) - end + player.wear(words[1], words[2]) end, ---comment fuse = function(words) - player.fuse(utils.strings_to_ints(words)) + player.fuse(words) M.tick() end, ---comment look = function(words) - player.look(utils.strings_to_ints(words)) + player.look(words) end, ---comment eat = function(words) - player.eat(utils.strings_to_ints(words)) + player.eat(words) M.tick() end, ---comment drop = function(words) - player.drop(utils.strings_to_ints(words)) + player.drop(words) M.tick() end, diff --git a/lua/neohack/player.lua b/lua/neohack/player.lua index 4a1fe68..c2802bd 100644 --- a/lua/neohack/player.lua +++ b/lua/neohack/player.lua @@ -1,6 +1,16 @@ --- player stuff --- +local utils = require("neohack.utils") +local fuse = require("neohack.fuse") +local Def = require("neohack.def") +local defs = require("neohack.defs") +local buffer = require("neohack.buffer") +local state = require("neohack.state") +local message = require("neohack.message") +local Entity = require("neohack.entity") +local chance = require("neohack.chance") + local M = { ---@type number required to search a corpse corpse_threshold = 0.5, @@ -23,15 +33,6 @@ local M = { handle_up = nil, } -local fuse = require("neohack.fuse") -local Def = require("neohack.def") -local defs = require("neohack.defs") -local buffer = require("neohack.buffer") -local state = require("neohack.state") -local message = require("neohack.message") -local Entity = require("neohack.entity") -local chance = require("neohack.chance") - ---comment ---@return boolean M.is_dead = function() @@ -269,17 +270,33 @@ M.retrieve_item_char = function(char) return nil end ----drop the specific item ----@param indexes integer[] +---get the named item out of inventory +---@param keys string[] names or indexes ---@return Entity[]? -M.retrieve_item_indexes = function(indexes) +M.retrieve_items = function(keys) local items = {} - for _, index in ipairs(indexes) do - local item = state.player.items[index] - if item then - table.insert(items, item) + local indexes = {} + for _, name in ipairs(keys) do + local found = false + local index = utils.string_to_int(name) + if index then + table.insert(items, state.player.items[index]) + table.insert(indexes, index) + found = true else - message.notify("No " .. index .. " to retrieve") + for i, v in ipairs(state.player.items) do + if v.name == name then + -- matches first found + table.insert(items, v) + table.insert(indexes, i) + found = true + break + end + end + end + if not found then + message.notify("No " .. name .. " to retrieve") + -- get all or nothing return nil end end @@ -297,8 +314,8 @@ end ---comment ---@param slot string ----@param index integer -M.wear = function(slot, index) +---@param key string +M.wear = function(slot, key) -- unwear the current item local p = state.player local current = p.slots[slot] @@ -308,10 +325,10 @@ M.wear = function(slot, index) p.slots[slot] = nil end - if index == 0 then + if key == 0 or key == "nothing" then return end - local items = M.retrieve_item_indexes({ index }) + local items = M.retrieve_items({ key }) if items and items[1] then p.slots[slot] = items[1] message.notify("Wearing " .. items[1].name .. " on " .. state.slot_name(slot)) @@ -321,9 +338,9 @@ M.wear = function(slot, index) end ---comment ----@param indexes integer[] -M.fuse = function(indexes) - local items = M.retrieve_item_indexes(indexes) +---@param keys string[] +M.fuse = function(keys) + local items = M.retrieve_items(keys) if not items then return end @@ -338,20 +355,20 @@ M.fuse = function(indexes) end end local new_item = Entity.new(new_def, 0, 0) - message.notify("Fused " .. table.concat(indexes, " ") .. " into " .. new_item.name) + message.notify("Fused " .. table.concat(keys, " ") .. " into " .. new_item.name) M.pickup_item(new_item) end ---comment ----@param indexes integer[] -M.look = function(indexes) - for i, index in ipairs(indexes) do - if index == 0 then +---@param keys string[] +M.look = function(keys) + for i, index in ipairs(keys) do + if index == 0 or index == "self" then message.notify("Looked at self " .. M.get_attributes()) - table.remove(indexes, i) + table.remove(keys, i) end end - local items = M.retrieve_item_indexes(indexes) + local items = M.retrieve_items(keys) if not items then return end @@ -364,9 +381,9 @@ M.look = function(indexes) end ---comment ----@param indexes integer[] -M.eat = function(indexes) - local items = M.retrieve_item_indexes(indexes) +---@param keys string[] +M.eat = function(keys) + local items = M.retrieve_items(keys) if not items then return end @@ -393,8 +410,10 @@ M.eat = function(indexes) end end -M.drop = function(indexes) - local items = M.retrieve_item_indexes(indexes) +---comment +---@param keys string[] +M.drop = function(keys) + local items = M.retrieve_items(keys) if not items then return end diff --git a/lua/neohack/utils.lua b/lua/neohack/utils.lua index 6e22890..646ac57 100644 --- a/lua/neohack/utils.lua +++ b/lua/neohack/utils.lua @@ -75,7 +75,6 @@ M.string_to_int = function(str) if num then return math.floor(num) else - message.notify("invalid number " .. str) return nil end end From 3a33116383827360e8518b24c395d4d63a77cbd6 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 13:57:12 +1100 Subject: [PATCH 07/31] refactor: remove spaces and punctuation for item and enemy names --- data/enemies.txt | 576 +++++++++++++++++++++---------------------- data/items.txt | 376 ++++++++++++++-------------- lua/neohack/defs.lua | 16 +- 3 files changed, 484 insertions(+), 484 deletions(-) diff --git a/data/enemies.txt b/data/enemies.txt index d1f71b0..9f89c0d 100644 --- a/data/enemies.txt +++ b/data/enemies.txt @@ -1,11 +1,11 @@ aardvark abnormality abuse -abyss walker -abyssal fiend -abyssal guardian -abyssal stalker -abyssal wraith +abyss_walker +abyssal_fiend +abyssal_guardian +abyssal_stalker +abyssal_wraith activist actor actress @@ -39,9 +39,9 @@ attack attacker avalanche axolotl -baba yaga +baba_yaga baboon -baby baboon +baby_baboon_ badger bandit banshee @@ -55,36 +55,36 @@ bedbug bee beetle beggar -beluga whale -beluga whale -bengal tiger cub -bengal tiger cub +beluga_whale +beluga_whale +bengal_tiger_cub +bengal_tiger_cub bigfoot -bird-watcher +bird_watcher blackbird -blackened knight +blackened_knight blackfish -blackwood hunter -blight lord -blighted apparition -bloodbound slayer -bloodmoon beast -bloodmoon witch -bloodmoon wraith +blackwood_hunter +blight_lord +blighted_apparition +bloodbound_slayer +bloodmoon_beast +bloodmoon_witch +bloodmoon_wraith bloodstalker bloodsucker -bloodsworn avenger -bloodthirst hound -bloodthirst mage -bloodthirsty marauder -blue jay +bloodsworn_avenger +bloodthirst_hound +bloodthirst_mage +bloodthirsty_marauder +blue_jay boar bobcat -bone dragon -bone golem -boneblade assassin +bone_dragon +bone_golem +boneblade_assassin bonecaller -bonecrush brute +bonecrush_brute bonewalker bonewitch boogeyman @@ -95,7 +95,7 @@ budgerigar buffalo bugbear bull -bull-fighter +bull_fighter bulldozer bunny bunny @@ -117,14 +117,14 @@ centipede chameleon chameleon cheetah -cheetah cub -cheetah cub +cheetah_cub +cheetah_cub chick chick chimera chimpanzee -chimpanzee baby -chimpanzee baby +chimpanzee_baby +chimpanzee_baby chinchilla chinchilla chipmunk @@ -140,50 +140,50 @@ cockroach condor corgi corgi -corrupted knight -corrupted sprite +corrupted_knight +corrupted_sprite cougar coyote coyote crab crab creeper -creeping dread -creeping horror +creeping_dread +creeping_horror cricket criminal -crimson specter -crimson wraith +crimson_specter +crimson_wraith crocodile crocodile crow crow crusader -crypt warden -curse bearer -curse weaver +crypt_warden +curse_bearer +curse_weaver cursebearer -cursed beastmaster -cursed knight -cursed marauder -cursed sentinel -cursed shade +cursed_beastmaster +cursed_knight +cursed_marauder +cursed_sentinel +cursed_shade cyclops cyclops -dark elf -dark enchantress -dark mage -dark sovereign -darkling beast -darkshadow beast -darkveil assassin -darkwing harbinger -darkwing hunter -death bringer -death knight -deathbound berserker -deathbound lurker -deathshroud wight +dark_elf +dark_enchantress +dark_mage +dark_sovereign +darkling_beast +darkshadow_beast +darkveil_assassin +darkwing_harbinger +darkwing_hunter +death_bringer +death_knight +deathbound_berserker +deathbound_lurker +deathshroud_wight deer demon demon @@ -213,7 +213,7 @@ duck duckling duckling dullahan -dung beetle +dung_beetle dungeon dusk dust @@ -224,48 +224,48 @@ eagle eagle earthquake earwig -ebon wight -ebonshade lurker -eldritch abomination -eldritch enchanter -eldritch fiend -eldritch horror -eldritch warden -eldritch warlock -elephant calf -elephant calf +ebon_wight +ebonshade_lurker +eldritch_abomination +eldritch_enchanter +eldritch_fiend +eldritch_horror +eldritch_warden +eldritch_warlock +elephant_calf +elephant_calf elf enemy evil -eyeless watcher +eyeless_watcher fairy fairy fang fawn fawn felony -fennec fox -fennec fox +fennec_fox +fennec_fox ferret ferret ferret -fiendish enchanter +fiendish_enchanter firefly firefly firefly flamingo flea -flesh puppeteer -flesh-eater +flesh_puppeteer +flesh_eater fly -forsaken knight -forsaken revenant -forsaken sorcerer +forsaken_knight +forsaken_revenant +forsaken_sorcerer fox frankenstein frog -frost wraith -fruit fly +frost_wraith +fruit_fly gerbil gerbil ghost @@ -276,8 +276,8 @@ giant giant gibbon gibbon -giraffe calf -giraffe calf +giraffe_calf +giraffe_calf gloomfiend gloomhound gloomhound @@ -289,50 +289,50 @@ goldfish golem gorgon gorilla -gorilla baby -gorilla baby +gorilla_baby +gorilla_baby gossip grasshopper -graveborne beast -gravebound brute -gravebound warrior +graveborne_beast +gravebound_brute +gravebound_warrior gravefiend gravewalker gremlin griffin -grim reaper -grim sorcerer -grimshroud guardian +grim_reaper +grim_sorcerer +grimshroud_guardian grimwarrior -grisly gargoyle -grisly stalker -guinea pig -guinea pig +grisly_gargoyle +grisly_stalker +guinea_pig +guinea_pig hag hamster hamster harpy harpy -haunted golem -haunted sentinel -haunting shade -haunting specter -haunting warden -haunting warlock +haunted_golem +haunted_sentinel +haunting_shade +haunting_specter +haunting_warden +haunting_warlock hawk -headless horseman +headless_horseman hedgehog hedgehog hedgehog hedgehog hellcat hellhound -hermit crab -hermit crab -hexed harbinger -hippopotamus calf -hollow brute -hollow sorcerer +hermit_crab +hermit_crab +hexed_harbinger +hippopotamus_calf +hollow_brute +hollow_sorcerer horde hornet hornet @@ -352,12 +352,12 @@ jellyfish jellyfish jellyfish jerk -jersey devil -jewel beetle -june bug +jersey_devil +jewel_beetle +june_bug kangaroo -kangaroo joey -kangaroo joey +kangaroo_joey +kangaroo_joey katydid killer kingfisher @@ -366,8 +366,8 @@ kitten knight koala koala -koala joey -koala joey +koala_joey +koala_joey kraken kraken lacewing @@ -376,15 +376,15 @@ lam lamb lamb lamia -leafcutter ant +leafcutter_ant leafhopper lemur lemur leopard -leopard gecko -leopard gecko +leopard_gecko +leopard_gecko lich -lightning bug +lightning_bug lion llama llama @@ -393,10 +393,10 @@ louse lovebird lovebird lovebug -lurking shade +lurking_shade lynx -lynx kitten -lynx kitten +lynx_kitten +lynx_kitten macaw macaw maggot @@ -405,28 +405,28 @@ manatee manatee maniac mantis -marbled polecat -marbled polecat +marbled_polecat +marbled_polecat medusa meerkat meerkat midge millipede minotaur -mire fiend +mire_fiend mobster monster -moonlit ghoul -moonlit phantom +moonlit_ghoul +moonlit_phantom moose -moose calf -moose calf +moose_calf +moose_calf mosquito mosquito moth mothman -mournful phantom -mournful revenant +mournful_phantom +mournful_revenant mouse mouse mummy @@ -438,19 +438,19 @@ narwhal necrofiend necromancer necroshade -necrotic abomination -necrotic enchantress -necrotic guardian -net-winged beetle -nether reaver -netherblade assassin +necrotic_abomination +necrotic_enchantress +necrotic_guardian +net_winged_beetle +nether_reaver +netherblade_assassin netherfiend -night stalker +night_stalker nightmare -nightmare fiend -nightmare specter -nightshade sorcerer -nightshade wraith +nightmare_fiend +nightmare_specter +nightshade_sorcerer +nightshade_wraith ninja nit nosferatu @@ -465,8 +465,8 @@ opossum opponent opportunist orangutan -orangutan baby -orangutan baby +orangutan_baby +orangutan_baby osprey ostrich otter @@ -478,11 +478,11 @@ ox panda panda panther -paper wasp +paper_wasp parakeet parakeet parrot -pea weevil +pea_weevil peacock peacock penguin @@ -490,22 +490,22 @@ penguin pest phantasm phantom -phantom seeker +phantom_seeker pig piglet piglet pimp pirate -plague bearer -plague warden +plague_bearer +plague_warden plaguebearer plaguebringer plaguefiend platypus platypus platypus -polar bear cub -polar bear cub +polar_bear_cub +polar_bear_cub poltergeist pony pony @@ -513,12 +513,12 @@ porcupine porcupine porcupine porpoise -potato beetle -prairie dog -prairie dog -prairie dog -prairie dog -praying mantis +potato_beetle +prairie_dog +prairie_dog +prairie_dog +prairie_dog +praying_mantis prisoner ptarmigan pufferfish @@ -529,15 +529,15 @@ puggle puma puppy puppy -pygmy goat -pygmy goat -quagmire beast -quake beast +pygmy_goat +pygmy_goat +quagmire_beast +quake_beast quarashi -quark demon +quark_demon quasit queen -queen ant +queen_ant quicksand quicksilver quillbeast @@ -550,71 +550,71 @@ rat rat rat raven -ravenous revenant -red panda -red panda -red squirrel -reindeer calf +ravenous_revenant +red_panda +red_panda +red_squirrel +reindeer_calf revenant rhinoceros ringworm riot -robber fly +robber_fly rooster -sable shade +sable_shade sandman sawfly -scarab beetle +scarab_beetle scarecrow scorpion scorpionfly -sea otter -sea otter -sea serpent -sea turtle -sea turtle +sea_otter +sea_otter +sea_serpent +sea_turtle +sea_turtle seagull seal -seal pup -seal pup +seal_pup +seal_pup serval shade -shadow creature -shadow fiend -shadow stalker -shadowblade hunter +shadow_creature +shadow_fiend +shadow_stalker +shadowblade_hunter shadowbringer shark shoat shrimp silverfish -sinister brute -sinister revenant -sinister shaman +sinister_brute +sinister_revenant +sinister_shaman sirens -skin crawler +skin_crawler skinwalker skunk sloth sloth snail snake -snow leopard cub -snow leopard cub +snow_leopard_cub +snow_leopard_cub soldier sorcerer -soul reaper -soulbound beast -soulbound sorcerer +soul_reaper +soulbound_beast +soulbound_sorcerer souleater soulflayer -soulflayer knight +soulflayer_knight sparrow specter -spectral assassin -spectral avenger -spectral beastmaster -spectral marauder +spectral_assassin +spectral_avenger +spectral_beastmaster +spectral_marauder spider spider spiderling @@ -633,8 +633,8 @@ stingray stonefly sturgeon succubus -sugar glider -sugar glider +sugar_glider +sugar_glider swan swan swine @@ -643,7 +643,7 @@ tamandua tamandua termite termite -terror wight +terror_wight terrorclaw terrorist thief @@ -660,49 +660,49 @@ trafficker train tramp trap -tree frog -tree frog +tree_frog +tree_frog troll -tsetse fly -twilight fiend -twilight ghoul -twilight phantom -twilight reaper -twisted bonefiend -twisted specter -twisted wraith +tsetse_fly +twilight_fiend +twilight_ghoul +twilight_phantom +twilight_reaper +twisted_bonefiend +twisted_specter +twisted_wraith ultrabeast ultraman ultron umbra -umbra horror +umbra_horror undead undine unicorn urchin -uruk-hai +uruk_hai urumi vampire vampire -vampire bat -veil reaper -veilbound shaman +vampire_bat +veil_reaper +veilbound_shaman venom -vile reaper -vile stalker -vile warlock -vile wraith +vile_reaper +vile_stalker +vile_warlock +vile_wraith vixen -void hunter -void lurker -void walker -void witch +void_hunter +void_lurker +void_walker +void_witch voidbringer voidwalker -voodoo priest +voodoo_priest vulture vulture -walking stick +walking_stick wallaby wallaby walrus @@ -712,16 +712,16 @@ warlord warrior wasp wasp -water strider +water_strider weasel weevil wendigo werewolf whale whitefly -wicked alchemist -wicked shade -wicked warlock +wicked_alchemist +wicked_shade +wicked_warlock witch witch wolf @@ -731,7 +731,7 @@ wombat woodlouse wraith wraithcaller -wraithcaller mage +wraithcaller_mage wraithlord wrestler xanathar @@ -747,7 +747,7 @@ xulo yaga yaksha yellowjacket -yeth hound +yeth_hound yeti yeti yfelgópa @@ -755,8 +755,8 @@ ymir yojimbo yowler yrthak -yuan-ti -yucca man +yuan_ti +yucca_man yurei zamiel zampire @@ -769,77 +769,77 @@ zephyr zerg zombie zombie -zombie hound -the lich -ice king -magic man -hunson abadeer -earl of lemongrab +zombie_hound +the_lich +ice_king +magic_man +hunson_abadeer +earl_of_lemongrab lemongrab -duke of nuts -ice elemental +duke_of_nuts +ice_elemental ricardio -me-mow -martin mertens -kee-oth -maja the sky witch +me_mow +martin_mertens +kee_oth +maja_the_sky_witch scorcher -the lich king's minions -susan strong +the_lich_king_minions +susan_strong goliad stormo orgalorg fern -hunson abadeer -the empress -the vampire king +hunson_abadeer +the_empress +the_vampire_king lich jake -uncle gumbald -aunt lolly +uncle_gumbald +aunt_lolly chicle crunchy -the dark cloud -patience st. pim +the_dark_cloud +patience_st_pim donny -the gut grinder -frog wizard -dr. gross -the bell witch +the_gut_grinder +frog_wizard +dr_gross +the_bell_witch moe -sleepy sam -lumpy space princess -tree witch -evil hermit -snow golem -fear feaster -giant spider -demon cat +sleepy_sam +lumpy_space_princess +tree_witch +evil_hermit +snow_golem +fear_feaster +giant_spider +demon_cat marceline -ghost lady -james baxter -crystal guardian +ghost_lady +james_baxter +crystal_guardian bufo -void caster -sky witch +void_caster +sky_witch marauder -mean guardian -cosmic owl -flame lord -mountain of matthew -ice king -evil snail -demon blood sword's curse -door lord -grass wizard -dream warrior +mean_guardian +cosmic_owl +flame_lord +mountain_of_matthew +ice_king +evil_snail +demon_blood_sword_curse +door_lord +grass_wizard +dream_warrior moon train -goo monster -river dragon -blood under the skin knight -sphere monsters -gnome king +goo_monster +river_dragon +blood_under_the_skin_knight +sphere_monsters +gnome_king witch skeleton martian diff --git a/data/items.txt b/data/items.txt index b63c1fa..fd7e6a4 100644 --- a/data/items.txt +++ b/data/items.txt @@ -33,7 +33,7 @@ alcohol alcove alder ale -allen wrench +allen_wrench alloy almanac almond @@ -184,7 +184,7 @@ ballot ballpark bamboo banana -banana phone +banana_phone band bandana bandanna @@ -285,7 +285,7 @@ beneficiary benefit beret berry -best-seller +best_seller bestseller bet beverage @@ -310,14 +310,14 @@ binoculars biology biopsy blanket -bo staff +bo_staff bookshelf -bottle opener -bouncy ball -bow tie +bottle_opener +bouncy_ball +bow_tie bowl broadsword -bubble wand +bubble_wand buck bucket buckle @@ -337,7 +337,7 @@ bulk bullet bump bumper -bumper sticker +bumper_sticker bun bunch bungalow @@ -348,7 +348,7 @@ bureau burial burlesque burn -burn-out +burn_out burning burrito burro @@ -371,7 +371,7 @@ buyer buying buzz buzzard -c-clamp +c_clamp cabana cabbage cabin @@ -400,13 +400,13 @@ call calm calorie camel -can opener +can_opener chair -chewing gum +chewing_gum chisel clamp claymore -clown nose +clown_nose club colander compass @@ -414,7 +414,7 @@ compress computer computer conditioner -contact lens +contact_lens container controller cook @@ -461,7 +461,7 @@ dining dinner diploma disco -disco ball +disco_ball dish dishwasher dishwasher @@ -486,7 +486,7 @@ dough doughnut draw drawer -dress-up wig +dress_up_wig drill drill drink @@ -495,7 +495,7 @@ dryer dryer duel duffel -dump truck +dump_truck dungarees duplexer earmuffs @@ -520,7 +520,7 @@ equal equipment eraser escalator -eskrima sticks +eskrima_sticks essence estoc ethernet @@ -547,25 +547,25 @@ face facelift facsimile fahrenheit -fake mustache -fake spider -fake teeth -fake vomit +fake_mustache +fake_spider +fake_teeth +fake_vomit falchion fang -fanny-pack +fanny_pack faucet feather fedora fender filter -finger puppet +finger_puppet fingernail firewall flail flash flatboat -foam finger +foam_finger fob folder footnote @@ -574,12 +574,12 @@ fort foundation freezer fritter -frying pan -funny hat +frying_pan +funny_hat futon -fuzzy dice +fuzzy_dice gadget -gag glasses +gag_glasses gallon gauge gauntlet @@ -588,15 +588,15 @@ gear gelding gem geyser -giant pencil -giant sunglasses +giant_pencil +giant_sunglasses gladius glaive glockenspiel -glow stick +glow_stick goggles gold -googly eyes +googly_eyes grater greatsword grenade @@ -632,23 +632,23 @@ headlight headphones heater helmet -hex key +hex_key hiking hoe hook -hook sword +hook_sword hose hovercraft hubcap hydrant -ice-cream +ice_cream iceberg icebreaker icicle igloo illustration image -inflatable hammer +inflatable_hammer ink instrument internet @@ -662,9 +662,9 @@ jeweller jewellery jewelry jug -juggling balls +juggling_balls juice -jump rope +jump_rope jumper jumpsuit kaleidoscope @@ -698,7 +698,7 @@ lunch lute lyre mace -magic 8-ball +magic_8_ball magnet mango manicure @@ -706,13 +706,13 @@ map marker mask match -measuring cup -measuring spoon +measuring_cup +measuring_spoon medal microphone microwave microwave -mini megaphone +mini_megaphone mirror missile modem @@ -726,15 +726,15 @@ mouth muzzle naginta nail -nail gun +nail_gun napkin necklace necktie needle net newsstand -noise putty -novelty socks +noise_putty +novelty_socks nuke nunchaku nutmeg @@ -769,8 +769,8 @@ parchment parka parser parsnip -party horn -party popper +party_horn +party_popper passage passbook passport @@ -803,7 +803,7 @@ pension peony pepper pepperoni -pet rock +pet_rock pharmacist phone photo @@ -827,14 +827,14 @@ pillow pilot pin pineapple -ping pong paddle +ping_pong_paddle pistil pistol pita pitcher pizza place -plastic tiara +plastic_tiara plate plate platform @@ -848,7 +848,7 @@ pocket pod podcast poem -pogo stick +pogo_stick pole poleaxe polenta @@ -870,10 +870,10 @@ pottery pouch powder practice -prank gum +prank_gum printer printer -proof-reader +proof_reader propane pulley pump @@ -892,15 +892,15 @@ quarterstaff quartet quartz quiche -quiche dish -quick-release -quick-sand +quiche_dish +quick_release +quick_sand quicklime quill -quill pen +quill_pen quilt quilt -quilted jacket +quilted_jacket quintain quintet quiver @@ -919,9 +919,9 @@ rifle ring robot rocket -rolling pin +rolling_pin rope -rubber chicken +rubber_chicken ruler saber sabre @@ -970,18 +970,18 @@ shortsword shovel shower silk -silly string +silly_string silver skate skirt skis skullcap -slap bracelet +slap_bracelet sled slippers soap soccer -socket set +socket_set sofa sofa software @@ -1000,7 +1000,7 @@ spork spreadsheet spring spyglass -squeaky toy +squeaky_toy stadium staff staircase @@ -1015,9 +1015,9 @@ stencil stereo stick sticker -sticky hand +sticky_hand stiletto -stir-fry +stir_fry stock stool stopwatch @@ -1031,7 +1031,7 @@ string strip stripe strudel -stud finder +stud_finder sty submarine suit @@ -1061,7 +1061,7 @@ taco tag tanto tape -tape measure +tape_measure target tart tassel @@ -1082,13 +1082,13 @@ tool toothbrush toothpaste toothpick -torque wrench -toy drum -toy handcuffs -toy microphone -toy robot -toy snake -toy soldier +torque_wrench +toy_drum +toy_handcuffs +toy_microphone +toy_robot +toy_snake +toy_soldier trailer trash tray @@ -1117,11 +1117,11 @@ twig twilight twine typewriter -u-bolt +u_bolt ukulele -ultrasonic cleaner -ultrasound machine -ultraviolet light +ultrasonic_cleaner +ultrasound_machine +ultraviolet_light umbrella undercoat underlayment @@ -1130,11 +1130,11 @@ uniform upholstery urn utensil -utility knife -utility knife +utility_knife +utility_knife vaccine vacuum -vacuum cleaner +vacuum_cleaner vase vehicle veil @@ -1150,17 +1150,17 @@ voice volume volunteer voulge -wacky straw +wacky_straw wagon waist waistband waiter wardrobe warhammer -washing machine +washing_machine watch water -water pistol +water_pistol waterbed waterfall wave @@ -1172,26 +1172,26 @@ whip whisk whiskey whistle -whoopee cushion +whoopee_cushion widget wifi wildlife -wind-up toy +wind_up_toy wine winery -wire cutter +wire_cutter workbench worm wrench wrench wrist -x-ray machine -xacto knife -xanthan gum +x_ray_machine +xacto_knife +xanthan_gum xenolith -xenon lamp -xerox machine -xmas tree +xenon_lamp +xerox_machine +xmas_tree xylitol xylophone yacht @@ -1207,106 +1207,106 @@ yoyo zafu zeppelin zester -zigzag ruler +zigzag_ruler zinc zinfandel -ziploc bag +ziploc_bag zipper zither -zodiac chart +zodiac_chart zucchini zweihander -finn's sword -demon blood sword -grass sword -scarlet sword -jake's sword -root sword -finn sword -night sword -crystal sword -flame sword -lightning sword -golden sword -candy sword -starchild sword -gauntlet of the hero -gauntlet of billy +finn_sword +demon_blood_sword +grass_sword +scarlet_sword +jake_sword +root_sword +finn_sword +night_sword +crystal_sword +flame_sword +lightning_sword +golden_sword +candy_sword +starchild_sword +gauntlet_of_the_hero +gauntlet_of_billy enchiridion -book of spells -magic gem apple +book_of_spells +magic_gem_apple nothung -necro sword -ice king's crown -lute of resolution -gem of the princesses -magic man's hat -flame princess' pendant -loyalty to the king -gauntlet of fire -magic star cane -lumpy space princess' space lumps -marceline's axe-bass -princess bubblegum's science wand -flame shield -sunlight magic wand -tree trunks' crystal gem apple -nothung the magic sword -lich's crown -hunson abadeer's night sword -battle moon -candy armory -grass sword's thorn -grass sword's thorn armor -royal tart +necro_sword +ice_king_crown +lute_of_resolution +gem_of_the_princesses +magic_man_hat +flame_princess_pendant +loyalty_to_the_king +gauntlet_of_fire +magic_star_cane +lumpy_space_princess_space_lumps +marceline_axe_bass +princess_bubblegum_science_wand +flame_shield +sunlight_magic_wand +tree_trunks_crystal_gem_apple +nothung_the_magic_sword +lich_crown +hunson_abadeer_night_sword +battle_moon +candy_armory +grass_sword_thorn +grass_sword_thorn_armor +royal_tart hambo -magical polaroid camera -crystal eye -psychic tandem war elephant -ancient psychic tandem war elephant -orgalorg's super buster -billy's gauntlet -billy's sword -finn's arm -jake suit -bee protection suit -hero's gauntlet -cursed sword -firewolf sword -ghost scepter -banana guard's spear -gumball guardian's laser cannon -hush's rock -whisper dan's blade -dungeon train -jake's shield -bubblegum's amulet -marceline's dragon axe -ancient book of wizards -flame resistance potion -potion of invisibility -tree trunks' crystal -finn's battle armor -the enchiridion key -jermaine's paintbrush -royal axe -fire kingdom torch -crystal orb -echo cave's mirror -lich's horcrux -magic oar -rainicorn horn -lumpy space princess' diamond -magic ball of yarn +magical_polaroid_camera +crystal_eye +psychic_tandem_war_elephant +ancient_psychic_tandem_war_elephant +orgalorg_super_buster +billy_gauntlet +billy_sword +finn_arm +jake_suit +bee_protection_suit +hero_gauntlet +cursed_sword +firewolf_sword +ghost_scepter +banana_guard_spear +gumball_guardian_laser_cannon +hush_rock +whisper_dan_blade +dungeon_train +jake_shield +bubblegum_amulet +marceline_dragon_axe +ancient_book_of_wizards +flame_resistance_potion +potion_of_invisibility +tree_trunkscrystal +finn_battle_armor +the_enchiridion_key +jermaine_paintbrush +royal_axe +fire_kingdom_torch +crystal_orb +echo_cave_mirror +lich_horcrux +magic_oar +rainicorn_horn +lumpy_space_princess_diamond +magic_ball_of_yarn necronomicon flamethrower -glob goblin's ring -hero heart -sun sword -grass blade -arm of billy -ancient psychic tandem war elephant medallion -the 'g' sword -hero crystal -nothung's blade -goliad's mind gems +glob_goblin_ring +hero_heart +sun_sword +grass_blade +arm_of_billy +ancient_psychic_tandem_war_elephant_medallion +the_g_sword +hero_crystal +nothung_blade +goliad_mind_gem diff --git a/lua/neohack/defs.lua b/lua/neohack/defs.lua index d09f380..7f7c21b 100644 --- a/lua/neohack/defs.lua +++ b/lua/neohack/defs.lua @@ -40,7 +40,7 @@ M.item_defs = { p = Def.new({ type = Def.DefType.item, char = "p", - name = "pork sword", + name = "pork_sword", damage = 3, durability = 5, hit_rate = 0.69, @@ -63,7 +63,7 @@ M.item_defs = { ["!"] = Def.new({ type = Def.DefType.item, char = "!", - name = "long sword", + name = "long_sword", damage = 5, durability = 10, hit_rate = 0.8, @@ -74,7 +74,7 @@ M.item_defs = { l = Def.new({ type = Def.DefType.item, char = "l", - name = "wooden leg", + name = "wooden_leg", damage = 3, durability = 4, hit_rate = 0.6, @@ -113,7 +113,7 @@ M.item_defs = { }), [M.player_corpse] = Def.new({ type = Def.DefType.item, - name = "player corpse", + name = "player_corpse", char = "X", damage = 0, durability = 5, @@ -165,7 +165,7 @@ M.terrain_defs = { o = Def.new({ type = Def.DefType.terrain, char = "o", - name = "small hole", + name = "small_hole", damage = 1, hit_rate = 0.5, block_vision = false, @@ -174,7 +174,7 @@ M.terrain_defs = { ["0"] = Def.new({ type = Def.DefType.terrain, char = "0", - name = "snake pit", + name = "snake_pit", damage = 3, hit_rate = 0.5, block_vision = false, @@ -246,7 +246,7 @@ M.enemy_defs = { ["="] = Def.new({ type = Def.DefType.enemy, char = "=", - name = "haunted log", + name = "haunted_log", health = 1, moves = moves.sideways, randomness = 0.0, @@ -306,7 +306,7 @@ M.enemy_defs = { A = Def.new({ type = Def.DefType.enemy, char = "A", - name = "cheese wizzard", + name = "cheese_wizzard", health = 11, moves = moves.diag, randomness = 0.9, From 9a1b33048859e996eaffb16517451fd42e029a56 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 15:38:45 +1100 Subject: [PATCH 08/31] feat: statusline for basic info, insert only working for change though. --- README.md | 2 +- lua/config.lua | 2 ++ lua/neohack/actions.lua | 2 +- lua/neohack/chance.lua | 2 +- lua/neohack/game.lua | 36 +++++++++++++++++++++++++++------- lua/neohack/generated_defs.lua | 4 ++-- lua/neohack/init.lua | 6 ++++++ lua/neohack/player.lua | 6 +++--- lua/neohack/state.lua | 4 ++-- 9 files changed, 47 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 06684ef..929f06e 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Actions - [x] yank - search, works in combination with sneaking - [ ] jumplist - ??? - [ ] use registers for inventory - - [ ] insert to run actions + - [x] insert to run actions - [ ] macros - [x] varied entities - [x] item and enemy generation from dictionary diff --git a/lua/config.lua b/lua/config.lua index 4e9230c..6b4559e 100644 --- a/lua/config.lua +++ b/lua/config.lua @@ -4,6 +4,8 @@ vim.opt.splitright = true vim.opt.splitbelow = true vim.o.cmdheight = 0 +vim.o.statusline = "%m %y %r %=%{mode()} %f" + -- Highlight when yanking (copying) text vim.api.nvim_create_autocmd("TextYankPost", { desc = "Highlight when yanking (copying) text", diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index d8e2360..e89fc64 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -12,7 +12,7 @@ local utils = require("neohack.utils") M.actions = { ---comment inventory = function() - message.notify("Level " .. state.current_level .. " " .. player.show_inventory()) + message.notify("Level " .. state.current_floor .. " " .. player.show_inventory()) end, ---comment diff --git a/lua/neohack/chance.lua b/lua/neohack/chance.lua index 3d8158e..7aebe11 100644 --- a/lua/neohack/chance.lua +++ b/lua/neohack/chance.lua @@ -12,7 +12,7 @@ local state = require("neohack.state") M.action_success = function(skill, advantage, resistance, threshold) -- random is either helpful or harmful local random = math.random() - 0.5 - local level_resistance = resistance + (state.current_level * 0.1) + local level_resistance = resistance + (state.current_floor * 0.1) local success_chance = skill + advantage - level_resistance + random message.notify( "action_success chance: " diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index 23fa3d5..b50490b 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -54,7 +54,7 @@ end M.setup_buffer = function(bufnr, level) state.current_bufnr = bufnr - state.current_level = level + state.current_floor = level local _, _, first_floor = map.scan_buf(bufnr) buffer.setup_buffer(bufnr, first_floor) actions.setup(bufnr, M.tick) @@ -63,28 +63,28 @@ M.setup_buffer = function(bufnr, level) end M.handle_down = function() - local new_level = state.current_level + 1 + local new_level = state.current_floor + 1 local bufnr = buffer.levels[new_level] if not bufnr then M.create_new_buffer({ " " }) else - state.current_level = new_level + state.current_floor = new_level state.current_bufnr = bufnr buffer.setup_buffer(bufnr, nil) end - return state.current_level + return state.current_floor end M.handle_up = function() - local new_level = state.current_level - 1 + local new_level = state.current_floor - 1 local bufnr = buffer.levels[new_level] if not bufnr then return nil else - state.current_level = new_level + state.current_floor = new_level state.current_bufnr = bufnr vim.api.nvim_set_current_buf(bufnr) - return state.current_level + return state.current_floor end end @@ -165,4 +165,26 @@ M.tick = function() end) end +M.status_line = function() + local line, col = unpack(vim.api.nvim_win_get_cursor(0)) + + local mode = vim.fn.mode() + local game_mode = { + n = "walking", + i = "action", + v = "sneaking", + V = "sneaking", + ["\22"] = "sneaking", -- CTRL-V + } + return string.format( + " %s | floor %s | turn %s | health %s | Line: %d, Col: %d ", + game_mode[mode] or mode, + state.current_floor, + state.turn_counter, + state.player.health, + line, + col + ) +end + return M diff --git a/lua/neohack/generated_defs.lua b/lua/neohack/generated_defs.lua index 669f115..98ac53b 100644 --- a/lua/neohack/generated_defs.lua +++ b/lua/neohack/generated_defs.lua @@ -81,7 +81,7 @@ end M.generate_item = function() local char = M.random_letter() local name = M.random_word_starting_with(M.item_list, char) - local total_points = state.current_level * math.random() * 10 + local total_points = state.current_floor * math.random() * 10 -- local total_points = 10 * math.random() * 10 local portions = allocate_portions(total_points) @@ -134,7 +134,7 @@ end M.generate_enemy = function() local char = M.random_letter() local name = M.random_word_starting_with(M.enemy_list, char) - local total_points = state.current_level * math.random() * 2 + local total_points = state.current_floor * math.random() * 2 -- local total_points = 10 * math.random() * 2 local portions = allocate_portions(total_points) diff --git a/lua/neohack/init.lua b/lua/neohack/init.lua index 3e53d03..60c115c 100644 --- a/lua/neohack/init.lua +++ b/lua/neohack/init.lua @@ -42,6 +42,12 @@ M.setup = function(opts) ) vim.api.nvim_create_user_command("EndGame", M.end_game, { nargs = 0, desc = "End the current NeoHack game" }) + + vim.o.statusline = "%!v:lua.require'neohack'.status_line()" +end + +M.status_line = function() + return game.status_line() end return M diff --git a/lua/neohack/player.lua b/lua/neohack/player.lua index c2802bd..cc8a350 100644 --- a/lua/neohack/player.lua +++ b/lua/neohack/player.lua @@ -193,7 +193,7 @@ M.hit_terrain = function(row, col, terrain) if level then message.notify("Went up to " .. level) else - message.notify("Up is blocked. On " .. state.current_level) + message.notify("Up is blocked. On " .. state.current_floor) end elseif terrain.damage then M.hit_by(terrain, state.prev_cursor.row, state.prev_cursor.col) @@ -362,8 +362,8 @@ end ---comment ---@param keys string[] M.look = function(keys) - for i, index in ipairs(keys) do - if index == 0 or index == "self" then + for i, key in ipairs(keys) do + if key == 0 or key == "self" then message.notify("Looked at self " .. M.get_attributes()) table.remove(keys, i) end diff --git a/lua/neohack/state.lua b/lua/neohack/state.lua index 00f1a6b..fa5284d 100644 --- a/lua/neohack/state.lua +++ b/lua/neohack/state.lua @@ -50,7 +50,7 @@ local M = { ---@type integer current_bufnr = nil, ---@type integer - current_level = nil, + current_floor = nil, ---@type Entity[] deleted = nil, @@ -98,7 +98,7 @@ M.init_state = function() } M.prev_cursor = { row = 1, col = 1 } M.turn_counter = 0 - M.current_level = 1 + M.current_floor = 1 -- keep corpse as that's from the previous game end From 502e7096ebf2322649192054da5feb3141d8fa03 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 15:42:23 +1100 Subject: [PATCH 09/31] fix: 0 as action subject now string not int --- lua/neohack/player.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/neohack/player.lua b/lua/neohack/player.lua index cc8a350..4e785a4 100644 --- a/lua/neohack/player.lua +++ b/lua/neohack/player.lua @@ -325,7 +325,7 @@ M.wear = function(slot, key) p.slots[slot] = nil end - if key == 0 or key == "nothing" then + if key == "0" or key == "nothing" then return end local items = M.retrieve_items({ key }) @@ -363,7 +363,7 @@ end ---@param keys string[] M.look = function(keys) for i, key in ipairs(keys) do - if key == 0 or key == "self" then + if key == "0" or key == "self" then message.notify("Looked at self " .. M.get_attributes()) table.remove(keys, i) end From 92b3f623b3bae1f1c91e9988c342d62557c06ea9 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 16:01:12 +1100 Subject: [PATCH 10/31] feat: setup global statusline in minimal config --- README.md | 2 +- lua/config.lua | 6 ++++-- lua/neohack/game.lua | 3 ++- lua/neohack/init.lua | 2 -- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 929f06e..9c31f08 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Actions - [ ] animate cursor - [ ] treesitter parser highlighter - [ ] figure out how to disable on change event listener - - [ ] stats in status line + - [x] stats in status line - [x] messages in split - [ ] async enemy movements - [x] show visible map and hide unexplored sections diff --git a/lua/config.lua b/lua/config.lua index 6b4559e..0a42ecf 100644 --- a/lua/config.lua +++ b/lua/config.lua @@ -4,8 +4,6 @@ vim.opt.splitright = true vim.opt.splitbelow = true vim.o.cmdheight = 0 -vim.o.statusline = "%m %y %r %=%{mode()} %f" - -- Highlight when yanking (copying) text vim.api.nvim_create_autocmd("TextYankPost", { desc = "Highlight when yanking (copying) text", @@ -81,3 +79,7 @@ require("lazy").setup({ -- automatically check for plugin updates checker = { enabled = true }, }) + +-- set the statusline to show in game info +vim.o.statusline = "%!v:lua.require'neohack'.status_line()" +vim.o.laststatus = 3 diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index b50490b..e09f841 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -167,6 +167,7 @@ end M.status_line = function() local line, col = unpack(vim.api.nvim_win_get_cursor(0)) + col = col + 1 local mode = vim.fn.mode() local game_mode = { @@ -177,7 +178,7 @@ M.status_line = function() ["\22"] = "sneaking", -- CTRL-V } return string.format( - " %s | floor %s | turn %s | health %s | Line: %d, Col: %d ", + " %s | floor %s | turn %s | health %s | position %d,%d ", game_mode[mode] or mode, state.current_floor, state.turn_counter, diff --git a/lua/neohack/init.lua b/lua/neohack/init.lua index 60c115c..682350d 100644 --- a/lua/neohack/init.lua +++ b/lua/neohack/init.lua @@ -42,8 +42,6 @@ M.setup = function(opts) ) vim.api.nvim_create_user_command("EndGame", M.end_game, { nargs = 0, desc = "End the current NeoHack game" }) - - vim.o.statusline = "%!v:lua.require'neohack'.status_line()" end M.status_line = function() From 3f1942a6070d0e5fd48c82f5d4b794e8a440082f Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 16:20:34 +1100 Subject: [PATCH 11/31] feat: don't show which-key when entering visual mode, just for normal --- lua/config.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lua/config.lua b/lua/config.lua index 0a42ecf..b6be9fb 100644 --- a/lua/config.lua +++ b/lua/config.lua @@ -56,6 +56,14 @@ require("lazy").setup({ desc = "Buffer Local Keymaps (which-key)", }, }, + config = function() + require("which-key").setup({ + triggers = { + { "", mode = "n" }, + { "a", mode = { "n" } }, + }, + }) + end, }, { -- "caspersg/neohack.nvim", From a08307994f5431cb9546be30e89379ab2e32419c Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 18:12:10 +1100 Subject: [PATCH 12/31] test: add test for find_deleted_positions --- tests/map_spec.lua | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/map_spec.lua diff --git a/tests/map_spec.lua b/tests/map_spec.lua new file mode 100644 index 0000000..419a02b --- /dev/null +++ b/tests/map_spec.lua @@ -0,0 +1,56 @@ +-- lsp action, mark describe as defined global +local map = require("neohack.map") +local Entity = require("neohack.entity") +local message = require("neohack.message") + +local match = require("luassert.match") +---@diagnostic disable-next-line: undefined-field +local eq = assert.is.equal +local not_nil = match.is_not_nil + +local function newE(name) + ---@diagnostic disable-next-line: missing-fields + return Entity.new({ char = name, name = "entity " .. name }, 1, 1) +end + +describe("find_deleted_positions", function() + message.notify_func = print + + it("finds deleted", function() + local old = { + { newE("a"), newE("b"), newE("c") }, + { newE("d"), newE("e"), newE("f") }, + { newE("g"), newE("h"), newE("i") }, + { newE("j"), newE("k"), newE("l") }, + { newE("m"), newE("n"), newE("o") }, + } + + local new = { + { newE(" "), newE("b"), newE("c") }, + { newE("d"), newE(" "), newE("f") }, + { newE("g"), newE("h"), newE(" ") }, + { newE("l") }, + { newE("m") }, + } + + local result, _ = map.find_deleted_positions(old, new) + + local deleted = "" + for _, entity in ipairs(result) do + deleted = deleted .. entity.char + end + -- eq("aeijkno", deleted) + -- TODO: this is not correct, it should be "aeijkno" + eq("aeijklno", deleted) + eq(8, #result) + eq("entity a", result[1].name) + eq("entity e", result[2].name) + eq("entity i", result[3].name) + eq("entity j", result[4].name) + eq("entity k", result[5].name) + -- TODO: this is not correct, l should not be deleted + eq("entity l", result[6].name) + eq("entity n", result[7].name) + eq("entity o", result[8].name) + end) +end) From 54a0b3b438f69e3fe34e6a99b8464f2a3b08b93e Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 18:28:52 +1100 Subject: [PATCH 13/31] feat: use a better way to get inserted characters, after edit is done --- lua/neohack/buffer.lua | 3 ++- lua/neohack/edits.lua | 10 +++++++--- lua/neohack/game.lua | 3 +-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lua/neohack/buffer.lua b/lua/neohack/buffer.lua index 17353c3..a115329 100644 --- a/lua/neohack/buffer.lua +++ b/lua/neohack/buffer.lua @@ -127,7 +127,8 @@ end --- Add insert handlers for a specific buffer ---@param bufnr integer M.add_insert_handlers = function(bufnr) - vim.api.nvim_create_autocmd("InsertCharPre", { + -- vim.api.nvim_create_autocmd("InsertCharPre", { + vim.api.nvim_create_autocmd("TextChangedI", { group = group, buffer = bufnr, callback = function() diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 9062df7..368e681 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -13,11 +13,15 @@ local event = require("neohack.event") local actions = require("neohack.actions") ---comment ----@param char string -M.handle_insert = function(char) +M.handle_insert = function() -- message.notify("handle_insert '" .. char .. "'") -- just store the text as it's inserted - state.inserted = state.inserted .. char + -- local char = vim.api.nvim_get_vvar("char") + -- state.inserted = state.inserted .. char + local line = vim.api.nvim_get_current_line() + local cursor_col = vim.api.nvim_win_get_cursor(0)[2] + state.inserted = line:sub(1, cursor_col) + -- message.notify("handle_insert " .. cursor_col .. " inserted '" .. state.inserted .. "'") -- local row, col = buffer.get_under_cursor() -- if char ~= defs.floor.char then diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index e09f841..ddb9b1c 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -102,8 +102,7 @@ M.handle_insert = function() if player.is_dead() then M.end_game() end - local char = vim.api.nvim_get_vvar("char") - edits.handle_insert(char) + edits.handle_insert() end ---comment From 6f90a5136f4e9db15f59a10638e5c4a44e1feeb2 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 18:29:21 +1100 Subject: [PATCH 14/31] fix: keymap for help and inventory --- lua/neohack/actions.lua | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index e89fc64..4120b0b 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -212,12 +212,8 @@ M.setup = function(bufnr, tick) vim.keymap.set("n", M.leader_key .. key, func, { buffer = bufnr, desc = desc }) end - map("?", function() - M.insert_action("help") - end, "help") - map("i", function() - M.insert_action("inventory") - end, "inventory") + map("?", M.actions.help, "help") + map("i", M.actions.inventory, "inventory") map("w", M.prompt_wear, "wear") map("k", M.prompt_kick, "kick") map("f", M.prompt_fuse, "fuse") From 5753701a2cd3f664bba850b31756b1bea2d1cf55 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Fri, 27 Dec 2024 23:18:38 +1100 Subject: [PATCH 15/31] feat: add some chat failure messages --- lua/neohack/actions.lua | 3 +- lua/neohack/chat.lua | 107 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 lua/neohack/chat.lua diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index 4120b0b..71ce200 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -1,3 +1,4 @@ +local chat = require("neohack.chat") local M = { leader_key = nil, tick = nil, @@ -194,7 +195,7 @@ M.parse_action = function(inserted_chars) local action_name = table.remove(words, 1) local action = M.actions[action_name] if action == nil then - message.notify("Don't know how to " .. action_name .. " " .. table.concat(words, " ")) + chat.no_action(action_name, words) else action(words) end diff --git a/lua/neohack/chat.lua b/lua/neohack/chat.lua new file mode 100644 index 0000000..4d5cb65 --- /dev/null +++ b/lua/neohack/chat.lua @@ -0,0 +1,107 @@ +local message = require("neohack.message") + +local M = {} + +M.no_actions_one = { + "computer says no", + "You forgot how to %s", + "You could %s but you decide not to", + "You %s but then nothing happened", + "You tried to %s but it was a bit embarassing", + "You %s again and again but it just doesn't work", + "I’m sorry, Dave. I’m afraid I can’t do that", + + "Why would you want to %s, even Gandalf would be confused.", + "Attempting to %s? You must be as lost as a hobbit in Mordor.", + "You can't just %s and expect dragons to bow to you.", + "Trying to %s? This ain't your first rodeo, pal.", + "You've got some nerve trying to %s in this town.", + "You can't just %s; this isn't a pulp fiction novel.", + "Arrr, ye can't %s without me parrot's permission.", + "Trying to %s? You're walking the plank for sure!", + "Even Blackbeard himself wouldn't dare to %s.", + "Are you trying to %s? That's not how wormholes work!", + "You can't just %s; it defies all known laws of physics.", + "The Federation doesn’t condone attempts to %s.", + "Are you trying to %s? That's not how wormholes work!", + "You can't just %s; it defies all known laws of physics.", + "The Federation doesn’t condone attempts to %s.", + "You're gonna try to %s? Well, I'll be a tumbleweed's uncle.", + "In this dusty town, folks don't take kindly to those who %s.", + "You can't just %s, not even with the sheriff's badge.", + "Trying to %s? Not even Superman can pull that off.", + "You can't %s; even the Justice League is stumped.", + "That’s a super-villain move, trying to %s.", + "Did you just try to %s? That's like rebooting a toaster.", + "You can't %s; this isn't a sci-fi movie.", + "Attempting to %s? That’s a 404 error waiting to happen.", + "You think you can %s? Even Merlin would be stumped.", + "Trying to %s? Did you forget your spellbook?", + "You can't just %s; the elves would be appalled.", + "Trying to %s? That's more suspicious than a raincoat in the desert.", + "You can't %s; it's not in the cards, gumshoe.", + "You wanna %s? This ain't my first case, rookie.", + "Ahoy! You can't %s without a proper Jolly Roger.", + "Trying to %s? Ye must be three sheets to the wind.", + "You can't %s; even Davy Jones would laugh.", + "Attempt to %s? That's light-years away from possible.", + "You can’t just %s; it’s against the Galactic Code.", + "Trying to %s? You must be from an alternate dimension.", + "You reckon you can %s? Not in this dusty town, partner.", + "Trying to %s? That's a showdown waiting to happen.", + "You can't %s; even the tumbleweeds disagree.", + "Thinking you can %s? Not even with all the superpowers combined.", + "Trying to %s? That's beyond even the Avengers’ paygrade.", + "You can’t %s; it's not on the superhero registry.", + "Attempting to %s? That's a firmware update you don't have.", + "You can't just %s; not even the latest patch can fix that.", + "Trying to %s? You must have encountered a serious bug.", +} + +M.no_actions_more = { + "computer says no", + "I’m sorry, Dave. I’m afraid I can’t do that", + "Why would you want to %s especially with a %s", + + "I'm pretty sure you can't %s a %s without some serious magic involved.", + "Have you tried turning it off and on again? Because you definitely can't %s with a %s.", + "In which universe does it make sense to %s a %s? Not this one, that's for sure!", + "Do you have a permit to %s a %s? Thought so.", + "Even the wizards of yore couldn't %s a %s. Nice try, though!", + "Attempting to %s a %s is like trying to teach a fish to climb a tree. Good luck!", + "This isn't your ordinary %s. Trying to %s it is downright impossible.", + "I've seen many things in my time, but trying to %s a %s takes the cake.", + "Unless you're hiding superpowers, you can't %s a %s here.", + "Trying to %s a %s? That's a one-way ticket to nowhere!", + "Are you trying to %s with a %s? I'm not sure Larry himself would dare!", + "Did you really think %sing a %s would get you anywhere here? Nice try, Casanova.", + "Oh, you naughty thing! %sing a %s won't win you any points in this game.", + "If Larry can't %s a %s, then neither can you. Let's try something less... adventurous.", + "Ah, the classic %s a %s move. Too bad it's as useful as a broken heart.", + "Even Leisure Suit Larry would blush at the thought of %sing a %s!", + "Trying to %s a %s? This isn't that kind of adventure, if you know what I mean.", + "I'm flattered, but no amount of charm will let you %s a %s here.", + "Not even Larry's smooth moves can make %sing a %s a thing.", + "Whoa there, tiger! %sing a %s is a no-go, even for someone as suave as you.", + "Houston, we have a problem! %sing a %s is as effective as a broken hyperspace drive.", + "Did you really think %sing a %s would help? You must be stuck in a temporal anomaly!", + "Even the Sarien battlecruisers would laugh at the thought of %sing a %s!", + "That's a negative on the %s with a %s. Better recalibrate your tricorder.", + "Attempting to %s a %s? Not even StarCon Academy would approve of that maneuver.", + "You’re trying to %s a %s? I’d say that’s an out-of-this-world mistake!", + "Attempting to %s a %s? You'd have better luck navigating the Labion Terror Beast.", + "Roger, your attempt to %s a %s is more baffling than a two-headed, Martian pygmy!", + "Engage your brain, space cadet! %sing a %s isn't in this galaxy's protocol.", +} + +M.no_action = function(action, rest) + if rest and #rest > 0 then + local msg = M.no_actions_more[math.random(#M.no_actions_more)] + message.notify(string.format(msg, action, table.concat(rest, " "))) + else + local msg = M.no_actions_one[math.random(#M.no_actions_one)] + message.notify(string.format(msg, action)) + end +end + +return M From 85509a34a1a0f45640666e5ceb66da9f5af3cb5c Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sat, 28 Dec 2024 14:53:53 +1100 Subject: [PATCH 16/31] feat: parse action object target instead of word lists. fix space in enemy corpse name --- data/items.txt | 1 + lua/neohack/actions.lua | 44 +++++++-------- lua/neohack/chat.lua | 116 +++++++++++++++++++++++++++++++++++++--- lua/neohack/edits.lua | 8 +-- lua/neohack/entity.lua | 2 +- lua/neohack/event.lua | 4 +- 6 files changed, 141 insertions(+), 34 deletions(-) diff --git a/data/items.txt b/data/items.txt index fd7e6a4..bc54915 100644 --- a/data/items.txt +++ b/data/items.txt @@ -1310,3 +1310,4 @@ the_g_sword hero_crystal nothung_blade goliad_mind_gem +xyzzy diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index 71ce200..70c5355 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -17,48 +17,49 @@ M.actions = { end, ---comment - kick = function(words) - event.kick(words[1]) + kick = function(request) + event.kick(request.object) M.tick() end, ---comment - wear = function(words) - player.wear(words[1], words[2]) + wear = function(request) + player.wear(request.object, request.target) end, ---comment - fuse = function(words) - player.fuse(words) + fuse = function(request) + --TODO: allow for multiple objects? or just keep to object and target + player.fuse({ request.object, request.target }) M.tick() end, ---comment - look = function(words) - player.look(words) + look = function(request) + player.look({ request.object }) end, ---comment - eat = function(words) - player.eat(words) + eat = function(request) + player.eat({ request.object }) M.tick() end, ---comment - drop = function(words) - player.drop(words) + drop = function(request) + player.drop({ request.object }) M.tick() end, ---comment - say = function(words) - event.say(words) + say = function(request) + event.say({ request.object, request.target }) M.tick() end, ---comment - wait = function(words) - local count = utils.string_to_int(words[1]) + wait = function(request) + local count = utils.string_to_int(request.object) if count then message.notify("Waiting " .. count .. " turns") for _ = 1, count do @@ -188,16 +189,15 @@ end ---parse a string into performing an action ---@param inserted_chars string M.parse_action = function(inserted_chars) - local words = utils.split_words(inserted_chars) - if words == nil or #words == 0 then + local request = chat.parse_request(inserted_chars) + if request == nil then return end - local action_name = table.remove(words, 1) - local action = M.actions[action_name] + local action = M.actions[request.action] if action == nil then - chat.no_action(action_name, words) + chat.no_action(request) else - action(words) + action(request) end end diff --git a/lua/neohack/chat.lua b/lua/neohack/chat.lua index 4d5cb65..86fe723 100644 --- a/lua/neohack/chat.lua +++ b/lua/neohack/chat.lua @@ -1,7 +1,30 @@ local message = require("neohack.message") +local utils = require("neohack.utils") local M = {} +--- You can do an action with an object to a target +---@class Request +---@field action string +---@field object string|nil +---@field target string|nil + +---comment +---@param raw_string string +---@return Request|nil +M.parse_request = function(raw_string) + local words = utils.split_words(raw_string) + if words == nil or #words == 0 then + return nil + end + + return { + action = words[1], + object = words[2], + target = words[3], + } +end + M.no_actions_one = { "computer says no", "You forgot how to %s", @@ -56,9 +79,19 @@ M.no_actions_one = { "Attempting to %s? That's a firmware update you don't have.", "You can't just %s; not even the latest patch can fix that.", "Trying to %s? You must have encountered a serious bug.", + "You really want to %s? That's as sensible as Vogon poetry.", + "Thinking you can %s? You'd need a Pan Galactic Gargle Blaster for that.", + "Planning to %s? Don't forget your towel!", + "Attempting to %s? Not even Zaphod would dare.", + "Going to %s? Marvin would find that depressing.", + "Trying to %s? That's utterly improbable.", + "About to %s? Make sure it's not Thursday.", + "Hoping to %s? Even the Guide would advise against it.", + "Preparing to %s? That's a job for the Heart of Gold.", + "Believing you can %s? You must have the Infinite Improbability Drive.", } -M.no_actions_more = { +M.no_actions_two = { "computer says no", "I’m sorry, Dave. I’m afraid I can’t do that", "Why would you want to %s especially with a %s", @@ -92,15 +125,86 @@ M.no_actions_more = { "Attempting to %s a %s? You'd have better luck navigating the Labion Terror Beast.", "Roger, your attempt to %s a %s is more baffling than a two-headed, Martian pygmy!", "Engage your brain, space cadet! %sing a %s isn't in this galaxy's protocol.", + "Attempting to %s with a %s? That's as sensible as Vogon poetry.", + "Trying to %s with a %s? You'd have better luck with a Pan Galactic Gargle Blaster.", + "You think you can %s with a %s? Not without your trusty towel.", + "Not even Zaphod Beeblebrox would %s with a %s.", + "You're as optimistic as Marvin trying to %s with a %s.", + "Imagine trying to %s with a %s. Utterly improbable.", + "Only a hitchhiker would try to %s with a %s.", + "That's as peculiar as trying to %s with a %s.", + "Even the Guide wouldn't recommend trying to %s with a %s.", + "That's as futile as trying to %s with a %s.", +} + +M.no_actions_three = { + "Nobody ever tried to %s a %s in the %s before, congratulations!", + "Is not valid bencoding err:%s status:%s stacktrace:%s", + + "You really think you can %s with a %s in the %s? Good luck!", + "That's a bold move to %s with a %s near the %s!", + "Attempting to %s with a %s on the %s? That's hilarious.", + "Not even the bravest adventurer would %s with a %s under the %s.", + "Trying to %s with a %s next to the %s is just asking for trouble.", + "Imagine trying to %s with a %s inside the %s. Ridiculous!", + "You must be out of your mind to %s with a %s outside the %s.", + "That's as crazy as trying to %s with a %s above the %s.", + "Nobody in their right mind would %s with a %s below the %s.", + "That's as futile as trying to %s with a %s in front of the %s.", + "Trying to %s with a %s in the %s? That's a one-way ticket to the chief's office.", + "Attempting to %s with a %s near the %s? That's not in the training manual.", + "You call that police work? %s with a %s on the %s is just reckless.", + "Not even the most decorated officer would %s with a %s under the %s.", + "You're as bold as they come to %s with a %s next to the %s.", + "Just imagine trying to %s with a %s inside the %s. Absurd!", + "Only a rookie would try to %s with a %s outside the %s.", + "That's as futile as trying to %s with a %s above the %s.", + "You're asking for trouble if you try to %s with a %s below the %s.", + "That's as laughable as trying to %s with a %s in front of the %s.", + "You think you can %s with a %s in the %s? That's against protocol!", + "Only a rookie would attempt to %s with a %s near the %s.", + "Trying to %s with a %s on the %s? That's a fast track to a reprimand.", + "Even the chief would shake his head at trying to %s with a %s under the %s.", + "You’re braver than most to %s with a %s next to the %s.", + "Imagine the paperwork if you tried to %s with a %s inside the %s.", + "You must be joking if you think you can %s with a %s outside the %s.", + "That's as futile as trying to %s with a %s above the %s.", + "You're asking for a lecture if you try to %s with a %s below the %s.", + "That's as ridiculous as trying to %s with a %s in front of the %s.", + "Attempting to %s with a %s in the %s? Even King Graham would be puzzled.", + "Trying to %s with a %s near the %s? That's as strange as a talking owl.", + "You think you can %s with a %s on the %s? Only in Daventry!", + "Not even a magic spell can help you %s with a %s under the %s.", + "You're as brave as a knight to %s with a %s next to the %s.", + "Imagine trying to %s with a %s inside the %s. Utterly fantastical!", + "Only a true adventurer would try to %s with a %s outside the %s.", + "That's as peculiar as trying to %s with a %s above the %s.", + "Even the gnomes would laugh at trying to %s with a %s below the %s.", + "That's as whimsical as trying to %s with a %s in front of the %s.", + "Attempting to %s with a %s in the %s? That's as sensible as Vogon poetry.", + "Trying to %s with a %s near the %s? You'd have better luck with a Pan Galactic Gargle Blaster.", + "You think you can %s with a %s on the %s? Not without your trusty towel.", + "Not even Zaphod Beeblebrox would %s with a %s under the %s.", + "You're as optimistic as Marvin trying to %s with a %s next to the %s.", + "Imagine trying to %s with a %s inside the %s. Utterly improbably.", + "Only a hitchhiker would try to %s with a %s outside the %s.", + "That's as peculiar as trying to %s with a %s above the %s.", + "Even the Guide wouldn't recommend trying to %s with a %s below the %s.", + "That's as futile as trying to %s with a %s in front of the Heart of Gold.", } -M.no_action = function(action, rest) - if rest and #rest > 0 then - local msg = M.no_actions_more[math.random(#M.no_actions_more)] - message.notify(string.format(msg, action, table.concat(rest, " "))) +---comment +---@param request Request +M.no_action = function(request) + if request.target then + local msg = M.no_actions_three[math.random(#M.no_actions_three)] + message.notify(string.format(msg, request.action, request.object, request.target)) + elseif request.object then + local msg = M.no_actions_two[math.random(#M.no_actions_two)] + message.notify(string.format(msg, request.action, request.object)) else local msg = M.no_actions_one[math.random(#M.no_actions_one)] - message.notify(string.format(msg, action)) + message.notify(string.format(msg, request.action)) end end diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 368e681..94abe40 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -14,14 +14,16 @@ local actions = require("neohack.actions") ---comment M.handle_insert = function() - -- message.notify("handle_insert '" .. char .. "'") - -- just store the text as it's inserted + -- TODO: this doesn't allow for backspace -- local char = vim.api.nvim_get_vvar("char") -- state.inserted = state.inserted .. char + -- + --TODO: this gets the whole line up to the cursor local line = vim.api.nvim_get_current_line() local cursor_col = vim.api.nvim_win_get_cursor(0)[2] state.inserted = line:sub(1, cursor_col) - -- message.notify("handle_insert " .. cursor_col .. " inserted '" .. state.inserted .. "'") + + message.notify("handle_insert '" .. state.inserted .. "'") -- local row, col = buffer.get_under_cursor() -- if char ~= defs.floor.char then diff --git a/lua/neohack/entity.lua b/lua/neohack/entity.lua index f54ed9b..29a140b 100644 --- a/lua/neohack/entity.lua +++ b/lua/neohack/entity.lua @@ -124,7 +124,7 @@ end function Entity:check_dead() if self.health <= 0 then self.char = Entity.enemy_corpse - self.name = self.name .. " corpse" + self.name = self.name .. "_corpse" self.type = Def.DefType.item self.block_vision = false return true diff --git a/lua/neohack/event.lua b/lua/neohack/event.lua index 764bf72..5e61168 100644 --- a/lua/neohack/event.lua +++ b/lua/neohack/event.lua @@ -162,7 +162,7 @@ M.move_enemies = function() -- message.notify("enemies " .. vim.inspect(enemies)) for _, enemy in ipairs(enemies) do if enemy:check_dead() then - message.notify(string.gsub(enemy.name, " corpse", "") .. " died") + message.notify(string.gsub(enemy.name, "_corpse", "") .. " died") else M.move_closer_to(enemy, finalRow, finalCol, M.enemy_try_move) if enemy.hit_highlight then @@ -182,7 +182,7 @@ M.move_friends = function() -- message.notify("friends " .. vim.inspect(friends)) for _, friend in ipairs(friends) do if friend:check_dead() then - message.notify(string.gsub(friend.name, " corpse", "") .. " died") + message.notify(string.gsub(friend.name, "_corpse", "") .. " died") else M.move_closer_to(friend, finalRow, finalCol, M.friend_try_move) if friend.hit_highlight then From bb725b12923956327f8d3832478ee4c5e75978bf Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sat, 28 Dec 2024 15:07:56 +1100 Subject: [PATCH 17/31] fix: mostly fix insert text issues. but doesn't deal with cursor movements in insert mode --- lua/neohack/buffer.lua | 21 ++++++++++++++++++++- lua/neohack/edits.lua | 11 +++++++++-- lua/neohack/game.lua | 6 ++++++ lua/neohack/state.lua | 3 +++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lua/neohack/buffer.lua b/lua/neohack/buffer.lua index a115329..1082310 100644 --- a/lua/neohack/buffer.lua +++ b/lua/neohack/buffer.lua @@ -8,6 +8,7 @@ --- @field buf_settings table --- @field handle_moved function --- @field handle_insert function +--- @field handle_insert_enter function --- @field handle_changed function --- @field handle_yanked function @@ -37,6 +38,7 @@ local function init_buffer(bufnr, handlers) buf_settings = nil, handle_moved = handlers.handle_moved, handle_insert = handlers.handle_insert, + handle_insert_enter = handlers.handle_insert_enter, handle_changed = handlers.handle_changed, handle_yanked = handlers.handle_yanked, } @@ -94,7 +96,13 @@ end ---@param bufnr integer M.add_handlers = function(bufnr) local buf_data = M.buffers[bufnr] - if buf_data.handle_moved and buf_data.handle_insert and buf_data.handle_changed and buf_data.handle_yanked then + if + buf_data.handle_moved + and buf_data.handle_insert + and buf_data.handle_insert_enter + and buf_data.handle_changed + and buf_data.handle_yanked + then M.add_moved_handlers(bufnr) M.add_insert_handlers(bufnr) M.add_change_handlers(bufnr) @@ -138,6 +146,17 @@ M.add_insert_handlers = function(bufnr) -- end) end, }) + + vim.api.nvim_create_autocmd("InsertEnter", { + group = group, + buffer = bufnr, + callback = function() + M.buffers[bufnr].handle_insert_enter() + -- vim.schedule(function() + -- M.write_buf(bufnr) + -- end) + end, + }) end --- Add change handlers for a specific buffer diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 94abe40..7b4c32d 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -12,16 +12,22 @@ local chance = require("neohack.chance") local event = require("neohack.event") local actions = require("neohack.actions") +M.handle_insert_enter = function() + state.insert_enter_col = vim.api.nvim_win_get_cursor(0)[2] +end + ---comment M.handle_insert = function() -- TODO: this doesn't allow for backspace + -- with InsertCharPre -- local char = vim.api.nvim_get_vvar("char") -- state.inserted = state.inserted .. char -- - --TODO: this gets the whole line up to the cursor + --TODO: this gets confused if arrow keys are used + -- with TextChangedI local line = vim.api.nvim_get_current_line() local cursor_col = vim.api.nvim_win_get_cursor(0)[2] - state.inserted = line:sub(1, cursor_col) + state.inserted = line:sub(state.insert_enter_col + 1, cursor_col) message.notify("handle_insert '" .. state.inserted .. "'") @@ -51,6 +57,7 @@ end M.handle_inserted = function() local inserted_chars = state.inserted state.inserted = "" + state.insert_enter_col = 1 if #inserted_chars > 0 then -- reset cursor position before performing any action buffer.move_prev_cursor() diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index ddb9b1c..9784c0f 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -43,6 +43,7 @@ M.create_new_buffer = function(lines) local bufnr, level = buffer.create_new_buffer(lines, { handle_moved = M.handle_moved, handle_insert = M.handle_insert, + handle_insert_enter = M.handle_insert_enter, handle_changed = M.handle_changed, handle_yanked = M.handle_yanked, }) @@ -105,6 +106,11 @@ M.handle_insert = function() edits.handle_insert() end +---comment +M.handle_insert_enter = function() + edits.handle_insert_enter() +end + ---comment M.handle_changed = function() if player.is_dead() then diff --git a/lua/neohack/state.lua b/lua/neohack/state.lua index fa5284d..dff8368 100644 --- a/lua/neohack/state.lua +++ b/lua/neohack/state.lua @@ -58,6 +58,9 @@ local M = { ---@type string inserted = "", + ---@type integer + insert_enter_col = 1, + --- previous player corpse corpse = { ---@type integer From d3b9af269b118b158d9d25c026baacdc6e62330b Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 15:08:22 +1100 Subject: [PATCH 18/31] feat: insert a new request on each line --- lua/neohack/edits.lua | 33 ++++++++++++++++++++++----------- lua/neohack/game.lua | 2 +- lua/neohack/state.lua | 8 ++++---- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 7b4c32d..0ffa665 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -13,7 +13,8 @@ local event = require("neohack.event") local actions = require("neohack.actions") M.handle_insert_enter = function() - state.insert_enter_col = vim.api.nvim_win_get_cursor(0)[2] + state.insert_enter_start = vim.api.nvim_win_get_cursor(0) + -- message.notify("handle_insert_enter " .. vim.inspect(state.insert_enter_start)) end ---comment @@ -25,11 +26,19 @@ M.handle_insert = function() -- --TODO: this gets confused if arrow keys are used -- with TextChangedI - local line = vim.api.nvim_get_current_line() - local cursor_col = vim.api.nvim_win_get_cursor(0)[2] - state.inserted = line:sub(state.insert_enter_col + 1, cursor_col) + local cursor_row, cursor_col = unpack(vim.api.nvim_win_get_cursor(0)) - message.notify("handle_insert '" .. state.inserted .. "'") + local lines = vim.api.nvim_buf_get_text( + state.current_bufnr, + state.insert_enter_start[1] - 1, + state.insert_enter_start[2], + cursor_row - 1, + cursor_col, + {} + ) + state.inserted = lines + + -- message.notify("handle_insert '" .. table.concat(state.inserted, "\n") .. "'") -- local row, col = buffer.get_under_cursor() -- if char ~= defs.floor.char then @@ -54,15 +63,17 @@ M.handle_insert = function() -- end end -M.handle_inserted = function() - local inserted_chars = state.inserted - state.inserted = "" - state.insert_enter_col = 1 - if #inserted_chars > 0 then +M.handle_insert_exit = function() + local inserted = state.inserted + state.inserted = {} + state.insert_enter_start = {} + if #inserted > 0 then -- reset cursor position before performing any action buffer.move_prev_cursor() - actions.parse_action(inserted_chars) + for _, line in ipairs(inserted) do + actions.parse_action(line) + end end end diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index 9784c0f..85972b4 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -153,7 +153,7 @@ M.tick = function() -- detect deleted on every turn state.deleted = map.find_deleted(state.current_bufnr) - edits.handle_inserted() + edits.handle_insert_exit() event.player_move() diff --git a/lua/neohack/state.lua b/lua/neohack/state.lua index dff8368..be92d83 100644 --- a/lua/neohack/state.lua +++ b/lua/neohack/state.lua @@ -55,11 +55,11 @@ local M = { ---@type Entity[] deleted = nil, - ---@type string - inserted = "", + ---@type string[] + inserted = {}, - ---@type integer - insert_enter_col = 1, + ---@type integer[] + insert_enter_start = {}, --- previous player corpse corpse = { From 11e73b56de6bbc7e91428b901427e0e70d348bd7 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 16:42:14 +1100 Subject: [PATCH 19/31] fix: menu actions --- README.md | 2 ++ lua/neohack/actions.lua | 74 +++++++++++++++++++++++------------------ lua/neohack/edits.lua | 3 ++ lua/neohack/player.lua | 8 +++-- 4 files changed, 52 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 9c31f08..ac2f4b2 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,8 @@ Actions - [ ] jumplist - ??? - [ ] use registers for inventory - [x] insert to run actions + - [ ] dot repeat + - doesn't seem possible, as game loop sets the last change - [ ] macros - [x] varied entities - [x] item and enemy generation from dictionary diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index 70c5355..ed483e9 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -73,13 +73,13 @@ M.actions = { message.notify( ":EndGame to quit.\n" .. ":StartGame to restart.\n" - .. "Move cursor in normal mode to move and attack. " - .. "Visual mode to sneak. " - .. "Delete to pickup items. " - .. "Insert to drop items. \n" - .. "Actions start with '" + .. "Move cursor in normal mode to move and attack.\n" + .. "Visual mode to sneak.\n" + .. "Delete to pickup items.\n" + .. "Insert to type an action. eg 'wear helmet head'\n" + .. "Or use the action keymaps, which start with '" .. M.leader_key - .. "' " + .. "'\n" .. "Actions: " .. "i to show inventory, w to wear, k to kick, f to fuse, l to look, e to eat, s to say, d to drop, to wait, ? for help" ) @@ -96,24 +96,24 @@ end M.prompt_kick = function() local direction = M.prompt_one_char("Kick direction? hjkl") if direction then - M.insert_action("kick " .. direction) - -- M.actions.kick({ direction }) + -- M.insert_action("kick " .. direction) + M.actions.kick({ object = direction }) end end ---comment M.prompt_wear = function() - local slot = M.prompt_one_char("Wear on? h:head r:right hand l:left hand b:body f:feet") - if slot then - message.notify("You have:\n0:nothing\n" .. player.get_inventory_item_with_index()) - vim.defer_fn(function() - local index_str = M.prompt_one_word("Wear what?") - if index_str then - M.insert_action("wear " .. slot .. " " .. index_str) - -- M.actions.wear({ slot, index_str }) + message.notify("You have:\n0:nothing\n" .. player.get_inventory_item_with_index()) + vim.defer_fn(function() + local object = M.prompt_one_word("Wear what?") + if object then + local slot = M.prompt_one_word("Wear on? h:head r:right_hand l:left_hand b:body f:feet") + if slot then + -- M.insert_action("wear " .. object .. " " .. slot) + M.actions.wear({ object = object, target = slot }) end - end, 50) - end + end + end, 50) end ---comment @@ -122,8 +122,11 @@ M.prompt_fuse = function() vim.defer_fn(function() local index = M.prompt("Fuse what?") if index then - M.insert_action("fuse " .. index) - -- M.actions.fuse(utils.split_words(index)) + -- M.insert_action("fuse " .. index) + local words = utils.split_words(index) + if words then + M.actions.fuse({ object = words[1], target = words[2] }) + end end end, 50) end @@ -132,10 +135,10 @@ end M.prompt_look = function() message.notify("You have:\n0:self\n" .. player.get_inventory_item_with_index()) vim.defer_fn(function() - local index = M.prompt("Look at what?") + local index = M.prompt_one_word("Look at what?") if index then - M.insert_action("look " .. index) - -- M.actions.look(utils.split_words(index)) + -- M.insert_action("look " .. index) + M.actions.look({ object = index }) end end, 50) end @@ -144,10 +147,10 @@ end M.prompt_eat = function() message.notify("You have:\n" .. player.get_inventory_item_with_index()) vim.defer_fn(function() - local index = M.prompt("Eat what?") + local index = M.prompt_one_word("Eat what?") if index then - M.insert_action("eat " .. index) - -- M.actions.eat(utils.split_words(index)) + -- M.insert_action("eat " .. index) + M.actions.eat({ object = index }) end end, 50) end @@ -156,10 +159,10 @@ end M.prompt_drop = function() message.notify("You have:\n" .. player.get_inventory_item_with_index()) vim.defer_fn(function() - local index = M.prompt("Drop what?") + local index = M.prompt_one_word("Drop what?") if index then - M.insert_action("drop " .. index) - -- M.actions.drop(utils.split_words(index)) + -- M.insert_action("drop " .. index) + M.actions.drop({ object = index }) end end, 50) end @@ -169,8 +172,11 @@ M.prompt_say = function() vim.defer_fn(function() local words = M.prompt("Say what?") if words then - M.insert_action("say " .. words) - -- M.actions.say(utils.split_words(words)) + -- M.insert_action("say " .. words) + local w = utils.split_words(words) + if w then + M.actions.say({ object = w[1], target = w[2] }) + end end end, 50) end @@ -180,8 +186,8 @@ M.prompt_wait = function() vim.defer_fn(function() local str = M.prompt_one_word("Wait how long?") if str then - M.insert_action("wait " .. str) - -- M.actions.wait({ str }) + -- M.insert_action("wait " .. str) + M.actions.wait({ object = str }) end end, 50) end @@ -214,7 +220,9 @@ M.setup = function(bufnr, tick) end map("?", M.actions.help, "help") + -- map("?", function() M.insert_action("help") end, "help") map("i", M.actions.inventory, "inventory") + -- map("i", function() M.insert_action("inventory") end, "inventory") map("w", M.prompt_wear, "wear") map("k", M.prompt_kick, "kick") map("f", M.prompt_fuse, "fuse") diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 0ffa665..3f84bfe 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -24,6 +24,9 @@ M.handle_insert = function() -- local char = vim.api.nvim_get_vvar("char") -- state.inserted = state.inserted .. char -- + -- This includes special chars for backspace + -- local dot = vim.fn.getreg(".") + -- --TODO: this gets confused if arrow keys are used -- with TextChangedI local cursor_row, cursor_col = unpack(vim.api.nvim_win_get_cursor(0)) diff --git a/lua/neohack/player.lua b/lua/neohack/player.lua index 4e785a4..fd5d353 100644 --- a/lua/neohack/player.lua +++ b/lua/neohack/player.lua @@ -313,11 +313,15 @@ M.retrieve_items = function(keys) end ---comment ----@param slot string ---@param key string -M.wear = function(slot, key) +---@param slot string either short or long, eg h or head +M.wear = function(key, slot) -- unwear the current item local p = state.player + if #slot > 1 then + -- handle slot name + slot = state.slots[slot] + end local current = p.slots[slot] if current then table.insert(state.player.items, current) From 14e2454d4b5eb61d0a230172c9ec454b4db503ef Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 16:51:30 +1100 Subject: [PATCH 20/31] fix: simplify spell casting --- lua/neohack/event.lua | 35 ++++++++++++----------------------- lua/neohack/spells.lua | 2 +- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/lua/neohack/event.lua b/lua/neohack/event.lua index 5e61168..64fbce5 100644 --- a/lua/neohack/event.lua +++ b/lua/neohack/event.lua @@ -267,36 +267,25 @@ M.say = function(words) local row, col = buffer.get_under_cursor() local enemies, items = map.scan_area(state.current_bufnr, row, col, player.view_distance()) + local seen = {} for _, enemy in ipairs(enemies) do - local cast = (#casting > 0 and " cast " .. spell_names) or "" - if string.find(word_str, string.upper(enemy.name)) ~= nil then - message.notify("The " .. enemy.name .. " HEARD you" .. cast) - for _, spell in ipairs(casting) do - spell.inscription.effect.cast(enemy, 1) - message.notify("Cast " .. string.upper(spell.inscription.effect.name) .. " on " .. enemy.name) - end - elseif string.find(word_str, enemy.name) ~= nil then - message.notify("The " .. enemy.name .. " heard you" .. cast) - for _, spell in ipairs(casting) do - spell.inscription.effect.cast(enemy, 0.6) - message.notify("Cast " .. spell.inscription.effect.name .. " on " .. enemy.name) - end - end + table.insert(seen, enemy) end - for _, item in ipairs(items) do - if string.find(word_str, string.upper(item.name)) ~= nil then - for _, spell in ipairs(casting) do - spell.inscription.effect.cast(item, 1) - message.notify("Cast " .. string.upper(spell.inscription.effect.name) .. " on " .. item.name) + table.insert(seen, item) + end + + for _, entity in ipairs(seen) do + local cast = (#casting > 0 and " cast " .. spell_names) or "" + if string.find(word_str, entity.name) ~= nil then + if entity.type == Def.DefType.enemy then + message.notify("The " .. entity.name .. " heard you" .. cast) end - elseif string.find(word_str, item.name) ~= nil then for _, spell in ipairs(casting) do - spell.inscription.effect.cast(item, 0.6) - message.notify("Cast " .. spell.inscription.effect.name .. " on " .. item.name) + spell.inscription.effect.cast(entity, 1) + message.notify("Cast " .. spell.inscription.effect.name .. " on " .. entity.name) end end - -- enemy:hear() end end diff --git a/lua/neohack/spells.lua b/lua/neohack/spells.lua index 6739293..33fd0ad 100644 --- a/lua/neohack/spells.lua +++ b/lua/neohack/spells.lua @@ -114,7 +114,7 @@ M.effects = { }, disruption = { - name = "disruption ", + name = "disruption", cast = function(target, amount) target.hit_rate = target.hit_rate - (1 * amount) end, From 29b70aa748a48b64b797570a85482c3bd4ea8578 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 17:11:15 +1100 Subject: [PATCH 21/31] chore: hide some debug logs --- lua/neohack/actions.lua | 1 + lua/neohack/chance.lua | 28 ++++++++++++++-------------- lua/neohack/edits.lua | 3 ++- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lua/neohack/actions.lua b/lua/neohack/actions.lua index ed483e9..6b5902f 100644 --- a/lua/neohack/actions.lua +++ b/lua/neohack/actions.lua @@ -74,6 +74,7 @@ M.actions = { ":EndGame to quit.\n" .. ":StartGame to restart.\n" .. "Move cursor in normal mode to move and attack.\n" + .. "Yank to search for items.\n" .. "Visual mode to sneak.\n" .. "Delete to pickup items.\n" .. "Insert to type an action. eg 'wear helmet head'\n" diff --git a/lua/neohack/chance.lua b/lua/neohack/chance.lua index 7aebe11..d14c8f9 100644 --- a/lua/neohack/chance.lua +++ b/lua/neohack/chance.lua @@ -14,20 +14,20 @@ M.action_success = function(skill, advantage, resistance, threshold) local random = math.random() - 0.5 local level_resistance = resistance + (state.current_floor * 0.1) local success_chance = skill + advantage - level_resistance + random - message.notify( - "action_success chance: " - .. success_chance - .. ", skill:" - .. skill - .. ", advantage: " - .. advantage - .. ", level_resistance: " - .. level_resistance - .. ", random: " - .. random - .. ", threshold: " - .. threshold - ) + -- message.notify( + -- "action_success chance: " + -- .. success_chance + -- .. ", skill:" + -- .. skill + -- .. ", advantage: " + -- .. advantage + -- .. ", level_resistance: " + -- .. level_resistance + -- .. ", random: " + -- .. random + -- .. ", threshold: " + -- .. threshold + -- ) return success_chance > threshold end diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 3f84bfe..de9b2e8 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -85,6 +85,7 @@ M.handle_changed = function() -- happens outside the tick -- don't use cached buffer, manipulate the buf directly -- otherwise changed event gets triggered + -- TODO: this will still be set after a yank, find a way to avoid that local deleted_chars = vim.fn.getreg('"') -- message.notify("handle_changed '" .. deleted_chars .. "'") -- this could be deleted chars, or changed chars after an insert @@ -123,7 +124,7 @@ M.handle_changed = function() end if not all_items then vim.cmd("normal! u") - message.notify("Can't pickup non items '" .. deleted_chars .. "'") + -- message.notify("Can't pickup non items '" .. deleted_chars .. "'") else -- -- deleted not always under cursor -- -- handles changes on one line From 790dfd498a8f336c599597679bacb5c3c5f0b3a6 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 17:41:26 +1100 Subject: [PATCH 22/31] fix: bug with delete with same char on line --- lua/neohack/edits.lua | 53 +++++++++++++++++++++++++++---------------- tests/map_spec.lua | 7 ++++-- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index de9b2e8..72fdd8d 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -91,7 +91,7 @@ M.handle_changed = function() -- this could be deleted chars, or changed chars after an insert if #deleted_chars > 0 then - -- message.notify("Deleted characters: '" .. deleted_chars .. "'") + message.notify("Deleted characters: '" .. deleted_chars .. "'") -- ---@type Entity[] local deleted_entities = state.deleted local deleted_e = "" @@ -99,7 +99,8 @@ M.handle_changed = function() -- message.notify("Deleted entity: '" .. vim.inspect(entity) .. "'") deleted_e = deleted_e .. entity.char end - -- message.notify("Deleted entities: '" .. deleted_e .. "'") + -- TODO: deleted_entities includes other chars for some reason + message.notify("Deleted entities: '" .. deleted_e .. "'") ---@type Entity[] local entities = {} @@ -126,27 +127,39 @@ M.handle_changed = function() vim.cmd("normal! u") -- message.notify("Can't pickup non items '" .. deleted_chars .. "'") else + for _, entity in ipairs(entities) do + player.pickup(entity) + buffer.set_entity_at_cell(entity.row, entity.col, defs.new_floor(entity.row, entity.col)) + + -- TODO: do this once for all entities + -- in the real buffer too, otherwise it only updates on the next tick + local line = vim.api.nvim_get_current_line() + local new_line = line:sub(1, entity.col) + .. string.rep(defs.floor.char, #deleted_chars) + .. line:sub(entity.col or #line) + vim.api.nvim_set_current_line(new_line) + end -- -- deleted not always under cursor -- -- handles changes on one line -- -- TODO: handle changes on multiple lines - local line = vim.api.nvim_get_current_line() - local startCol, endCol = line:find(deleted_chars, 1, true) - - local row = buffer.get_under_cursor() - if startCol and endCol then - for col = startCol, endCol do - local entity = buffer.get_entity_at_pos(row, col) - if entity then - player.pickup(entity) - -- fill in the deleted column in the next frame - -- message.notify("replace pickup " .. i) - end - buffer.set_entity_at_cell(row, col, defs.new_floor(row, col)) - end - end - -- in the real buffer too, otherwise it only updates on the next tick - local new_line = line:sub(1, startCol) .. string.rep(defs.floor.char, #deleted_chars) .. line:sub(endCol or #line) - vim.api.nvim_set_current_line(new_line) + -- local line = vim.api.nvim_get_current_line() + -- local startCol, endCol = line:find(deleted_chars, 1, true) + -- + -- local row = buffer.get_under_cursor() + -- if startCol and endCol then + -- for col = startCol, endCol do + -- local entity = buffer.get_entity_at_pos(row, col) + -- if entity then + -- player.pickup(entity) + -- -- fill in the deleted column in the next frame + -- -- message.notify("replace pickup " .. i) + -- end + -- buffer.set_entity_at_cell(row, col, defs.new_floor(row, col)) + -- end + -- end + -- -- in the real buffer too, otherwise it only updates on the next tick + -- local new_line = line:sub(1, startCol) .. string.rep(defs.floor.char, #deleted_chars) .. line:sub(endCol or #line) + -- vim.api.nvim_set_current_line(new_line) end end vim.fn.setreg('"', "") diff --git a/tests/map_spec.lua b/tests/map_spec.lua index 419a02b..12ad355 100644 --- a/tests/map_spec.lua +++ b/tests/map_spec.lua @@ -23,6 +23,7 @@ describe("find_deleted_positions", function() { newE("g"), newE("h"), newE("i") }, { newE("j"), newE("k"), newE("l") }, { newE("m"), newE("n"), newE("o") }, + { newE("p"), newE("q"), newE("p") }, } local new = { @@ -31,6 +32,7 @@ describe("find_deleted_positions", function() { newE("g"), newE("h"), newE(" ") }, { newE("l") }, { newE("m") }, + { newE("p"), newE("q") }, } local result, _ = map.find_deleted_positions(old, new) @@ -41,8 +43,8 @@ describe("find_deleted_positions", function() end -- eq("aeijkno", deleted) -- TODO: this is not correct, it should be "aeijkno" - eq("aeijklno", deleted) - eq(8, #result) + eq("aeijklnop", deleted) + eq(9, #result) eq("entity a", result[1].name) eq("entity e", result[2].name) eq("entity i", result[3].name) @@ -52,5 +54,6 @@ describe("find_deleted_positions", function() eq("entity l", result[6].name) eq("entity n", result[7].name) eq("entity o", result[8].name) + eq("entity p", result[9].name) end) end) From fcab14e0789735679e8fc35b8430de53ef6661c7 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 18:23:24 +1100 Subject: [PATCH 23/31] fix: multiple match bug --- lua/neohack/edits.lua | 8 ++++++-- lua/neohack/map.lua | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 72fdd8d..9521de4 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -91,6 +91,8 @@ M.handle_changed = function() -- this could be deleted chars, or changed chars after an insert if #deleted_chars > 0 then + deleted_chars = deleted_chars:gsub(" ", "") + -- deleted_chars = deleted_chars:gsub(".", "") message.notify("Deleted characters: '" .. deleted_chars .. "'") -- ---@type Entity[] local deleted_entities = state.deleted @@ -108,14 +110,16 @@ M.handle_changed = function() for i = 1, #deleted_chars do local char = deleted_chars:sub(i, i) local found = false - for _, entity in ipairs(deleted_entities) do + for e_i, entity in ipairs(deleted_entities) do if entity.char == char then found = true if not player.can_pickup(entity) then all_items = false else table.insert(entities, entity) + table.remove(deleted_entities, e_i) end + break end end if not found and char ~= defs.floor then @@ -125,7 +129,7 @@ M.handle_changed = function() end if not all_items then vim.cmd("normal! u") - -- message.notify("Can't pickup non items '" .. deleted_chars .. "'") + message.notify("Can't pickup non items '" .. deleted_chars .. "'") else for _, entity in ipairs(entities) do player.pickup(entity) diff --git a/lua/neohack/map.lua b/lua/neohack/map.lua index 956ed22..83f5aae 100644 --- a/lua/neohack/map.lua +++ b/lua/neohack/map.lua @@ -217,7 +217,19 @@ end ---@param bufnr integer ---@return Entity[][] M.find_deleted = function(bufnr) - return M.find_deleted_positions(buffer.buffers[bufnr].cells, buffer.read_a_buf(bufnr)) + local new_buffer = buffer.read_a_buf(bufnr) + local old_buffer = buffer.buffers[bufnr].cells + -- TODO: this doesn't work properly on the last line + while #new_buffer < #old_buffer do + -- there are deleted lines + local cursor_row = vim.api.nvim_win_get_cursor(0)[1] + if cursor_row == #new_buffer then + cursor_row = cursor_row + 1 + end + -- message.notify("inserted empty row at " .. cursor_row) + table.insert(new_buffer, cursor_row, {}) + end + return M.find_deleted_positions(old_buffer, new_buffer) end -- Function to compare two states of the buffer and find deleted positions @@ -233,7 +245,10 @@ M.find_deleted_positions = function(old_buffer, new_buffer) if old_buffer[row][col].visible then if not new_buffer[row] or not new_buffer[row][col] then table.insert(deleted_positions, old_buffer[row][col]) - elseif new_buffer[row][col].char ~= old_buffer[row][col].char then + elseif + new_buffer[row][col].char ~= defs.not_visible and new_buffer[row][col].char ~= old_buffer[row][col].char + then + message.notify(old_buffer[row][col].char .. " vs " .. new_buffer[row][col].char) table.insert(deleted_positions, old_buffer[row][col]) end else From 11354badaa001f118d3bb49adf55cfc6c38ab052 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 18:45:37 +1100 Subject: [PATCH 24/31] fix: use find_closest_match for delete, it's far more accurate --- lua/neohack/edits.lua | 23 +++++++++-------------- lua/neohack/game.lua | 2 +- lua/neohack/map.lua | 5 ++++- lua/neohack/state.lua | 4 ++-- lua/neohack/utils.lua | 10 ++++++++++ 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 9521de4..1f923bf 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -90,19 +90,19 @@ M.handle_changed = function() -- message.notify("handle_changed '" .. deleted_chars .. "'") -- this could be deleted chars, or changed chars after an insert - if #deleted_chars > 0 then - deleted_chars = deleted_chars:gsub(" ", "") - -- deleted_chars = deleted_chars:gsub(".", "") - message.notify("Deleted characters: '" .. deleted_chars .. "'") - -- ---@type Entity[] - local deleted_entities = state.deleted + local patterns = utils.split_lines(deleted_chars) + -- this seems to have no issues, while state.deleted just doesn't work right + local deleted_entities = map.find_closest_match(state.current_bufnr, patterns) + if #deleted_chars > 0 and deleted_entities then + -- message.notify("Deleted characters: '" .. deleted_chars .. "'") + -- state.deleted just doesn't work + -- local deleted_entities = state.deleted local deleted_e = "" for _, entity in ipairs(deleted_entities) do -- message.notify("Deleted entity: '" .. vim.inspect(entity) .. "'") deleted_e = deleted_e .. entity.char end - -- TODO: deleted_entities includes other chars for some reason - message.notify("Deleted entities: '" .. deleted_e .. "'") + -- message.notify("Deleted entities: '" .. deleted_e .. "'") ---@type Entity[] local entities = {} @@ -176,12 +176,7 @@ M.handle_yanked = function() -- message.notify("looking for '" .. yanked_chars .. "'") ---@type string[] - local patterns = {} - for line in yanked_chars:gmatch("([^\n]*)\n?") do - if #line > 0 then - table.insert(patterns, line) - end - end + local patterns = utils.split_lines(yanked_chars) local entities = map.find_closest_match(state.current_bufnr, patterns) local names = {} diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index 85972b4..85602a4 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -151,7 +151,7 @@ M.tick = function() tick_timer.on_tick() -- detect deleted on every turn - state.deleted = map.find_deleted(state.current_bufnr) + -- state.deleted = map.find_deleted(state.current_bufnr) edits.handle_insert_exit() diff --git a/lua/neohack/map.lua b/lua/neohack/map.lua index 83f5aae..44a72e7 100644 --- a/lua/neohack/map.lua +++ b/lua/neohack/map.lua @@ -213,6 +213,7 @@ M.generate_new_map_sections = function(bufnr, view_distance) return new_section_generated end +--TODO: deprecated ---comment ---@param bufnr integer ---@return Entity[][] @@ -231,7 +232,6 @@ M.find_deleted = function(bufnr) end return M.find_deleted_positions(old_buffer, new_buffer) end - -- Function to compare two states of the buffer and find deleted positions ---comment ---@param old_buffer Entity[][] @@ -314,6 +314,9 @@ end ---@param patterns string[] ---@return Entity[] | nil M.find_closest_match = function(bufnr, patterns) + if #patterns == 0 then + return nil + end local player_row, player_col = buffer.get_under_cursor() local cells = buffer.buffers[bufnr].cells local matches = M.find_all_matches(cells, patterns) diff --git a/lua/neohack/state.lua b/lua/neohack/state.lua index be92d83..c649548 100644 --- a/lua/neohack/state.lua +++ b/lua/neohack/state.lua @@ -52,8 +52,8 @@ local M = { ---@type integer current_floor = nil, - ---@type Entity[] - deleted = nil, + -- ---@type Entity[] + -- deleted = nil, ---@type string[] inserted = {}, diff --git a/lua/neohack/utils.lua b/lua/neohack/utils.lua index 646ac57..5292c85 100644 --- a/lua/neohack/utils.lua +++ b/lua/neohack/utils.lua @@ -103,4 +103,14 @@ M.random_key = function(table) return random_key end +M.split_lines = function(chars) + local patterns = {} + for line in chars:gmatch("([^\n]*)\n?") do + if #line > 0 then + table.insert(patterns, line) + end + end + return patterns +end + return M From 033fbd182205f193d16e3f55d19418cc76ba2676 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 18:48:07 +1100 Subject: [PATCH 25/31] feat: remove The prefix --- lua/neohack/event.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/neohack/event.lua b/lua/neohack/event.lua index 64fbce5..f9adeea 100644 --- a/lua/neohack/event.lua +++ b/lua/neohack/event.lua @@ -113,7 +113,7 @@ M.enemy_try_move = function(mover, move, in_fear, target_row, target_col) else M.make_move(mover, move) if in_fear then - message.notify("The " .. mover.name .. " is scared") + message.notify(mover.name .. " is scared") end return true end @@ -145,7 +145,7 @@ M.friend_try_move = function(mover, move, in_fear, target_row, target_col) else M.make_move(mover, move) if in_fear then - message.notify("The " .. mover.name .. " is scared") + message.notify(mover.name .. " is scared") end return true end @@ -279,7 +279,7 @@ M.say = function(words) local cast = (#casting > 0 and " cast " .. spell_names) or "" if string.find(word_str, entity.name) ~= nil then if entity.type == Def.DefType.enemy then - message.notify("The " .. entity.name .. " heard you" .. cast) + message.notify(entity.name .. " heard you" .. cast) end for _, spell in ipairs(casting) do spell.inscription.effect.cast(entity, 1) From 5c343206199c7f0811696babc152d6f0ac4f8391 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Sun, 29 Dec 2024 18:50:06 +1100 Subject: [PATCH 26/31] chore: remove debug --- lua/neohack/edits.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index 1f923bf..d282a52 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -129,7 +129,7 @@ M.handle_changed = function() end if not all_items then vim.cmd("normal! u") - message.notify("Can't pickup non items '" .. deleted_chars .. "'") + -- message.notify("Can't pickup non items '" .. deleted_chars .. "'") else for _, entity in ipairs(entities) do player.pickup(entity) From b162dbf2c4dd8ef4b3f2eef4419bf9f1c213b5eb Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Mon, 30 Dec 2024 10:48:58 +1100 Subject: [PATCH 27/31] test: add find tests --- lua/neohack/edits.lua | 5 +- lua/neohack/map.lua | 14 ++- tests/map_spec.lua | 242 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 242 insertions(+), 19 deletions(-) diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index d282a52..fbae699 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -92,7 +92,8 @@ M.handle_changed = function() local patterns = utils.split_lines(deleted_chars) -- this seems to have no issues, while state.deleted just doesn't work right - local deleted_entities = map.find_closest_match(state.current_bufnr, patterns) + + local deleted_entities = map.find_closest_to_player(patterns) if #deleted_chars > 0 and deleted_entities then -- message.notify("Deleted characters: '" .. deleted_chars .. "'") -- state.deleted just doesn't work @@ -177,7 +178,7 @@ M.handle_yanked = function() ---@type string[] local patterns = utils.split_lines(yanked_chars) - local entities = map.find_closest_match(state.current_bufnr, patterns) + local entities = map.find_closest_to_player(patterns) local names = {} if entities then diff --git a/lua/neohack/map.lua b/lua/neohack/map.lua index 44a72e7..5a4058d 100644 --- a/lua/neohack/map.lua +++ b/lua/neohack/map.lua @@ -7,6 +7,7 @@ local Def = require("neohack.def") local defs = require("neohack.defs") local buffer = require("neohack.buffer") local message = require("neohack.message") +local state = require("neohack.state") --- scan the buf, looking for points of interest ---@return Entity[] enemies @@ -312,12 +313,13 @@ end ---comment ---@param bufnr integer ---@param patterns string[] +---@param player_row integer +---@param player_col integer ---@return Entity[] | nil -M.find_closest_match = function(bufnr, patterns) +M.find_closest_match = function(bufnr, patterns, player_row, player_col) if #patterns == 0 then return nil end - local player_row, player_col = buffer.get_under_cursor() local cells = buffer.buffers[bufnr].cells local matches = M.find_all_matches(cells, patterns) if #matches == 0 then @@ -339,6 +341,14 @@ M.find_closest_match = function(bufnr, patterns) return closest_match end +---comment +---@param patterns string[] +---@return Entity[]|nil +M.find_closest_to_player = function(patterns) + local player_row, player_col = buffer.get_under_cursor() + return M.find_closest_match(state.current_bufnr, patterns, player_row, player_col) +end + --- Initialize a solid map of walls ---@param rows integer height ---@param cols integer width diff --git a/tests/map_spec.lua b/tests/map_spec.lua index 12ad355..8731941 100644 --- a/tests/map_spec.lua +++ b/tests/map_spec.lua @@ -2,15 +2,35 @@ local map = require("neohack.map") local Entity = require("neohack.entity") local message = require("neohack.message") +local buffer = require("neohack.buffer") +local state = require("neohack.state") local match = require("luassert.match") ---@diagnostic disable-next-line: undefined-field local eq = assert.is.equal local not_nil = match.is_not_nil -local function newE(name) +---comment +---@param name string +---@return Entity +local function newE(name, row, col) ---@diagnostic disable-next-line: missing-fields - return Entity.new({ char = name, name = "entity " .. name }, 1, 1) + return Entity.new({ char = name, name = "entity " .. name }, row, col) +end + +---comment +---@param chars string[][] +---@return Entity[][] +local function toEntities(chars) + local entities = {} + for i, row in ipairs(chars) do + local entity_row = {} + for j, char in ipairs(row) do + table.insert(entity_row, newE(char, i, j)) + end + table.insert(entities, entity_row) + end + return entities end describe("find_deleted_positions", function() @@ -18,24 +38,24 @@ describe("find_deleted_positions", function() it("finds deleted", function() local old = { - { newE("a"), newE("b"), newE("c") }, - { newE("d"), newE("e"), newE("f") }, - { newE("g"), newE("h"), newE("i") }, - { newE("j"), newE("k"), newE("l") }, - { newE("m"), newE("n"), newE("o") }, - { newE("p"), newE("q"), newE("p") }, + { "a", "b", "c" }, + { "d", "e", "f" }, + { "g", "h", "i" }, + { "j", "k", "l" }, + { "m", "n", "o" }, + { "p", "q", "p" }, } local new = { - { newE(" "), newE("b"), newE("c") }, - { newE("d"), newE(" "), newE("f") }, - { newE("g"), newE("h"), newE(" ") }, - { newE("l") }, - { newE("m") }, - { newE("p"), newE("q") }, + { " ", "b", "c" }, + { "d", " ", "f" }, + { "g", "h", " " }, + { "l" }, + { "m" }, + { "p", "q" }, } - local result, _ = map.find_deleted_positions(old, new) + local result, _ = map.find_deleted_positions(toEntities(old), toEntities(new)) local deleted = "" for _, entity in ipairs(result) do @@ -57,3 +77,195 @@ describe("find_deleted_positions", function() eq("entity p", result[9].name) end) end) + +---comment +---@param result Entity[][] +---@return string +local function as_chars(result) + local chars = "" + for _, entities in ipairs(result) do + for _, entity in ipairs(entities) do + chars = chars .. entity.char + end + chars = chars .. "\n" + end + return chars +end + +describe("find_all_matches", function() + message.notify_func = print + + it("finds single char", function() + local cells = { + { "a", "b", "c" }, + { "d", "e", "f" }, + { "g", "h", "i" }, + { "j", "k", "l" }, + { "m", "n", "o" }, + { "p", "q", "p" }, + } + eq("a\n", as_chars(map.find_all_matches(toEntities(cells), { "a" }))) + + eq("b\n", as_chars(map.find_all_matches(toEntities(cells), { "b" }))) + + eq("c\n", as_chars(map.find_all_matches(toEntities(cells), { "c" }))) + + eq("p\np\n", as_chars(map.find_all_matches(toEntities(cells), { "p" }))) + end) + + it("finds multi char", function() + local cells = { + { "a", "a", "c" }, + { "d", "a", "a" }, + { "a", "a", "a" }, + { "j", "k", "l" }, + { "m", "a", "a" }, + { "a", "q", "a" }, + } + eq("aa\naa\naa\naa\naa\n", as_chars(map.find_all_matches(toEntities(cells), { "aa" }))) + end) + + it("finds multi line", function() + local cells = { + { "a", "a", "c" }, + { "d", "a", "a" }, + { "a", "a", "a" }, + { "j", "k", "l" }, + { "m", "a", "a" }, + { "a", "q", "a" }, + } + eq("aa\naa\naa\naa\n", as_chars(map.find_all_matches(toEntities(cells), { "a", "a" }))) + + local found_entities = map.find_all_matches(toEntities(cells), { "aa", "a" }) + eq("aaa\n", as_chars(found_entities)) + eq(1, #found_entities) + local found = found_entities[1] + not_nil(found) + if found then + eq(3, #found) + eq(2, found[1].row) + eq(2, found[1].col) + + eq(2, found[2].row) + eq(3, found[2].col) + + eq(3, found[3].row) + eq(2, found[3].col) -- TODO this should be 1 + end + end) +end) + +local bufnr = 1 +---comment +---@param chars string[][] +local function set_buffer(chars) + state.current_bufnr = bufnr + ---@diagnostic disable-next-line: missing-fields + buffer.buffers[bufnr] = { + cells = toEntities(chars), + } +end + +describe("find_closest_match", function() + message.notify_func = print + + it("finds single char", function() + local cells = { + { "a", "b", "c" }, + { "d", "e", "f" }, + { "g", "h", "i" }, + { "j", "k", "l" }, + { "m", "n", "o" }, + { "p", "q", "p" }, + } + set_buffer(cells) + local row = 1 + local col = 1 + + local found = map.find_closest_match(bufnr, { "a" }, row, col) + not_nil(found) + if found then + eq(1, #found) + eq(1, found[1].row) + eq(1, found[1].col) + end + + local found_last = map.find_closest_match(bufnr, { "p" }, row, col) + not_nil(found_last) + if found_last then + eq(1, #found_last) + eq(6, found_last[1].row) + eq(1, found_last[1].col) + end + end) + + it("finds multi char", function() + local cells = { + { "a", "a", "c" }, + { "d", "a", "a" }, + { "a", "a", "a" }, + { "j", "k", "l" }, + { "m", "a", "a" }, + { "a", "q", "a" }, + } + + set_buffer(cells) + + local found = map.find_closest_match(bufnr, { "aa" }, 1, 1) + not_nil(found) + if found then + eq(2, #found) + eq(1, found[1].row) + eq(1, found[1].col) + eq(1, found[2].row) + eq(2, found[2].col) + end + + local found_last = map.find_closest_match(bufnr, { "aa" }, 6, 3) + not_nil(found_last) + if found_last then + eq(2, #found_last) + eq(5, found_last[1].row) + eq(2, found_last[1].col) + eq(5, found_last[2].row) + eq(3, found_last[2].col) + end + end) + + it("finds multi line", function() + local cells = { + { "a", "a", "c" }, + { "d", "a", "a" }, + { "a", "a", "a" }, + { "j", "k", "l" }, + { "m", "a", "a" }, + { "a", "q", "a" }, + } + + set_buffer(cells) + + local found = map.find_closest_match(bufnr, { "aa", "a" }, 1, 1) + not_nil(found) + if found then + eq(3, #found) + eq(2, found[1].row) + eq(2, found[1].col) + eq(2, found[2].row) + eq(3, found[2].col) + eq(3, found[3].row) + eq(2, found[3].col) -- TODO this should be 1 + end + + local found_last = map.find_closest_match(bufnr, { "aa", "a" }, 6, 3) + not_nil(found_last) + if found_last then + eq(3, #found_last) + eq(2, found_last[1].row) + eq(2, found_last[1].col) + eq(2, found_last[2].row) + eq(3, found_last[2].col) + eq(3, found_last[3].row) + eq(2, found_last[3].col) -- TODO this should be 1 + end + end) +end) From 9deb5bdb538e1bc0125a16ff06a83c684ddd5138 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Tue, 31 Dec 2024 11:33:24 +1100 Subject: [PATCH 28/31] fix: find_closest_match logic bugs and refactor --- lua/neohack/map.lua | 82 ++++++++++---------- tests/map_spec.lua | 183 ++++++++++++++++++++++++++++---------------- 2 files changed, 161 insertions(+), 104 deletions(-) diff --git a/lua/neohack/map.lua b/lua/neohack/map.lua index 5a4058d..f1c51e0 100644 --- a/lua/neohack/map.lua +++ b/lua/neohack/map.lua @@ -262,46 +262,48 @@ M.find_deleted_positions = function(old_buffer, new_buffer) end ---comment ----@param grid any ----@param patterns string[] +---@param grid Entity[][] +---@param row_start integer +---@param col_start integer +---@param pattern_lines string[] +---@return Entity[] | nil the cells if found nil if not found from the current starting pos +M.find_patterns = function(grid, row_start, col_start, pattern_lines) + local matched_cells = {} + for row_inner = 1, #pattern_lines do + for col_inner = 1, #pattern_lines[row_inner] do + local sub_pattern = pattern_lines[row_inner]:sub(col_inner, col_inner) + local row = row_start + row_inner - 1 + local col = col_start + col_inner - 1 + local cell = grid[row][col] + -- message.notify("looking at " .. cell.char .. " " .. row .. " " .. col) + -- not visible matches anything + if cell.char ~= sub_pattern and sub_pattern ~= defs.not_visible then + -- message.notify("no match " .. cell.char .. " " .. sub_pattern) + return nil + end + + table.insert(matched_cells, cell) + end + -- after each row, start back at first col + col_start = 1 + end + return matched_cells +end + +---comment +---@param grid Entity[][] +---@param pattern_lines string[] ---@return Entity[][] -M.find_all_matches = function(grid, patterns) +M.find_all_matches = function(grid, pattern_lines) ---@type Entity[][] local matches = {} - -- message.notify("looking for " .. vim.inspect(patterns)) - - local pattern_height = #patterns - local pattern_width = #patterns[1] - - for row = 1, #grid - pattern_height + 1 do - for col = 1, #grid[row] - pattern_width + 1 do - local is_match = true - for i = 0, pattern_height - 1 do - for j = 1, #patterns[i + 1] do - local sub_pattern = patterns[i + 1]:sub(j, j) - local cell = grid[row + i][col + j - 1] - -- not visible matches anything - if cell.char ~= sub_pattern and sub_pattern ~= defs.not_visible then - is_match = false - break - end - end - if not is_match then - break - end - end - if is_match then - -- message.notify("got match " .. "row " .. row .. " col " .. col) - local matched_cells = {} - for i = 0, pattern_height - 1 do - for j = 1, #patterns[i + 1] do - ---@type Entity - local cell = grid[row + i][col + j - 1] - table.insert(matched_cells, cell) - end - end - -- message.notify("got match " .. vim.inspect(matched_cells)) + local pattern_width = #pattern_lines[1] + for row_start = 1, #grid - #pattern_lines + 1 do + for col_start = 1, #grid[row_start] - pattern_width + 1 do + local matched_cells = M.find_patterns(grid, row_start, col_start, pattern_lines) + if matched_cells then + -- message.notify("got match " .. row_start .. " " .. col_start) table.insert(matches, matched_cells) end end @@ -312,16 +314,16 @@ end ---comment ---@param bufnr integer ----@param patterns string[] +---@param pattern_lines string[] a multiline pattern to match ---@param player_row integer ---@param player_col integer ---@return Entity[] | nil -M.find_closest_match = function(bufnr, patterns, player_row, player_col) - if #patterns == 0 then +M.find_closest_match = function(bufnr, pattern_lines, player_row, player_col) + if #pattern_lines == 0 then return nil end local cells = buffer.buffers[bufnr].cells - local matches = M.find_all_matches(cells, patterns) + local matches = M.find_all_matches(cells, pattern_lines) if #matches == 0 then return nil end diff --git a/tests/map_spec.lua b/tests/map_spec.lua index 8731941..01fe722 100644 --- a/tests/map_spec.lua +++ b/tests/map_spec.lua @@ -33,6 +33,17 @@ local function toEntities(chars) return entities end +local function assertFound(expected, found) + not_nil(found) + if found then + eq(#expected, #found) + for i, e in ipairs(expected) do + eq(e[1], found[i].row) + eq(e[2], found[i].col) + end + end +end + describe("find_deleted_positions", function() message.notify_func = print @@ -111,6 +122,7 @@ describe("find_all_matches", function() eq("c\n", as_chars(map.find_all_matches(toEntities(cells), { "c" }))) eq("p\np\n", as_chars(map.find_all_matches(toEntities(cells), { "p" }))) + eq("", as_chars(map.find_all_matches(toEntities(cells), { "z" }))) end) it("finds multi char", function() @@ -122,7 +134,11 @@ describe("find_all_matches", function() { "m", "a", "a" }, { "a", "q", "a" }, } + eq("a\na\na\na\na\na\na\na\na\na\na\n", as_chars(map.find_all_matches(toEntities(cells), { "a" }))) eq("aa\naa\naa\naa\naa\n", as_chars(map.find_all_matches(toEntities(cells), { "aa" }))) + eq("aaa\n", as_chars(map.find_all_matches(toEntities(cells), { "aaa" }))) + eq("", as_chars(map.find_all_matches(toEntities(cells), { "aaaa" }))) + eq("", as_chars(map.find_all_matches(toEntities(cells), { "cd" }))) end) it("finds multi line", function() @@ -136,22 +152,94 @@ describe("find_all_matches", function() } eq("aa\naa\naa\naa\n", as_chars(map.find_all_matches(toEntities(cells), { "a", "a" }))) - local found_entities = map.find_all_matches(toEntities(cells), { "aa", "a" }) - eq("aaa\n", as_chars(found_entities)) - eq(1, #found_entities) - local found = found_entities[1] - not_nil(found) - if found then - eq(3, #found) - eq(2, found[1].row) - eq(2, found[1].col) - - eq(2, found[2].row) - eq(3, found[2].col) - - eq(3, found[3].row) - eq(2, found[3].col) -- TODO this should be 1 - end + local found_1 = map.find_all_matches(toEntities(cells), { "aa", "a" }) + eq("aaa\naaa\n", as_chars(found_1)) + eq(2, #found_1) + assertFound({ + { 2, 2 }, + { 2, 3 }, + { 3, 1 }, + }, found_1[1]) + assertFound({ + { 5, 2 }, + { 5, 3 }, + { 6, 1 }, + }, found_1[2]) + + local found_2 = map.find_all_matches(toEntities(cells), { "l", "m" }) + eq("lm\n", as_chars(found_2)) + eq(1, #found_2) + assertFound({ { 4, 3 }, { 5, 1 } }, found_2[1]) + + -- no line split, so doesn't match + local found_3 = map.find_all_matches(toEntities(cells), { "lm" }) + eq("", as_chars(found_3)) + eq(0, #found_3) + assertFound({}, found_3[1]) + end) + + it("finds over line single", function() + local cells = { + { "a" }, + { "b" }, + } + local found_1 = map.find_all_matches(toEntities(cells), { "a", "b" }) + eq("ab\n", as_chars(found_1)) + eq(1, #found_1) + assertFound({ + { 1, 1 }, + { 2, 1 }, + }, found_1[1]) + end) + + it("finds over line dual", function() + local cells = { + { "a", "b" }, + { "c", "d" }, + } + local found_1 = map.find_all_matches(toEntities(cells), { "ab", "cd" }) + eq("abcd\n", as_chars(found_1)) + eq(1, #found_1) + assertFound({ + { 1, 1 }, + { 1, 2 }, + { 2, 1 }, + { 2, 2 }, + }, found_1[1]) + end) + + it("finds over line full", function() + local cells = { + { "a", "b", "c" }, + { "d", "e", "f" }, + } + local found_1 = map.find_all_matches(toEntities(cells), { "abc", "def" }) + eq("abcdef\n", as_chars(found_1)) + eq(1, #found_1) + assertFound({ + { 1, 1 }, + { 1, 2 }, + { 1, 3 }, + { 2, 1 }, + { 2, 2 }, + { 2, 3 }, + }, found_1[1]) + end) + + it("finds over line partial", function() + local cells = { + { "a", "b", "c" }, + { "d", "e", "f" }, + } + local found_1 = map.find_all_matches(toEntities(cells), { "bc", "de" }) + eq("bcde\n", as_chars(found_1)) + eq(1, #found_1) + assertFound({ + { 1, 2 }, + { 1, 3 }, + { 2, 1 }, + { 2, 2 }, + }, found_1[1]) end) end) @@ -183,20 +271,11 @@ describe("find_closest_match", function() local col = 1 local found = map.find_closest_match(bufnr, { "a" }, row, col) - not_nil(found) - if found then - eq(1, #found) - eq(1, found[1].row) - eq(1, found[1].col) - end + + assertFound({ { 1, 1 } }, found) local found_last = map.find_closest_match(bufnr, { "p" }, row, col) - not_nil(found_last) - if found_last then - eq(1, #found_last) - eq(6, found_last[1].row) - eq(1, found_last[1].col) - end + assertFound({ { 6, 1 } }, found_last) end) it("finds multi char", function() @@ -212,24 +291,10 @@ describe("find_closest_match", function() set_buffer(cells) local found = map.find_closest_match(bufnr, { "aa" }, 1, 1) - not_nil(found) - if found then - eq(2, #found) - eq(1, found[1].row) - eq(1, found[1].col) - eq(1, found[2].row) - eq(2, found[2].col) - end + assertFound({ { 1, 1 }, { 1, 2 } }, found) local found_last = map.find_closest_match(bufnr, { "aa" }, 6, 3) - not_nil(found_last) - if found_last then - eq(2, #found_last) - eq(5, found_last[1].row) - eq(2, found_last[1].col) - eq(5, found_last[2].row) - eq(3, found_last[2].col) - end + assertFound({ { 5, 2 }, { 5, 3 } }, found_last) end) it("finds multi line", function() @@ -245,27 +310,17 @@ describe("find_closest_match", function() set_buffer(cells) local found = map.find_closest_match(bufnr, { "aa", "a" }, 1, 1) - not_nil(found) - if found then - eq(3, #found) - eq(2, found[1].row) - eq(2, found[1].col) - eq(2, found[2].row) - eq(3, found[2].col) - eq(3, found[3].row) - eq(2, found[3].col) -- TODO this should be 1 - end + assertFound({ + { 2, 2 }, + { 2, 3 }, + { 3, 1 }, + }, found) local found_last = map.find_closest_match(bufnr, { "aa", "a" }, 6, 3) - not_nil(found_last) - if found_last then - eq(3, #found_last) - eq(2, found_last[1].row) - eq(2, found_last[1].col) - eq(2, found_last[2].row) - eq(3, found_last[2].col) - eq(3, found_last[3].row) - eq(2, found_last[3].col) -- TODO this should be 1 - end + assertFound({ + { 5, 2 }, + { 5, 3 }, + { 6, 1 }, + }, found_last) end) end) From b2454f3e34376b22a173df6a8964d34bd4b00ec8 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Tue, 31 Dec 2024 12:19:12 +1100 Subject: [PATCH 29/31] feat: handle changes during CursorMoved, and check directly if yanked_chars are present in the real view buffer to know if they're deleted. --- lua/neohack/buffer.lua | 23 ++++++++++++++++++++++- lua/neohack/edits.lua | 6 ++++++ lua/neohack/game.lua | 17 +++++++++++------ lua/neohack/map.lua | 17 +++++++++++++++++ 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/lua/neohack/buffer.lua b/lua/neohack/buffer.lua index 1082310..f313eee 100644 --- a/lua/neohack/buffer.lua +++ b/lua/neohack/buffer.lua @@ -159,6 +159,7 @@ M.add_insert_handlers = function(bufnr) }) end +---TODO: deprecated cursor moved also handles changed --- Add change handlers for a specific buffer ---@param bufnr integer M.add_change_handlers = function(bufnr) @@ -167,7 +168,8 @@ M.add_change_handlers = function(bufnr) buffer = bufnr, callback = function() -- M.remove_handlers(bufnr) - M.buffers[bufnr].handle_changed() + ---TODO: deprecated cursor moved also handles changed + -- M.buffers[bufnr].handle_changed() -- M.add_handlers(bufnr) end, }) @@ -194,6 +196,7 @@ M.tick = function(callback) M.write_buf(nil) end +--TODO: is this actually used now that maps are generated? it creates entities from the existing chars --- Read buffer content and update the cells for a specific buffer ---@param bufnr integer ---@return Entity[][] @@ -211,6 +214,23 @@ M.read_a_buf = function(bufnr) return new_cells end +--- Read buffer content as a grid of chars +---@param bufnr integer +---@return string[][] +M.read_buf_chars = function(bufnr) + local new_cells = {} -- prepare a new frame + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + for row, value in ipairs(lines) do + local result = {} + for col = 1, #value do + local char = value:sub(col, col) + result[col] = char + end + new_cells[row] = result + end + return new_cells +end + --- Read buffer content and update the cells for a specific buffer ---@param bufnr integer M.read_buf = function(bufnr) @@ -396,6 +416,7 @@ M.setup_game_buffer = function(bufnr) vim.o.listchars = "" -- TODO: disable code complete + --TODO: save/restore statusline return bufnr end diff --git a/lua/neohack/edits.lua b/lua/neohack/edits.lua index fbae699..e9302c0 100644 --- a/lua/neohack/edits.lua +++ b/lua/neohack/edits.lua @@ -98,6 +98,12 @@ M.handle_changed = function() -- message.notify("Deleted characters: '" .. deleted_chars .. "'") -- state.deleted just doesn't work -- local deleted_entities = state.deleted + local present = map.present_in_buffer(deleted_entities) + if present then + -- message.notify("entities were not deleted '" .. deleted_chars .. "'") + return + end + -- message.notify("entities were deleted '" .. deleted_chars .. "'") local deleted_e = "" for _, entity in ipairs(deleted_entities) do -- message.notify("Deleted entity: '" .. vim.inspect(entity) .. "'") diff --git a/lua/neohack/game.lua b/lua/neohack/game.lua index 85602a4..dd3d379 100644 --- a/lua/neohack/game.lua +++ b/lua/neohack/game.lua @@ -91,7 +91,6 @@ end ---comment M.handle_moved = function() - -- message.notify("tick") if player.is_dead() then M.end_game() end @@ -111,15 +110,16 @@ M.handle_insert_enter = function() edits.handle_insert_enter() end +---TODO: deprecated cursor moved also handles changed ---comment M.handle_changed = function() if player.is_dead() then M.end_game() end -- message.notify("changed") - if not event.in_sneak_move() then - edits.handle_changed() - end + -- if not event.in_sneak_move() then + -- edits.handle_changed() + -- end end ---comment @@ -148,11 +148,16 @@ M.tick = function() state.turn_counter = state.turn_counter + 1 -- message.notify("tick") - tick_timer.on_tick() - -- detect deleted on every turn -- state.deleted = map.find_deleted(state.current_bufnr) + -- cursor moved also triggered on change + if not event.in_sneak_move() then + edits.handle_changed() + end + + tick_timer.on_tick() + edits.handle_insert_exit() event.player_move() diff --git a/lua/neohack/map.lua b/lua/neohack/map.lua index f1c51e0..d017f98 100644 --- a/lua/neohack/map.lua +++ b/lua/neohack/map.lua @@ -351,6 +351,23 @@ M.find_closest_to_player = function(patterns) return M.find_closest_match(state.current_bufnr, patterns, player_row, player_col) end +---comment +---@param entities Entity[] +---@return boolean if entities are all the same in the real view buffer +M.present_in_buffer = function(entities) + local cells = buffer.read_buf_chars(state.current_bufnr) + for _, entity in ipairs(entities) do + local char = cells[entity.row][entity.col] + if char ~= entity.char then + -- message.notify("difference '" .. entity.char .. "'!='" .. char .. "' at " .. entity.row .. " " .. entity.col) + return false + else + -- message.notify("no difference '" .. entity.char .. "'=='" .. char .. "' at " .. entity.row .. " " .. entity.col) + end + end + return true +end + --- Initialize a solid map of walls ---@param rows integer height ---@param cols integer width From 3e0917951b291d5a8e93e1da8a90976562c9948f Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Tue, 31 Dec 2024 12:24:09 +1100 Subject: [PATCH 30/31] feat: set statusline on game start/end --- lua/config.lua | 4 ---- lua/neohack/buffer.lua | 10 +++++++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lua/config.lua b/lua/config.lua index b6be9fb..9a6e2b5 100644 --- a/lua/config.lua +++ b/lua/config.lua @@ -87,7 +87,3 @@ require("lazy").setup({ -- automatically check for plugin updates checker = { enabled = true }, }) - --- set the statusline to show in game info -vim.o.statusline = "%!v:lua.require'neohack'.status_line()" -vim.o.laststatus = 3 diff --git a/lua/neohack/buffer.lua b/lua/neohack/buffer.lua index f313eee..54112a8 100644 --- a/lua/neohack/buffer.lua +++ b/lua/neohack/buffer.lua @@ -403,6 +403,8 @@ M.setup_game_buffer = function(bufnr) listchars = vim.o.listchars, cursorline_hl = vim.api.nvim_get_hl(0, { name = "CursorLine", link = false }), cursorcolumn_hl = vim.api.nvim_get_hl(0, { name = "CursorColumn", link = false }), + statusline = vim.o.statusline, + laststatus = vim.o.laststatus, } vim.api.nvim_buf_clear_namespace(bufnr, -1, 0, -1) @@ -414,9 +416,13 @@ M.setup_game_buffer = function(bufnr) vim.cmd.nohlsearch() vim.cmd("set nowrap") vim.o.listchars = "" + + -- set the statusline to show in game info + vim.o.statusline = "%!v:lua.require'neohack'.status_line()" + vim.o.laststatus = 3 + -- TODO: disable code complete - --TODO: save/restore statusline return bufnr end @@ -445,6 +451,8 @@ M.restore_original_settings = function(bufnr) end ---@diagnostic disable-next-line: undefined-field vim.o.listchars = buf.buf_settings.listchars + vim.o.statusline = buf.buf_settings.status_line + vim.o.laststatus = buf.buf_settings.laststatus end end From 62705dcf28a4937c2bbde511289cd2956dc67f86 Mon Sep 17 00:00:00 2001 From: Casper Szymiczek-Graley Date: Tue, 31 Dec 2024 12:28:44 +1100 Subject: [PATCH 31/31] feat: minimal test targets --- .github/workflows/ci.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa05fe4..10d2efb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,9 @@ name: Tests -on: [push, pull_request] +on: [ + # push, + pull_request +] jobs: unit_tests: @@ -12,9 +15,12 @@ jobs: os: [ ubuntu-22.04, # macos-14, - windows-2022 + # windows-2022 + ] + rev: [ + # nightly, + v0.10.0 ] - rev: [nightly, v0.10.0] steps: - uses: actions/checkout@v4