Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
befd8e6
feat: rename items
caspersg Jan 1, 2025
3fd9bc8
docs: new ecs todos
caspersg Jan 1, 2025
d5243f9
refactor: make inventory an object
caspersg Jan 1, 2025
37e458c
refactor: make player an object
caspersg Jan 1, 2025
10b526d
fix: notify takes varargs properly
caspersg Jan 1, 2025
83b2c91
refactor: extract health component and move to components dirs
caspersg Jan 1, 2025
8ea9fb9
wip: mixin components helper
caspersg Jan 1, 2025
23104a0
refactor: use inventory component from health
caspersg Jan 1, 2025
e3364b2
refactor: wear functions now on inventory component
caspersg Jan 1, 2025
fd6ca14
refactor: extract dodge into combat component
caspersg Jan 2, 2025
574d607
refactor: moved dodge_skill to combat component
caspersg Jan 2, 2025
376b27f
refactor: extract deflect
caspersg Jan 2, 2025
0ca7b6e
feat: eating affects deflect
caspersg Jan 2, 2025
5979108
refactor: extracted hit with weapon logic to combat
caspersg Jan 2, 2025
bf40701
refactor: extract hit_by
caspersg Jan 2, 2025
99cde4c
feat: enemy can attack enemy
caspersg Jan 2, 2025
e0c7204
refactor: give all Entity instances a Health and Inventory component
caspersg Jan 2, 2025
48bfad3
docs: update todos
caspersg Jan 2, 2025
17e3c62
feat: give enemies a random item in their inventory
caspersg Jan 2, 2025
bab331a
refactor: move get_inventory to Inventory
caspersg Jan 2, 2025
a468aaf
docs: update todo
caspersg Jan 2, 2025
44f986d
refactor: make player an Entity, move Combat into Entity
caspersg Jan 2, 2025
1efb5cf
feat: all attacks use the same logic for every combination of Entity …
caspersg Jan 2, 2025
afd5102
refactor: parent in combat to access main entity, health, and invento…
caspersg Jan 2, 2025
fc4c5ec
refactor: and test combat
caspersg Jan 3, 2025
2e214e3
refactor: drop player corpse as an entity like enemy corpses
caspersg Jan 3, 2025
4d29dd7
refactor: remove old player corpse logic
caspersg Jan 3, 2025
baff522
docs: new ideas
caspersg Jan 3, 2025
103daea
feat: add pilfer action to get items out of an item's inventory ie lo…
caspersg Jan 3, 2025
842e8b1
feat: pilfer corpses as they are eaten
caspersg Jan 3, 2025
cf36482
refactor: extract Sneak component
caspersg Jan 3, 2025
35b11dd
feat: remove kick corpse to generate items
caspersg Jan 3, 2025
ac9f35f
refactor: extract Fuse component
caspersg Jan 3, 2025
f7dccc9
refactor: extract Eat component
caspersg Jan 3, 2025
416ffdd
refactor: extract Vision component
caspersg Jan 3, 2025
4686ff0
refactor: Entity no longer inherit from Def, and move combat attribut…
caspersg Jan 3, 2025
bcd8030
refactor: extract Movement. Just the attributes so far
caspersg Jan 3, 2025
eecc894
refactor: extracted movement logic into Movement from events
caspersg Jan 3, 2025
6bbdf88
refactor: extracted Speak, and update player entity row,col based on …
caspersg Jan 3, 2025
f419181
refactor: inscription on Speak component
caspersg Jan 4, 2025
cdb2420
refactor: extract Decision and source attributes and inspect from com…
caspersg Jan 4, 2025
4b008f8
refactor: extract remaining actions to components. generate effect no…
caspersg Jan 4, 2025
149077e
refactor: extracted all attributes to Attributes component. now spell…
caspersg Jan 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ Actions
- [x] unknown letters are terrain
- [x] health items
- [x] collect your corpse
- [ ] drop full inventory chars
- [x] copy to new buffer on game start
- [x] highlight hurt
- [x] miss hits and dodges
Expand Down Expand Up @@ -93,6 +92,33 @@ Actions
- [ ] add more specific effects
- [ ] build terrain, same but with terrain
- [ ] pick up terrain, or only for in place
- [x] rename item
- [ ] movement
- [ ] restrict teleport with an item
- [ ] physics
- [ ] entity weight
- [ ] entity strength
- [ ] force
- [ ] knockdown
- [ ] kick acceleration
- [ ] bump acceleration
- [ ] pickup weight
- [ ] teleport acceleration?
- [ ] water and density?
- [ ] slippery floor?
- [ ] entity component system
- [ ] refactor
- [ ] extract all features into components
- [ ] all player actions can be performed by entities
- [ ] ai for entities to choose action
- [ ] control player movement with a spell
- [x] enemies have inventory
- [x] player and enemies drop inventory the same way
- [ ] enemies have view_distance
- [ ] target for enemies and friends
- [ ] enemies pickup items
- [ ] enemies use weapons
- [ ] npcs
- [ ] friends
- [x] enchant enemies into friends
- [x] friend follows player
Expand All @@ -108,7 +134,9 @@ Actions
- [x] change/replace - both pickup and drop
- [x] visual - move without attacking ie sneaking
- [x] an entity stat for sneakability
- [ ] steal items
- [x] yank - search, works in combination with sneaking
- [ ] paste - ???
- [ ] jumplist - ???
- [ ] use registers for inventory
- [x] insert to run actions
Expand All @@ -125,6 +153,7 @@ Actions
- [ ] performance
- [x] write buffer once per tick
- [x] store map as 2D array
- [ ] vim tutor/tutorial map
- [ ] easy run
- [x] minimal neovim config with single command to run
- [ ] slash screen
Expand Down
84 changes: 63 additions & 21 deletions lua/neohack/actions.lua
Original file line number Diff line number Diff line change
@@ -1,60 +1,68 @@
local chat = require("neohack.chat")
local inventory = require("neohack.inventory")
local state = require("neohack.state")
local message = require("neohack.message")
local utils = require("neohack.utils")

