Tuesday, December 16, 2008

It has presence

Today marks the first time in history that World of V is available to the public.
Last night I signed up for hosting on WebFaction, and today I loaded up the code and got it working. Normally, such a step would require a few blog posts about the steps I had to take to get everything up and running, but with webfaction I don't need to!

Everything works exactly the same, although I cutely disabled registration for new accounts. The nice thing is that I can now get a feel for the lag while moving and interacting with the site. I do need to put something in to discourage people from clicking and not waiting for the lag, since it is AJAX, you don't notice that things are going on behind the scenes.

So that's very cool.

I still have some work to do with abilities, security, interface, and clean-up, but it's a damn good start. At least I know it will actually work.

And so the countdown begins: 45 days until alpha-launch.

Tuesday, December 9, 2008

Being Productive


I have been very productive lately.
Here are the things I have accomplished:

  • I worked on the interface a little. I don't know if it is the final interface I will go with, but it doesn't look to bad. You can see a screen shot on the right. I used some jquery rounded corners and CSS fun to change the color based on the map type. I still need to play with the other interface elements such as the mappable's info, the character info, messages, and abilities, but it's a start.
  • As the screen shot may show, you can also view the mappable items that are not in your current map cell. This had always been planned (how else could you hunt down monsters?) but never implemented. I improved the way that the map cells are created and streamlined the retrieval of the mappables in the surrounding and current map cell. For now, equipment and items not in the current map cell still won't show. I think that's pretty cool.
  • Abilities totally work. Not only do they work, but they can send back forms or something else to get more information from the player and they return a json object that indicates what interface items should be reloaded. For example, if you choose an ability that only changes the messages and the character info, you won't reload the map or the mappable info. This should save network and time.
  • Did I mention Abilities totally work? They also are implemented differently. Now, if I want to make an Ability, I just create a class in the abilities module that extends Ability and implement a perform method. The method may return different results depending on what data was passed. For example, for messages, if no message data was passed, then it returns a form asking for the message to send, then a message will be passed and so the message gets sent to the other player.
  • What else? The JavaScript has been cleaned up as well as the map loading. Map cells are now loaded individually, and the client-side tracks what mappable we are currently showing the info for.

Okay, maybe there are other advancements, but that's all I can think of for now. I'm hoping to keep the Jan.30th deadline for total deployment of Stoneage.



Did I mention that I know exactly how the story is going to be and the quest system? I don't think so.

Tuesday, November 11, 2008

Anniversary

Well, I missed the 1 year anniversary of this blog, but that doesn't matter since when it started I was still in WebObjects land.

You know what would be cool? If I released StoneAge on January 30th, 1 year exactly from the date that I started working on the Django implementation.

Whoops, I just screwed up! I accidentally gave myself a deadline!

CJson

So I installed my first python module (other than django).
This involved the following steps:

  1. Download the module from the site:http://pypi.python.org/pypi/python-cjson/1.0.3
  2. Unzip and move to '/Library/Python/2.5/site-packages/'
  3. Go there in Terminal and inside the python-cjson directory run 'python setup.py install'. The README should indicate this, but this is one of those things that everyone should know, so why bother, right? Grrrr...


It works! and so does 'import cjson'!

Strangled by Python

For the latest cool stuff I want to do with the ability views, I needed the new json library in Python 2.6. Unfortunately, there's problems with the binary release of 2.6 on the Mac. When I installed, running 'python' from the Terminal still shows 2.5.1, I think there may be other issues, but it might be related to this problem:
http://bugs.python.org/issue4017

Here's the steps I'm trying to fix it:

  1. Download 2.6 compressed source from http://www.python.org/download/
  2. Open Terminal and configure the install with './configure'
  3. Build python with 'make'.
  4. I got 'Operation Not Permitted' when I first tried to install, so I had to install with 'sudo make install'.
  5. Still didn't work, so I looked around and found 2.5 inside '/System/Libraries/Frameworks/Python.Framework/' and a symbolic link called Current. I moved 2.6 into there and remade the symbolic link to now point to 2.6 with 'ln -s 2.6 Current' (from inside the Python.Framework directory).
  6. Still didnt work, so I restarted.
  7. That didn't work, so I'm giving up for now.....


Apparently there are major issues anyways with the binary distro (see the very bottom):
http://wiki.python.org/moin/MacPython/Leopard

