Log In  
Follow
tsojcanth
[ :: Read More :: ]

So I made raycasting.

No code yet because it's really rubbish and needs cleaned up.

P#21367 2016-05-25 21:41 ( Edited 2016-05-26 21:23)

[ :: Read More :: ]

It would be great to have a way to output information to a log file.

P#21132 2016-05-23 04:58 ( Edited 2016-05-31 15:49)

[ :: Read More :: ]

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.

Cart #21114 | 2016-05-23 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

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).

P#21116 2016-05-22 20:34 ( Edited 2016-05-23 08:53)

[ :: Read More :: ]

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))

If you want to save tokens you can do away with defining push and enqueue and just use add() instead.

P#20837 2016-05-19 03:40 ( Edited 2016-05-21 10:00)

[ :: Read More :: ]

[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)())

It will create the dpad and the two buttons: Z on the left and X on the right. It also creates the buttons on a desktop browser. Try clicking on them.

To save it on android:
1: copy the bookmarklet link
2: create a bookmark of any page, rename it as PICOPAD, change its URL to the link of the bookmarklet
3: save the bookmark :3
4: go on a page with a pico game player
5: go the address bar and type "PICOPAD". A result should be there, starting with "javascript:(function)%7B..."
6: tap on it!
7: tap on your new keys!

For the time being it's not 100% reliable but it is perfectly adequate for turn-based games. The code is really garbage that should be better factored but hey whatever, it's a proof of concept.
One known bug: pressing too long on a button selects it. I'll eventually fix it.

LICENCE: CC-NC-BY-SA.

P#20836 2016-05-19 03:37 ( Edited 2016-11-12 10:08)

[ :: Read More :: ]

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  

So before i start do delve into the pinzillacchere accretion pattern I wanted combat done, a level generator and monsters spawning. Combat is done! monsters can fight and die!

Small screenshot here with the wizard chased by an angry mob. I also added x-flip to the actor's sprite depending on their direction. Not much but helps a lot make sense of screenshots.

I can start coding the DODECATHAUMAGRAMMATA and the monsters tomorrow :)

P#20731 2016-05-17 18:40 ( Edited 2016-05-18 12:58)

[ :: Read More :: ]

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

I ended up shadowcasting toward each of the border coords in a 11x11 bounding square, with the player in the middle. That's 42 rays. But then some walls that ought to be visible were not, so i cast 38 more rays to the 9x9 bounding box, and everything is ok.

P#20621 2016-05-15 19:00 ( Edited 2016-05-16 09:36)

Follow Lexaloffle:          
Generated 2024-04-19 04:29:55 | 0.072s | Q:14