local M = {
leader_key = nil,
tick = nil,
}

local player = require("neohack.player")
local message = require("neohack.message")
local event = require("neohack.event")
local state = require("neohack.state")
local utils = require("neohack.utils")

M.actions = {
---comment
inventory = function()
message.notify("You have " .. player.get_inventory())
message.notify("You have " .. state.player.inventory:get_inventory())
end,

---comment
kick = function(request)
event.kick(request.object)
state.player.movement:kick(request.object)
M.tick()
end,

---comment
wear = function(request)
player.wear(request.object, request.target)
state.player.inventory:wear(request.object, request.target)
end,

---comment
fuse = function(request)
--TODO: allow for multiple objects? or just keep to object and target
player.fuse({ request.object, request.target })
state.player.fuse:fuse({ request.object, request.target })
M.tick()
end,

---comment
rename = function(request)
state.player.inventory:rename(request.object, request.target)
M.tick()
end,

---comment
look = function(request)
player.look({ request.object })
state.player.inventory:look({ request.object })
end,

---comment
pilfer = function(request)
state.player.inventory:pilfer(request.object)
end,

---comment
eat = function(request)
player.eat({ request.object })
state.player:eat_keys({ request.object })
M.tick()
end,

---comment
drop = function(request)
player.drop({ request.object })
state.player.inventory:drop({ request.object })
M.tick()
end,

---comment
say = function(request)
event.say({ request.object, request.target })
state.player.speak:say({ request.object, request.target })
M.tick()
end,

Expand Down Expand Up @@ -83,7 +91,7 @@ M.actions = {
.. 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, <space> to wait, ? for help"
.. "i to show inventory, w to wear, k to kick, f to fuse, r to rename, l to look, p to pilfer, e to eat, s to say, d to drop, <space> to wait, ? for help"
)
end,
}
Expand All @@ -105,11 +113,18 @@ M.synonyms = {
wield = "wear",

f = "fuse",
r = "rename",

l = "look",
read = "look",
examine = "look",

p = "pilfer",
steal = "pilfer",
pickpocket = "pilfer",
loot = "pilfer",
take = "pilfer",

e = "eat",

d = "drop",
Expand Down Expand Up @@ -141,7 +156,7 @@ end

---comment
M.prompt_wear = function()
message.notify("You have:\n0:nothing\n" .. inventory.get_inventory_item_with_index())
message.notify("You have:\n0:nothing\n" .. state.player.inventory:get_inventory_item_with_index())
vim.defer_fn(function()
local object = M.prompt_one_word("Wear what?")
if object then
Expand All @@ -156,7 +171,7 @@ end

---comment
M.prompt_fuse = function()
message.notify("You have:\n" .. inventory.get_inventory_item_with_index())
message.notify("You have:\n" .. state.player.inventory:get_inventory_item_with_index())
vim.defer_fn(function()
local index = M.prompt("Fuse what?")
if index then
Expand All @@ -169,9 +184,23 @@ M.prompt_fuse = function()
end, 50)
end

---comment
M.prompt_rename = function()
message.notify("You have:\n" .. state.player.inventory:get_inventory_item_with_index())
vim.defer_fn(function()
local index = M.prompt_one_word("Rename what?")
if index then
local name = M.prompt_one_word("New name?")
if name then
M.actions.rename({ object = index, target = name })
end
end
end, 50)
end

---comment
M.prompt_look = function()
message.notify("You have:\n0:self\n" .. inventory.get_inventory_item_with_index())
message.notify("You have:\n0:self\n" .. state.player.inventory:get_inventory_item_with_index())
vim.defer_fn(function()
local index = M.prompt_one_word("Look at what?")
if index then
Expand All @@ -181,9 +210,20 @@ M.prompt_look = function()
end, 50)
end

---comment
M.prompt_pilfer = function()
message.notify("You have:\n0:self\n" .. state.player.inventory:get_inventory_item_with_index())
vim.defer_fn(function()
local index = M.prompt_one_word("Pilfer from what?")
if index then
M.actions.pilfer({ object = index })
end
end, 50)
end

---comment
M.prompt_eat = function()
message.notify("You have:\n" .. inventory.get_inventory_item_with_index())
message.notify("You have:\n" .. state.player.inventory:get_inventory_item_with_index())
vim.defer_fn(function()
local index = M.prompt_one_word("Eat what?")
if index then
Expand All @@ -195,7 +235,7 @@ end

---comment
M.prompt_drop = function()
message.notify("You have:\n" .. inventory.get_inventory_item_with_index())
message.notify("You have:\n" .. state.player.inventory:get_inventory_item_with_index())
vim.defer_fn(function()
local index = M.prompt_one_word("Drop what?")
if index then
Expand Down Expand Up @@ -276,7 +316,9 @@ M.setup = function(bufnr, tick)
map("w", M.prompt_wear, "wear")
map("k", M.prompt_kick, "kick")
map("f", M.prompt_fuse, "fuse")
map("r", M.prompt_rename, "rename")
map("l", M.prompt_look, "look")
map("p", M.prompt_pilfer, "pilfer")
map("e", M.prompt_eat, "eat")
map("d", M.prompt_drop, "drop")
map("s", M.prompt_say, "say")
Expand Down
19 changes: 19 additions & 0 deletions lua/neohack/attribute_getters.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
local M = {}

M.vision = function(item)
return item and item.attributes.vision or 0
end

M.randomness = function(item)
return item and item.attributes.randomness or 0
end

M.hit_rate = function(item)
return item and item.attributes.hit_rate or 0
end

M.durability = function(item)
return item and item.attributes.durability or 0
end

return M
41 changes: 23 additions & 18 deletions lua/neohack/buffer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ M.create_new_buffer = function(lines, handlers)
M.buffers[bufnr] = init_buffer(bufnr, handlers)
table.insert(M.levels, bufnr)
M.buffers[bufnr].level = #M.levels
M.read_buf(bufnr)
-- M.read_buf(bufnr)
return bufnr, #M.levels
end

Expand Down Expand Up @@ -98,12 +98,12 @@ M.add_handlers = function(bufnr)
end
end

--- Read buffer content and update the cells for a specific buffer
---@param bufnr integer
M.read_buf = function(bufnr)
-- replace the old frame
M.buffers[bufnr].cells = view_buffer.read_a_buf(bufnr)
end
-- --- Read buffer content and update the cells for a specific buffer
-- ---@param bufnr integer
-- M.read_buf = function(bufnr)
-- -- replace the old frame
-- M.buffers[bufnr].cells = view_buffer.read_a_buf(bufnr)
-- end

--- Write the buffer content based on the cells for a specific buffer
---comment
Expand Down Expand Up @@ -140,10 +140,8 @@ M.get_entity_at_pos = function(row, col)
end
local entity = line[col]
if entity then
if entity.row ~= row or entity.col ~= col then
message.notify(
"entity mismatch " .. entity.char .. " " .. entity.row .. " " .. entity.col .. " " .. row .. " " .. col
)
if entity.movement.row ~= row or entity.movement.col ~= col then
message.notify("entity mismatch", entity.movement.char, entity.movement.row, entity.movement.col, row, col)
end
else
-- message.notify("nothing at " .. row .. " " .. col)
Expand All @@ -159,7 +157,7 @@ M.get_under_cursor = function()
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
col = col + 1
local entity = M.get_entity_at_pos(row, col)
-- message.notify("under cursor " .. row .. " " .. col .. " " .. entity.char)
-- message.notify("under cursor " .. row .. " " .. col .. " " .. entity.movement.char)
return row, col, entity
end

Expand All @@ -169,9 +167,16 @@ end
---@param entity Entity
M.set_entity_at_cell = function(row, col, entity)
local bufnr = state.current_bufnr
entity.row = row
entity.col = col
M.buffers[bufnr].cells[row][col] = entity
entity.movement.row = row
entity.movement.col = col
-- TODO: deal with nil
local buf = M.buffers[bufnr]
if not buf then
error("no buffer")
end
-- error("set entity at " .. row .. " " .. col)
-- message.notify(vim.inspect(buf.cells[row][col]))
buf.cells[row][col] = entity
end

--- Insert an entity at a specific position in a specific buffer
Expand All @@ -180,12 +185,12 @@ end
---@param entity Entity
M.insert_entity_at_cell = function(row, col, entity)
local bufnr = state.current_bufnr
entity.row = row
entity.col = col
entity.movement.row = row
entity.movement.col = col
table.insert(M.buffers[bufnr].cells[row], col, entity)
-- increment the remaining cols in the row
for i = col + 1, #M.buffers[bufnr].cells[row] do
M.buffers[bufnr].cells[row][i].col = i
M.buffers[bufnr].cells[row][i].movement.col = i
end
end

Expand Down
Loading