So I'll just wait for now, maybe find a better json serializer.

Friday, October 31, 2008

Map Editor

I made a map editor!

Friday, September 19, 2008

First Looks at the System

I finally have things connected and can now get my first idea of how everything is working together.

Many of the views are done. The view for moving and getting the map, the view for getting the messages, for getting info on a mappable item when the user clicks it, and for getting the abilities when a user clicks a mappable.

Clicking an ability almost works. You can attack monsters and kill them, but what if the ability needs more things from the user? What if it is a message, we need to get the message. What if you want to cast a spell, we need to get the spell from the user. So the next step is to deal with passing things back and forth based on the ability. Or maybe send it all with the info on the mappable. I was thinking about looking a jquery, and using that to decide, but that doesn't fit my design model of back to front. So I should look at the info view and see what way makes the most sense, do it on the back end (or, I guess, middle end since it's the view), and then make jquery and the client-side javascript work with it.

I also spent some time playing with the lovable mod_python and apache. I learned a lot and now see how this will all work together.

So... you can walk around, click on Monsters and attack and kill them. That's cool.
But then again, the page is super-ugly. I'll work on that later.

Saturday, August 16, 2008

Forms, Helpers, and Views, Oh My!

Views do three things: take in the request, do some logic, push out the response. I had a difficult time figuring out how I was going to use views and the new newforms forms recently added to django. My major concern was that I wanted to have all data validation handled in one place (which newforms is great for), but I wanted to be able to process information that might not have come from a browser session (which newforms sucks for). I went back and forth, but finally decided on the following system.

All form data will come in as a newforms form. This is easy for webpage submits, but may require a little movement of data when stuff starts coming in through REST or webservices or something. The form handles validation and is pushed of to a helper method that does further validation and handles data transactions. This way both the site views and web services can operate with these helpers. Finally, the view sends back the reply, either a reload of the page, and redirect to a new page, or renders a template.

When looked at this way, testing became much easier, too. I test each view pretty much 3 times. 1 test is for the form, making sure valid forms are valid, and invalid forms are invalid. Another test is of the helper, that it validates the form correctly and handles the data properly, moving, saving, updating or not as it should. Finally, I test the view using django's test client. I like the test client system. It is very easy to use to test results and processes.

The nice thing about working with views is that I still don't have to worry about how it will look. I just test that for certain input (usually data provided to a form, or a dict) I get the expected output (status code, template rendered, and the correct data in the template's context). Easy!

Using this method I have created and tested the views for user registration, login, avatar creation, avatar selection, game map, and movement. I'm currently working on some views for other functions of the main game area: Message viewing, character profile viewing, and the fun abilities. I still need to do some inventory and equipment and equiping views, plus some things I've probably not even thought about yet but that need to be done for Stoneage.

Stay tuned.

Friday, July 25, 2008

Notes

I did upgrade to django 1.0 Alpha. No real problems yet, but we'll see.

I've also added a list of things to be done on the side of the page. Right now it's views for the Stone Age release. I've decided to work on things in the order which the user will see them, so first connecting User registration to Avatar creation, and User sign-in to Avatar selection. Then the map and some interface stuff.

Thought you'd like to know.

Milestone, and moving on

User sign up is done thanks to some good django documentation, and no thanks to some bad django documentation.

Since user registration is almost-universal to web applications, there are plenty of resources on how to do it. Most of the programming is copy-paste-edit from my Avatar creation forms and views.

The only problem was creating a user profile model. This model saves extra data about a user that isn't in Django's included User model. I haven't thought of anything to add, but I'm sure I will, so I worked on it anyway. The problem came when connecting the models together with a foreign key. The main docs don't indicate that this foreign needs to be called 'user' to work correctly (I named mine 'djangoUser'). The Django book correctly notes this. I created a ticket about this, so we'll see what happens.

And with that, at 5:33PM, on Friday, July 25, I officially close main development on the back-end models for my initial release (hereon codenamed 'Stone Age') and move up a level to start writing views.

Friday, July 18, 2008

Auto-monster

Ever since I came up with the idea of V, the problem of monster movement and generation chewed on the back of my head. Somehow, no matter what programming language or platform, things had to happen on their own. I would always sooth the teeth marks with "Somehow I'll use threads, or maybe crontabs if I have too." A few weeks ago, with very little left on the menu, I finally tamed the beast, and following what is becoming a V standard, I created an independent system for handling background tasks.

