Showing posts with label algorithm. Show all posts
Showing posts with label algorithm. Show all posts

Thursday, January 13, 2011

Adventurer 0.0.2.4 - Lowercase Creatures and Timing System


The bestiary file was what, 2 kb before? 82kb now. I spent a good deal of time for this update on filling out the bestiary, referencing Nethack data. I got all the lowercase creatures. If I'd done the rest, it would be well into next week before the update would be out.

I also worked on the timing system. Before, it progressed by having the player move, then all the other creatures would move, then the world would update. IT was very quirky and I ended up breaking a lot of things that way. Doing any sort of nonstandard timing was near impossible. So I just rewrote all that to be a tick/energy based system. Basically, it simulates the flow of time and only then does it start assigning who's turn it is, based on said flow of time.

This did and enables many things. First and foremost, creatures have varying speeds and it all seems to be working perfectly. If you're a jelly, you're not going to be moving very quickly. If you're a warhorse, you're going to be racing circles around opponents. Another thing this enabled is the easy resolution of the tripwire issue - yes, tripwires finally work. I also reduced the number of them on any given level. There were really just way too many, especially since there isn't variety in traps yet.

Next week, I'm working on some new features, rather than just filling out the ones that are already there. Mostly, I'm going to try to add new types, and more items of types that are already in. Items with different uses, more items to implement in crafting, more varieties of potions, scrolls for one-use effects... heck, I may even get some magic working. Creatures got their week of targeted development, now I'm going to give items theirs.

Saturday, January 1, 2011

End of Year One

I was going to post an update tonight. I really was. But there's a little more to do left before it's ready. I'd rather post the complete thing tomorrow, than leave you for a week with a bestiary disproportionately full of insects and blobs, but lacking in everything else. My resolution this year? Lose some weight. Write something. Make Adventurer popular enough to get Google to pay me something for the ad space. And I know I've just jinxed all three.

So it's 2011. Okay, only half a year of Adventurer. But it's a big milestone. So what have we accomplished so far? Well, Adventurer has gone from a small hobby project using the restrictive but simple XNA, to what is becoming a truly playable or even enjoyable roguelike using more sophisticated, easier to run techniques such as SDL. When I started, I had no idea what a List was. Now, I know how to do A* pathfinding with binary search.

I've learned a lot through the process, and I'm still learning more. Looking back, I can almost kick myself on some of the ways I stumbled through the process. But I was learning, I gave it my best, and darn it if I didn't just power through all the problems and turn out a working roguelike. Now that I know better, I'm going back and upgrading some of my old code. As well as developing more.

What am I doing for tomorrow's update? Well, a good deal of what I've done is fan-found fixes (fanciful alliteration there) and suggestions. Don't groan: it's part of establishing Dev Team Thinks Of Everything. More appropriately Anonymous Thinks of Everything and Dev Guy Makes it Happen. This week's major contributor towards making bug fixes happen was the forum-goer known as Archenon, who broke the game in ways I didn't even know were possible. I'm also adding a lot of creatures, so that next week I can focus on making them unique with status effects and such. You know, spiders that can web things up, wizards that can confuse you, gels that can hold you in place, poisons, etc. Also I'll be working on potions and possibly scrolls to do the same things. I'm afraid tripwires are going to be broken still until I next week add an effect to stun/paralyze you for a short duration.

The blog stats: December - 803 views +40% All time - 2292
The main page stats: December - 862 views +29% All time - 2462
Ads/Donations: December - $1.69; $0 All time - $6.32, $0

What does this tell me? Well, there's a linear growth rate of 30-40% on views, it's always seemed to be that way. Which still means the absolute increase in views is exponential. Notice that though Adventurer has been going for seven months, December had a third of the views. Exactly. Ad revenue has also been on the rise. Maybe if it keeps increasing, I'll be able to get some actual web hosting. If you think that is a good use of the money. Really, what do you think I should do with it? Also, it makes me a sad Kala that no one out of 2000+ people has donated anything. I thought I would get a rate more like 1%. Or 0.1%.

