wanted to write a roguelike. I spent a while finding out what to do with the roguelike. Then it dawned on me I could use the Chthonic Codex setting, make the character a student in the University and give the players some pet goats.

For the time being goats only attack enemies and get killed horribly. Add magic and that's pretty much what the game will be about.

The game is gong to be mission-based, with your cranky professor giving a mission per quarter. Of course if the goats stay alive for a while, you get more goats. Goats do that. They also make convenient sacrifice victims and, of course, are great scapegoats. So, if you are about to die and you have a goat, the goat dies instead. Amongst the treasure you'll be able to find goats. Not sure if I'll manage selective breeding, or any sound effect (I'm going deaf and I'd rather spend time writing code instead of writing bad music, but if someone can help it would be fantastic).

Pico lacks native stack and queue support. I'm unhappy about it, so i cried a bit and my friend GreyKnight came up with a small implementation of a deque (queue/stack combo). From preliminary tests it works fine.

-- 3 tokens push=add -- 19 tokens function pop(stack) local v = stack[#stack] stack[#stack]=nil return v end -- 11 tokens function pop_discard(stack) stack[#stack]=nil end -- 3 tokens enqueue=add -- 16 tokens function dequeue(queue) local v = queue[1] del(queue, v) return v end ----- Usage ----- stack = {} push(stack, "goat") push(stack, "billy") assert("billy" == pop(stack)) assert("goat" == pop(stack)) queue = {} enqueue(queue, "nanny") enqueue(queue, "kid") assert("nanny" == dequeue(queue)) assert("kid" == dequeue(queue)) |

[sorry if you have seen this already. I have no idea which posts show up where in this bbs and I keep on putting it in the wrong places]

I'm kind of working on a couple of shameful hacks for Pico.

The first one is a network stack. Since Hey @ lexaloffe is not answering my emails, I'm just keeping myself busy this way :p. I have a few ways I can try, including saving and reading from a cartridge that, in fact, is a named pipe. More on that later.

The second hack is an on-screen keypad. Android users can't use pico as the keyboard does not pop up. So I made a thingie. This is what it looks like on my desktop while I play PICO-2048:

So save this bookmarklet and use it in a cartridge page: [PICOPAD](javascript:(function()%7Bfunction%20insertAfter(referenceNode%2C%20newNode)%20%7BreferenceNode.parentNode.insertBefore(newNode%2C%20referenceNode.nextSibling)%3B%7Dfunction%20lp_key_event(letter%2C%20code%2C%20type)%7Bvar%20e%20%3D%20new%20Event(type)%3Be.key%3Dletter%3Be.keyCode%3Dcode%3Be.which%3De.keyCode%3Be.altKey%3Dfalse%3Be.ctrlKey%3Dtrue%3Be.shiftKey%3Dfalse%3Be.metaKey%3Dfalse%3Be.bubbles%3Dtrue%3Breturn%20e%3B%7Dwindow.pressZ%20%3D%20function()%7B%20%20%20%20%20%20document.dispatchEvent(lp_key_event(%22Z%22%2C%22Z%22.charCodeAt(0)%2C%22keydown%22))%3B%20%7D%3Bwindow.pressX%3D%20function()%7B%20%20%20%20%20%20document.dispatchEvent(lp_key_event(%22X%22%2C%22X%22.charCodeAt(0)%2C%22keydown%22))%3B%20%7D%3Bwindow.pressLeft%3D%20function()%7B%20%20%20document.dispatchEvent(lp_key_event(%22%22%2C37%2C%22keydown%22))%3B%20%7D%3Bwindow.pressUp%3D%20function()%7B%20%20%20%20%20document.dispatchEvent(lp_key_event(%22%22%2C38%2C%22keydown%22))%3B%20%7D%3Bwindow.pressRight%3D%20function()%7B%20%20document.dispatchEvent(lp_key_event(%22%22%2C39%2C%22keydown%22))%3B%20%7D%3Bwindow.pressDown%3D%20function()%7B%20%20%20document.dispatchEvent(lp_key_event(%22%22%2C40%2C%22keydown%22))%3B%20%7D%3Bwindow.releaseZ%3D%20function()%7B%20%20%20%20%20%20document.dispatchEvent(lp_key_event(%22Z%22%2C%22Z%22.charCodeAt(0)%2C%22keyup%22))%3B%20%7D%3Bwindow.releaseX%3D%20function()%7B%20%20%20%20%20%20document.dispatchEvent(lp_key_event(%22X%22%2C%22X%22.charCodeAt(0)%2C%22keyup%22))%3B%20%7D%3Bwindow.releaseLeft%3D%20function()%7B%20%20%20document.dispatchEvent(lp_key_event(%22%22%2C37%2C%22keyup%22))%3B%20%7D%3Bwindow.releaseUp%3D%20function()%7B%20%20%20%20%20document.dispatchEvent(lp_key_event(%22%22%2C38%2C%22keyup%22))%3B%20%7D%3Bwindow.releaseRight%3D%20function()%7B%20%20document.dispatchEvent(lp_key_event(%22%22%2C39%2C%22keyup%22))%3B%20%7D%3Bwindow.releaseDown%3D%20function()%7B%20%20%20document.dispatchEvent(lp_key_event(%22%22%2C40%2C%22keyup%22))%3B%20%7D%3Bvar%20el%20%3D%20document.createElement(%22div%22)%3Bel.innerHTML%20%3D%20%22%3Cdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22display%3Ainline-block%3B%5C%22%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20background%3Ared%3B%5C%22%20onMouseDown%3D%5C%22window.pressLeft()%5C%22%20onMouseUp%3D%5C%22window.releaseLeft()%5C%22%20ontouchstart%3D%5C%22window.pressLeft()%5C%22%20ontouchend%3D%5C%22window.releaseLeft()%5C%22%3E%20%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22display%3Ainline-block%3B%5C%22%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20background%3Agreen%3B%5C%22%20onMouseDown%3D%5C%22window.pressUp()%5C%22%20onMouseUp%3D%5C%22window.releaseUp()%5C%22%20ontouchstart%3D%5C%22window.pressUp()%5C%22%20ontouchend%3D%5C%22window.releaseUp()%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20background%3Ablue%3B%5C%22%20onMouseDown%3D%5C%22window.pressDown()%5C%22%20onMouseUp%3D%5C%22window.releaseDown()%5C%22%20ontouchstart%3D%5C%22window.pressDown()%5C%22%20ontouchend%3D%5C%22window.releaseDown()%5C%22%3E%20%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22display%3Ainline-block%3B%5C%22%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20background%3Ared%3B%5C%22%20onMouseDown%3D%5C%22window.pressRight()%5C%22%20onMouseUp%3D%5C%22window.releaseRight()%5C%22%20ontouchstart%3D%5C%22window.pressRight()%5C%22%20ontouchend%3D%5C%22window.releaseRight()%5C%22%3E%20%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22display%3Ainline-block%3B%5C%22%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22display%3Ainline-block%3B%5C%22%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20background%3Ared%3B%5C%22%20onMouseDown%3D%5C%22window.pressZ()%5C%22%20onMouseUp%3D%5C%22window.releaseZ()%5C%22%20ontouchstart%3D%5C%22window.pressZ()%5C%22%20ontouchend%3D%5C%22window.releaseZ()%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22display%3Ainline-block%3B%5C%22%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20background%3Ablue%3B%5C%22%20onMouseDown%3D%5C%22window.pressX()%5C%22%20onMouseUp%3D%5C%22window.releaseX()%5C%22%20ontouchstart%3D%5C%22window.pressX()%5C%22%20ontouchend%3D%5C%22window.releaseX()%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3Cdiv%20style%3D%5C%22width%3A100px%3B%20height%3A100px%3B%20%5C%22%3E%26nbsp%3B%3C%2Fdiv%3E%22%2B%22%3C%2Fdiv%3E%22%3BinsertAfter(document.getElementById(%22canvas%22)%20%7C%7C%20document.getElementById(%22playarea_0%22)%2C%20el)%7D)())

I'm writing a roguelike! it's not even a game at this point, because all the gamey bits are missing (victory conditions, interesting decisions, etc). So you need stuff(monsters, magic, item, traps). But how do you put stuff in?

For the time being I'm doing it when the room is created. The rooms can vary in size a whole lot by design, but I'm kind of worried about having the same amount of stuff in small and huge rooms.

So I decided for he following algorithm:

1: each room has a 50% chance of having a monster, and if it does try again (and then again, etc)

2: rooms bigger than 20-40 locs should have as many attempts to have monsters (so 2 attempts if >30, 3 if >60, etc)

Here's the code. I understand it's really not much, but it does a neat trick

function stock_room(x,y,x2,y2) local area = (x2-x)*(y2-y) -- the size of the room do if chance(0.5) then -- 50% chance spawn_monster(x,y,x2,y2) else area -= random_in_range(20,40) end while area > 0 end |

Hi,

I wanted to implement line of sight for a roguelike today so I started looking up Bresanham's algorithm and ended up writing a parametric version of it because mixing conditionals and iterators makes me barf. :p

I'm posting the implementation algorithm because I'm not sure if I'm doing things in a way that is blatantly wrong for Lua, or if there's a better way. I'm very new to Lua so, well, I'm kind of clueless about how to write good Lua software. I saw a few implementations around and was wondering what's the best choice for LOS in Lua, also considering that code points are a scarce resource and between them and heat maps I feel somewhat... constrained. So, yes, what's the best line-tracing implementation, given a metric of your choice?

Here's mine. It has as only advantage a clean iterator. :)

function los(x,y,x2,y2) local c_x = x -- x position of the cursor along the los local c_y = y -- y position of the cursor along the los local dx -- the deltas will determine how much to move the cursor along both axes local dy local i -- how many real pixels long the line is. Not the diagonal nor the manhattan distance if (x == x2) then -- do not divide by 0 ;) dx=0 dy = sgn(y2-y) i = abs(y2-y) else dx = x2-x dy = y2-y if (abs(dx) > abs(dy)) then i = abs(dx) dy = dy/i dx = sgn(dx) else i = abs(dy) dx = dx/i dy = sgn(dy) end end i = i-1 -- we only need to check that the intermediate positions are not occluding, not the start nor the end for c=1,i do c_x += dx c_y += dy -- if you want to memoize that this location is visible from x,y, do it right here before the test if (obstruction_at(flr(c_x+0.5),flr(c_y+0.5))) then -- there's no round, only zuul return false -- no LOS end end return true -- ok LOS end |