MinLis, or Minute Listener, runs saved events at a scheduled time. It works as a background thread that wakes up every 60 seconds. It checks the database for any events scheduled to run, fires those events, and goes back to sleep. The events are django models saved to the database. They store the scheduled time to run and how often to repeat (if at all). So far there are two type of events, events that can run a method on a model (using generics) and events that run a string through python's eval(). This way, to schedule something to run, all you have to do is save an Event to the database. One problem the eval creates is that modules must be included somehow, so I still need to create a separate include file. I created MinLis as a separate django application and have also created a google code project for it. I haven't done anything to the project yet, but once she's polished I will open her up to the world.

With MinLis working in the background, I started moving monsters around. I added a preferred map type field to the monster type model and an aggression level to monsters (these were always planned, but not necessary until now). The code for wandering monsters moves any monsters with a low enough aggression to a random surrounding map cell of the preferred type. A MinLis scheduled event runs the code every 5 minutes.

Finally, I finished monster generation. Another new field in MonsterType tracks the average number of monsters of that type that should exist. The generation code checks if the current count of existing (or waiting to exist) monsters is under this average. It then creates a random number more, but schedules them to be created every minute so that they don't all pop into existence at once. This is scheduled to run every couple of minutes.

Many of these timings will eventually be randomized. I don't want users to anticipate that every 5 minutes monsters move. But for now it's fun to kill a couple of Trolls, wait for new ones to pop out, and then watch them walk around (okay, all of this is still through text logs, but it's still cool anyways).

Amazingly, there is only 1 item left before I start moving forward with views: User sign-up. Today is django sprint and they are apparently going to merge the newforms admin into the trunk. I'm going to wait a little while, see if there are any problems, then update and see what (if anything) breaks.

Plus, there's a new beast lurking: Quest system.

Monday, June 30, 2008

Items and Equipment

This past week I have been working on the items and equipment system.

Both systems work similarly, using Django's contenttype and generic relationships to connect characters and the items and equipment they hold. Items are just names for right now. There is no programming underneath to make something special happen if you get a certain item, or programming to control what you can do with an item, but that will follow as soon as I figure out how to do it. The number of items a character may have is currently a hard-coded value. That fits with the simplistic nature of the first release. Nothing fancy, you only get 4 items.

The equipment system is even worse. Each piece of equipment has a type, like sword, helmet, shield, and each type has a slot, like on-hand, head, off-hand. Currenly, you may only equip one piece per slot, which makes sense. However, you may not carry extra equipment and have it take up a slot in your item inventory. I know this is lame, and I'll do something different eventually, but I like the thought that if you defeat a monster or find good equipment, you must decide to equip it right there, dropping whatever was previously in that slot. It again simplifies things.

Now, I am connecting equipment with stats. The stat that is increased is based on type, so swords raise strength while attacking, helmets raise toughness while defending, staves raise knowledge. The amount of increase is based on 2 modifiers, the equipment modifier, and the equipment's material. These numbers are multiplied, so you can have a silver sword +2 be as good as a gold sword + 1. Material is going to be a fun system in V, perhaps with quests for rare materials.

Looking at my goals for 1st release, I have a few things left on the back-end:
  • Monster and item generation

  • Monster wandering

  • User creation



Once these are done, I should be able to start working on views for the interface, then pull the interface all together.
Yay!

Tuesday, June 24, 2008

Levelling and Creation

Levelling and Avatar creation have been completed and tested.

Levelling forced me to finalize my Fighter stats structure, and think about how I would flexibly control advancement. I decided that each tribe controls how many points each stat increases for every level, plus maximum Hp and max Sp. Extra will be added to maxes based on knowledge and stamina. Every level also grants Level Points which can be spent on attributes.

For Avatar creation, I learned about the newforms system in django. I built a helper method to do the actual creation, and a form to pick the name, sex, and tribe. After object creation, every new Avatar is randomly assigned to a clan of the chosen tribe, moved to the clan's starting location, given starting stats, and "leveled up" to level 1.

Next steps include:

  • Items
  • Equipment
  • Monster wandering

Thursday, May 29, 2008

State of V

3 months and a few refactorings later, V is nicely moving along.
Pieces and models are beginning to fit together and I am adding new
functionality all the time. I am headed toward a goal of a simple
alpha release with user sign-up, avatar creation, movement, fighting
wandering monsters, level advancement, and items. I so far have the
movement, fighting, and levelling programmed on the back-end. Let's
see how I got there and how I set up the infrastructure.

Unlike previous V implementations, I developed django-V from the
bottom up. I started by designing the models. I started with the same
map models that I have been using all along. One class for each map
type, a class for the map region, and a class for each map cell that
holds the type for its x,y location. I even had old SQL import
statements so that I could define a starting map to work with. This
was a good introduction to django models since I was making something
I was familiar with in a language and framework that I was not
familiar with.

Next, I designed and implemented the main class structure: Mappable.
Mappable is the superclass for all models that can appear on the map,
including Avatars (the player's character), Monsters, NPCs, Items, and
Buildings. It encapsulates location storage, placement and movement
methods, and the Abilities system (more on that later). Making the
model was easy, but extending it was harder. When I started, I had to
do some hacking to make inheritence work in django. The fields and
models were inherited correctly, but the objects Manager did not work
correctly, so every subclass had to specify it explicitly. Recently, I
upgraded to latest development release, and the single-table
inheritence fixed all of the necessary hacks.

There are two branches off of Mappable, Thing and GameCharacter. Thing
splits into SmallThing (anything an Avatar can hold, like items and
equipment) and BigThing (cannot be held, but still placed on the map,
like buildings and signs and fountains). GameCharacter includes all
living beings. It first splits into NPCs (can't fight) and Fighter.
Fighter then splits into Avatar and Monster. While this may seem like
a complicated inheritence structure, it reduces A LOT of coding (don't
have to specify xLocation and yLocation for everything) and makes it
easy to add new types.

The Mappable structure also aids in coding the interface. The
interface works by getting a list of all of the Mappable objects in
the same location as the player's Avatar. The template then lists
through these objects and displays them. The display interface is all
the same (a 'name' property), so if I create a new Mappable model, I
do not have to rewrite any view or template code in order to display
it. The only problem is actions.

An Avatar can attack a Monster, but can only talk to an NPC and pick
up an Item. I needed a standardized way to represent the abilities
that could be performed on a Mappable. I also needed a way to specify
which actions an Avatar could perform, which could change depending on
the Avatar's type (only magic users can Cast Spell), level (so that
you gain abilities as you level up), and equipment. The goal was to
easily create a list of abilities for each Mappable object that is an
intersection of the actions that can be performed on the Mappble, and
the abilities that the Avatar can currently perform. And so, I created
the Ability system.

The Ability system both standardizes abilities and the methods that
perform them. Abilities are definied by a standardized name. Each
Mappable subclass defines a list of Abilities which can be performed
on the object. This also includes superclasses (any subclass of
Fighter automatically can have Attack performed on it). Also, a method
in the Avatar class retrieves all Abilities which the Avatar can
currently perform. The execution of the Ability is standardized as
well. There is a standard naming convention for Ability methods that
depend on whether the Mappable is either performing the Ability or is
the target of the Ability and when the method is executing. The
interface calls a single method which dynamically builds the method
names and calls them indirectly. This way, a Mappable can define a
brand new Ability and implement it without changing code in any other
model.

I liked my Mappable and Ability structure, but I wasn't sure if it
would work. I next moved out of the back-end, and began doing some
interface programming. I built the map template and started loading
data from the database. For AJAX-y stuff, I included the JQuery
javascript library.

When the user clicks a new location, in the
background JQuery requests a url based on the direction the Avatar is
moving, a view in django handles the movement and loads the new map
template, then sends the HTML back to JQuery which it loads into a
<div>. The list of Mappables, and their list of Abilities, is included
in the template. When the user clicks on a Mappable, the Abilities
appear below it, and when a user clicks on an Abilitiy, JQuery sends
the data in a background POST request. Django performs the Ability,
and sends back the new map HTML. Ahh... progress.

Relieved that my system worked, and that I hadn't just wasted several
weeks of my life on this thing(again), I moved back to the models
where I didn't have to worry about things like layout and colors. My
first Ability implemented was Message. This allows Avatars to send
messages to one another, and allows the system to send messages to the
Avatar. To test, I wrote unit test cases and eventually got fixtures
to work. After that, I moved on to Attack. I decided on fighting
statistics (perhaps more on that in another post) and programmed the
initial fighting system. It's a simple system with a simple formula
that may need to be tweeked, but it works for now. Finally, if you can
kill monsters and gain xp, you need to be able to level up, so that it
is what I am working on right now.

On the side (which would make it a side-project to a side-project) I
am also writing a project management system to control what tasks need
to be accomplished. With this project I am learning a lot about the
django admin interface which I plan to use heavily in the future (way
more on that in a way later post).

Up next is to finish the levelling system, including stat progression,
and unit test it. Then it's on to items (which I finally have figured
out how I'm going to do) and Avatar creation.

Tuesday, February 12, 2008

Configure a Django project

Here's how to create and configure a new Django project with a mySQL database on Mac OS X:


  1. Create the project. This one is easy. CD into the directory that will hold the directory for your code. Then type in:
    django-admin.py startproject 
  2. Edit settings.py All of the configuration settings are in settings.py. All of the ones at the top that start with DATABASE are the ones you want to touch. The biggie is DATABASE_ENGINE. Set it to this, for mysql:
    DATABASE_ENGINE = 'mysql'
    At the bottom, is INSTALLED_APPS. This setting includes (or removes) extra applications for your project. Take out anything you don't need.
  3. Test the db. To test the database, run the syncdb that creates the database from the models.py and settings:
    python manage.py syncdb
  4. Test the server. If that worked, test the included server:
    python manage.py runserver

Yay! It works!

Wednesday, January 30, 2008

Setting up Django

Here's the steps to setup Django:


  1. Get Python. This was the easiest part because Python is installed by default on Mac OS X. Not only that, but Leopard includes the most up to date version (2.5.1). You can check the version by typing in python at the terminal.
  2. Install Django. There are 2 Django releases, the released version, and the development version. The documentation does a great job of pointing out what features are available in the current dev version. While normally I only trust the released versions, I liked many of the new features (especially the named URL paths which was probably taken from Rails) so I decided to go for the recent build. Installation wasn't too bad, primarily because subversion is also installed with Tiger. The only problem was that the documentation gives two different methods of installation. The tutorial suggests adding a symbolic link in the python lib directory and the usr/bin directory. The Djano book gave instructions for adding a path document and including django in the system PATH variable. I did the latter, putting my djtrunk directory in /Library/. The only thing to know is that the site-packages directory is in /Library/Python/2.5.
  3. Install MySQLdb. A database binding is needed so that Python can talk to MySQL. You can get MySQLdb from its SourceForge site. After downloading and extracting the tar-gzip, you must edit site.cfg to point to the installation of mysql. Replace the line that begins with #mysql_config with:
    mysql_config = /usr/local/mysql/bin/mysql_config
    Next you need to do a little work to prevent some errors. See the post here and follow steps 3 and 4.
    EDIT: 12/23/08: Murphy remains an optimist, and the link above is gone. Here are the needed steps:
    1. edit _mysql.c and comment out the line "#define uint unsigned int".

    2. And then type in this:
      sudo mkdir /usr/local/mysql/lib/mysql
      sudo cp /usr/local/mysql/lib/libmysqlclient_r.16.dylib /usr/local/mysql/lib/mysql/libmysqlclient_r.16.dylib




    Finally, install from terminal with the following:
    python setup.py build
    sudo python setup.py install

And that's it. There are some things to do to set up each project, but I'll leave that for the next entry

Things change again.

Many things frustrated me with Ruby on Rails. I hate migrations. I also ran into issues with the auto-pluralization of models and database tables. Finally, I figured out that RoR was focused toward supporting user-created content and doesn't provide the same benefits when you are making a web application, let alone a web game. And then there's Ruby, a language that, while beautiful, has a strong learning curve to get the most out of it.

So I changed again.

For some reason, I started looking at Python. I've never programmed in Python before, but I knew it was C-like. I read through a couple of tutorials, and docs, and liked what I saw. It has the fun and power of Ruby, but is easier and more approachable.

The next step was to find a good web framework. The first one I looked at was Django. To me the most important things in a web framework are its Object Relational Mapping, its content management tools, and its ease of data access. I looked at the other Python frameworks, and liked Django the best.

So I switched again, so sue me! On to v7.0!