Some other interesting stats are from the scary amount of data Google Analytics offers. For example, I know most of you are browsing this blog with Firefox on a Windows operating system running in 24/32-bit color at 1280x1024 screen resolution, and you live in the United States in either Washington, California, Tennessee, Texas, or New York. Whoever that is near Bellavue, Washington: I'm on to you and your 48 visits. Admit it, you're obsessed. >:D Also, ha ha, I get it Finland: one of your towns is named Kalasen. Although I don't get YOU, Russia at third place. China still remains sadly unaware Adventurer exists.

So happy new year everybody. And remember: Both I and Google know what you did. Yes you.

Tuesday, December 7, 2010

0.0.2.0 Graveyard Files




I'm almost back on track with this update. I'm a day late, so sue me. Actually, don't sue me, I haven't even made five dollars yet. This was never meant to be a major update, so don't expect a ton of new features.

What I did do, first off, is fixed some of the bugs from the last update. Yeah, that was a major update. You had items multiplying on reload, and sometimes when a level would try to save, it would hit a null item, give up, and cry. No more, I fixed that. As far as what I added instead of just fixed, two things. The first is graveyard files. Whenever you die, a file is buried in the graveyard preserving some stats on your run. Also I fixed potions to where shattering against a foe causes their effect. This opens up the options for things like poison and acid later.

I also sped up pathfinding considerably by having it return a path in a stack of moves, instead of a single move that has to be calculated each time. What this means is that the processing can be used elsewhere. Specifically, what I'm going to work on next week, temperature and its effects.

Yes, next week will have temperature and ways to affect it, as well as things it affects. Set things on fire, freeze water, etcetera.

Friday, December 3, 2010

End of Month 5 - November; Full Persistence and Save Files

I'm not dead. I'd just locked myself away in a white room, with only a television, a bed, and a computer to fulfill my needs. And guess what? I only watch TV out of utter boredom or to get a laugh out of the ads. As in, laugh at some of the cheap marketing techniques that no one should really fall for, but do. But mostly, I spent my time working on this update.

I cannot begin to describe the complexity of what went on here. Wait, I think I can: I can perfectly (presumably, there may be bugs) recreate a session's universe based on what I've saved in text files. They are relatively small. A universe in which I dived down fifty levels was less than 300 kb saved. Basically, I crammed a universe into 2 million on/off switches, and can recreate it all from those files. It wasn't easy, either; there is no command to write what's in memory to the hard drive that I know of. I had to write it all in legible text based on what is in memory, and save it to a plain text file. What all this means for you? Truly persistent levels and save files. When you drop an item and come back, it will still be there.

I had some hilarious bugs while I was working on this, too. At one point, I was randomly switching bodies with random wildlife. Dragon on a rampage through the forest, while I was suddenly a wolf. We had whole inventories shuffling from one creature to another. I was suddenly a quest giver. And I can't even near promise all the bugs are out. But it seemed to work well enough after a fair amount of play testing.

As for the statistics so far. 1308 downloads grand total. 549 blog views this month, up 27.38%. 636 code page views, up 36.77%. $4.63 in ads grand total, $0.66 this month. No donations. So it seems that views are definitely on the rise, and downloads are either maintaining or growing in their rate. While the money is lackluster, I don't mind. I've learned a lot on the way and maybe I've given a few people a few minutes of fun. And I will continue to work diligently.

Next week... wow. Let's see if I can't get something simple done to get back on track, and submit Monday. Perhaps the things I've been saying the past three weeks. Maybe graveyard entries. That would be partially on the road to bones files.

Saturday, October 16, 2010

0.0.1.3 - Semi-Persistent Levels




You can get the most recent update at Google Code, as always. Two big things I did for this update. The first is semi-persistent levels. They'll keep the same floor layout when you return to them. Items and creatures will still shuffle. This, at least, will have nil effects on memory.

The second thing is that I fixed some combat bugs. Like in the quick MSPaint crud above, I think it's pretty obvious why rats were still hardcore. They were wielding daggers. It happened because in the creature loading code, I never set the default item back to null. So since rats came after goblins and rats have no weapon data, the goblin data never got overwritten in that regard. I fixed that. Also, I added something else that will help combat make more sense.

Weapons now, instead of replacing natural damage, add to it. So I went through and reworked the item damage data and natural creature damage data to compensate. In the bit of testing I did, it seemed much better. Rats are just annoying, a single goblin can seriously hurt you, but you probably won't die in an encounter unless you have terrible luck with RNG and just keep fighting. I didn't encounter any ogres or minotaurs or dragons yet, but I wanted to get the update out faster than making sure those are balanced.

So next week, I'll work more on that. I'll also see about getting more interesting interactions going on. Such as a creature not having arms and being unable to wield a weapon or open doors normally, but still able to bash down doors if they're large and strong enough (aka dragon). Also things that can get through doors should path through doors, while things that can't don't. See you then.

Thursday, September 9, 2010

SDL Conversion Complete

Since I have two or three more days before the expected update, I'll spend the extra time adding stuff. On my end, an object to handle the generation of creatures separate from the creatures themselves. This will save processing power and speed by reducing irrelevant data. On the user end, creatures will be individually generated with their own quirks, and a stat system with growth should be coming in.

But yes, the SDL conversion is complete. Everything is done and behaves exactly as it did. The advantage? Come next update, you will be able to run it right out of the box, pretty much regardless of your system layout. Heck, theoretically you can run it in Mono on non-Windows systems. I'll need more people to play test it though. I've only got one download on last week's update. :/

I faced several problems during the conversion. The first of which is that SDL is written in C, and I have to get at it with Tao. Which means lots and lots of pointers. Like I said in the last blog post, I was able to sort that out in safe code with IntPtr and Marshalling the pointer into accessible data. The second was that SDL alone does not come with some of what you think would be pretty critical commands, like drawing text or a rectangle. You have to import SDL_TTF and SDL_Gfx respectively. Which it turns out Tao included, and it took me forever to find.

And the third time-waster was looking up how to change the color of an image. You know, I have a white @ sign, I want to turn it green because it's a goblin. Well, SDL doesn't have a command for that. SDL_Gfx doesn't have a command for that. In fact, there are no commands for it whatsoever. The things I found about color key switching were all theoretical and did not work for me. No one had working code anywhere. That's when I decided to check out if anyone on the roguelike development chatroom #RGRD could give me any ideas. I will say right now that if it weren't for them, Adventurer may very well have taken two weeks to convert and still be in black and white.

#RGRD is your hero, guys. It turns out that there really is no easy way to do it, but someone helped guide me through how to make it happen. So I had the data, and the color I wanted to change it to. I have to be able to get at the data. Not normal C# stuff, I had to get at the ^raw^ data. So I needed a pointer. And not just an IntPtr. I needed an honest C style pointer. So I had to flip it to unsafe mode. Got a pointer to the raw data. Now, how to mess with it?

You can get at pointer data by saying pointerWhatever[somenumber]. That finds a block of data in there. In this case, a pixel stored in RGBA format. Or maybe it was ARGB. I forget. I then had to convert a color into its raw ARGB data. Thankfully, there was a command for that. Then I had to put it in an appropriate pixel. Well, at first I just picked one at random. White dots started appearing in images, which meant that it worked.

Next, I had to get at not just one, but all the pixels. Pixels are not stored as [x,y] coordinates in an image. They're all one dimension. Which meant I had to write a function to make that happen. Which I did with the help of the #RGRD folks. All this with the help of the #RGRD folks. Once I had access to all the pixels, I had to work out criteria for changing the color, or else I'd end up with solid color blocks. Color multiplying was brought up, and I tried to implement that. Basically, R100 * R50 = R75. Well, it didn't work like I wanted. But then I figured something else.

I simply looked for any pixel that was not transparent (Alpha > 0), and changed only those. It suddenly worked. From misshapen color garbles to the old Adventurer. And from there, it was smooth sailing. Well, except for a little kink with the shift key that I just today finished working out. After all that, the final thing was just a logic slip on my part. So it's all working, and expect an update in two or three days. I can't seem to find the chat log, which has a link to a Pastebin post which would have given you all the code. Nor can I properly thank the person who showed me how to do it. So to all my players, all of #RGRD, all of the roguelike community, and in particular that one #RGRD guy, thank you!

Tuesday, July 6, 2010

Version 0.0.0.2 is up!

**************
Version 0.0.0.2
**************

After nearly three weeks of work on pathfinding, version 0.0.0.2 is up. It really shouldn't have taken that long, I was moving onto a project that is now a core system within the game, when I should have just thrown something quick up and work on other things. But no matter. It's done now, and now I can focus on the quicker-to-implement things. In fact, I went ahead and threw in a little bit of code already in 0.0.0.2. If a creature doesn't see the player, it'll path to where it last saw the player. If still nothing, it will go back to wandering around. It sounds simple, it wasn't that hard to put in. But it greatly enhances the overall effect and realism.

That's the kind of things I'm going to be working on for 0.0.0.3. Quick, easy to implement things, as well as some general code improvement. After all, Move Creature is still the Level object's job, when it should be the job of the creature itself. Another rough edge is that creatures are stored in an array, when they should really be a list. Switching from an array to a list should speed things up, as well as allow a limitless number of creatures. I think I can put in creature spawning for 0.0.0.3.

I hope to have 0.0.0.3 ready within the next few days, and again, the project can be found at code.google.com/p/adventurerroguelike.

Sunday, July 4, 2010

Pathfinding and Binary Search

.........
.........
....W....

.@..W..O.

..xxWxx..
....x....
.........


*************
Pathfinding

*************


I'm in the process of coding the main pathfinding code of Adventurer. You may be interested to know that it isn't as simple as "go here", or "move towards here". No, pathfinding is a problem that has plagued and intrigued coders for years. It handles the problem of figuring out how to get from point A to point B. I've looked at the Bresenham Line Algorithm before, and I use it for my line of sight calculations. But if I used a pure line for deciding where to go, creatures would endlessly bump into walls if it was the most direct route in a wall-less environment. That's unrealistic and not very fun.

So I'm
looking into what is known as the A* pathfinding algorithm. What is this, you might ask? Put simply, it looks at all adjacent tiles, guesses which one brings it closer to the target, and looks at all adjacent tiles to that one. It keeps looking at the shortest paths it's found, combined with its guess at which is next. This bit of code is very efficient, and only rarely wrong, and only by a little even then. It's perfect for what promises to be the processing-heavy Adventurer.

Now, one crucial part of this is finding the lowest number in a list of numbers. I've found it's easiest for my purposes to keep the list in order, and just pluck from the bottom. The only problem comes when it comes time to put a new number into the list, i.e. the best path estimate of a tile. I have to find where it goes. Now, I could look each and every spot, and figure out where the number I'm putting in is greater than the number to the left of it, and less than the number to the right of it. This is known as a sequential search, and it's fine if you just have a few numbers in your list.

But this list is tracking all tiles adjacent to the ones it's looked at. this could be hundreds of tiles. But there's a nifty trick that works perfectly. It's known as a binary search. It works like this: Look at the number in the middle. If yours is higher, look only in the numbers to the right and look halfway there. Same if it is lower, but for the left side. Eventually, you'll find the spot where your number is right between two. Suddenly, 2 million items takes at most 20 cycles of this pattern.

So that's what I'm implementing in my code: an A* pathfinding algorithm, saving its values in a list with binary search. It might not be the absolute most efficient thing out there, nor the easiest, but it combines the two worlds in the best way I can think of. I can expand and fine tune it later if I need to.

I expect to have this implemented within a couple days in Adventurer, and have a new download up. Then that test critter can hunt you down much more intelligently. >:D

The game can be found at code.google.com/p/adventurerroguelike