startshape realStart rule realStart { start { x 2 } } background { b -1 } rule start { terminal4 { r 12 } } rule start { terminal1 { r 12 } } rule start { terminal4 { r 12 } } rule start { terminal4 { r 12 } } rule start .05 { terminal2 { r 12 } } rule terminal4 { SQUARE { b 0.50 s .055 sat 0.40 hue 95 } SQUARE { b 1 s .055 a -.8 } train { x .06 } train { r 90 y .06 } train { r 180 x -.06 } train { r 270 y -.06 } } rule terminal2 2 { SQUARE { b 1 s .055 a -.85 } train { r 90 y .06 } train { r 270 y -.06 } } rule terminal2 1 { SQUARE { b 1 s .055 a -.8 } train { x .06 } train { r 90 y .06 } } rule terminal2 1 { SQUARE { b 1 s .055 a -.85 } train { x.06 } train { r 270 y -.06 } } rule terminal1 { CIRCLE { b 1 s .055 a -.9 } train { r 90 y .06 } } rule terminal1 { CIRCLE { b 1 s .055 a -.9 } train { r -90 y -.06 } } rule train 1 { CIRCLE { b 1 s .045 a -.9 } train { x .06 } } rule train 2 { terminal1 { } } rule train .02 { terminal2 { } } rule train .005 { terminal4 { } } rule train .03 { CIRCLE { b 1 s .03 a -.9 r -95 } }

Keith's Blog

A teen's .net musings

JSAdventure

Posted on May 11, 2010 at 4:50 PM

Copy this code into an html file and then run it and you will get the saving on your computer. All this does is make it so that you get the saved cookies on your computer instead of the site which makes it so that they don’t get saved to this domain but yours which for some reason seems to work better.

<html>
<head>
    <title>Text Adventure</title>
</head>
<body onunload="save()">
    <p id="p0.3">
        You do not have javascript enabled currently. Please enable javascript to play my
        game.</p>
    <script type="text/javascript">
        "use strict";
        var versionNumber = 0.3;
        var paragraphElementID = "p" + versionNumber;
        var currentRoom;
        var rooms = {};
        var inventory = {};
        var output = "";
        var header = "<b>JSAdventure version " + versionNumber + "</b> <br/> <br/>";
        var setUp = false;
        var jsonizer = {};

        // implementation of JSON.stringify borrowed from http://www.sitepoint.com/blogs/2009/08/19/javascript-json-serialization/
        jsonizer.stringify = function (obj)
        {
            var type = typeof (obj);
            if (type !== "object" || obj === null)
            {
                // simple data type
                if (type === "string")
                {
                    obj = '"' + obj + '"';
                }
                return String(obj);
            }
            else
            {
                // recurse array or object
                var nameOfElement;
                var v;
                var json = [];
                var isArray = (obj && obj.constructor === Array);
                for (nameOfElement in obj)
                {
                    if (obj.hasOwnProperty(nameOfElement))
                    {
                        v = obj[nameOfElement];
                        type = typeof (v);

                        if (type === "string")
                        {
                            v = '"' + v + '"';
                        }
                        else if (type === "object" && v !== null)
                        {
                            v = jsonizer.stringify(v);
                        }

                        json.push((isArray ? "" : '"' + nameOfElement + '":') + String(v));
                    }
                }
                return (isArray ? "[" : "{") + String(json) + (isArray ? "]" : "}");
            }
        };

        // implementation JSON.parse borrowed from http://www.sitepoint.com/blogs/2009/08/19/javascript-json-serialization/
        jsonizer.parse = function (str)
        {
            if (str === "")
            {
                str = '""';
            }
            var func = new Function("var p =" + str + ";" +
    "return p;");
            return func();
        };

        function CreateCookie(name, value, days)
        {
            var expires = "";
            if (days)
            {
                var date = new Date();
                date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                expires = "; expires=" + date.toGMTString();
            }
            value = value.replace(/\;/g, "#");
            document.cookie = name + "=" + value + expires + "; path=/";
        }

        function ReadCookie(name)
        {
            var nameEQ = name + "=";
            var ca = document.cookie.split(';');
            for (var i = 0; i < ca.length; i = i + 1)
            {
                var c = ca[i];
                while (c.charAt(0) === ' ')
                {
                    c = c.substring(1, c.length);
                }
                if (c.indexOf(nameEQ) === 0)
                {
                    var string = c.substring(nameEQ.length, c.length);
                    string = string.replace(/#/g, ";");
                    return string;
                }
            }
            return null;
        }

        function AddToOutPut(text)
        {
            output += text;
        }

        function AddLinkToOutput(text, functionName, functionParams)
        {
            AddToOutPut("<b onclick=\"" + functionName + "(" + functionParams + ")\">" + text + "</b>");
        }

        function AddToCurrentText(text)
        {
            document.getElementById(paragraphElementID).innerHTML += "<br/" + text;
        }

        function WriteStoredLine()
        {
            document.getElementById(paragraphElementID).innerHTML = header + output;
            output = "";
        }

        function WriteDiscription()
        {
            AddToOutPut("You are in " + currentRoom.name + "<br/><br/>");
            AddToOutPut(currentRoom.discription + "<br/><br/>");
            for (var direction in currentRoom.exits)
            {
                if (currentRoom.exits.hasOwnProperty(direction))
                {
                    AddLinkToOutput(direction + " ", "Go", "'" + direction + "'");
                    if (currentRoom.exits[direction].key)
                    {
                        AddToOutPut("there is a locked exit.<br/>");
                    }
                    else
                    {
                        AddToOutPut("there is an exit.<br/>");
                    }
                }
            }
            for (var x in currentRoom.items)
            {
                if (currentRoom.items.hasOwnProperty(x))
                {
                    AddToOutPut("There is a ");
                    AddLinkToOutput(x, "GetOrDrop", "'" + x + "'");
                    AddToOutPut(" in the room.<br/>");
                }
            }
            AddToOutPut("<br/>");
            for (var itemName in inventory)
            {
                AddToOutPut("You have a ");
                AddLinkToOutput(itemName, "GetOrDrop", "'" + itemName + "'");
                AddToOutPut(" in your inventory.<br/>");
                if (inventory[itemName].listOfUses)
                {
                    AddToOutPut("With it you can:<br/>");
                    for (var useName in inventory[itemName].listOfUses)
                    {
                        if (inventory[itemName].listOfUses.hasOwnProperty(useName))
                        {
                            AddToOutPut("&nbsp&nbsp&nbsp&nbsp&nbsp");
                            AddLinkToOutput(useName, "Use", "'" + itemName + "','" + useName + "'");
                        }
                    }
                }
            }
            WriteStoredLine();
        }

        function Room(name, discription)
        {
            this.name = name;
            this.discription = discription;
            this.actors = {};
            this.items = {};
            this.exits = {};
            this.visits = 0;
            this.events = [];
            rooms[name] = this;
        }

        function Exit(direction, room, targetRoom, key)
        {
            this.direction = direction;
            room.exits[direction] = this;
            this.targetRoom = targetRoom;
            this.key = key;
        }

        function Item(name, container, carryable, listOfUses)
        {
            this.name = name;
            if (container)
            {
                container.items[name] = this;
            }
            else
            {
                inventory[name] = this;
            }
            this.carryable = carryable;
            this.listOfUses = listOfUses;
        }

        function Event(room, action, timesInRoom)
        {
            rooms[room].events.push(this);
            this.action = action;
            this.timesInRoom = timesInRoom;
        }

        function GetOrDrop(item)
        {
            var found = false;
            for (var name in currentRoom.items)
            {
                if (name === item)
                {
                    if (currentRoom.items[name].carryable === true)
                    {
                        inventory[name] = currentRoom.items[name];
                        delete currentRoom.items[name];
                        WriteDiscription();
                        found = true;
                    }
                    else
                    {
                        AddToCurrentText("You can't carry that! It's too big!");
                    }
                }
            }
            if (!found)
            {
                for (var itemName in inventory)
                {
                    if (itemName === item)
                    {
                        currentRoom.items[itemName] = inventory[itemName];
                        delete inventory[itemName];
                        WriteDiscription();
                    }
                }
            }
        }

        function Go(direction)
        {
            for (var i in currentRoom.exits)
            {
                if (currentRoom.exits[i].direction === direction)
                {
                    var door = currentRoom.exits[i];
                    if (!door.key)
                    {
                        if (rooms[door.targetRoom] === currentRoom)
                        {
                            AddToOutPut("You go through the exit and somehow come right back to the room you were just in... Weird...<br/><br/>");
                        }
                        currentRoom = rooms[door.targetRoom];
                        currentRoom.visits += 1;
                        WriteDiscription();
                    }
                    else
                    {
                        for (var x in inventory)
                        {
                            if (x == door.key.name)
                            {
                                door.key = null;
                                currentRoom = rooms[door.targetRoom];
                                currentRoom.visits += 1;
                                WriteDiscription();
                                AddToCurrentText("You unlocked the door with your " + x + " and step through.");
                                break;
                            }
                        }
                        if (door.key)
                        {
                            AddToCurrentText("You can't go that way because it's locked with a " + door.key.name);
                        }
                    }
                    break;
                }
            }
        }

        function Use(nameofitem, nameofuse)
        {
            for (var i in inventory)
            {
                if (i === nameofitem)
                {
                    var tool = inventory[i];
                    for (var z in tool.listOfUses)
                    {
                        if (z === nameofuse)
                        {
                            var func = new Function(tool.listOfUses[z]);
                            func();
                        }
                    }
                }
            }
        }

        function save()
        {
            if (setUp === true)
            {
                var inventoryJSON = jsonizer.stringify(inventory);
                var roomsJSON = jsonizer.stringify(rooms);
                CreateCookie("roomsJSON" + versionNumber, roomsJSON, 50);
                CreateCookie("inventoryJSON" + versionNumber, inventoryJSON, 50);
                CreateCookie("currentRoomName" + versionNumber, currentRoom.name, 50);
                CreateCookie("currentText" + versionNumber, document.getElementById(paragraphElementID).innerHTML, 50);
                CreateCookie("saved" + versionNumber, "saved", 50);
            }
        }

        if (ReadCookie("saved" + versionNumber))
        {
            rooms = jsonizer.parse(ReadCookie("roomsJSON" + versionNumber));
            inventory = jsonizer.parse(ReadCookie("inventoryJSON" + versionNumber));
            currentRoom = rooms[ReadCookie("currentRoomName" + versionNumber)];
            var text = ReadCookie("currentText" + versionNumber);
            text = text.replace(/$/g, "");
            document.getElementById(paragraphElementID).innerHTML = text;
            setUp = true;
        }
        else
        {
            var room1 = new Room("Room1", "A plain room... what else?");
            var room2 = new Room("Room2", "Another plain room... sigh...");
            var room3 = new Room("Room3", "Yet a third plain room... I'll give you a guess what the next one is!");
            var room4 = new Room("Room4", "Yep! Another plain one.");
            var room5 = new Room("Room5", "This is a secret room!!!!");
            var room6 = new Room("Room6", "Congrats! you just got past the first puzzle.");

            currentRoom = room1;
            currentRoom.visits += 1;

            var bouncyBall = new Item("small bouncy ball", room1, true, null);
            var bolder = new Item("large rock", room3, false, null);
            var key = new Item("key", room3, true, null);
            var bombuses = {};
            bombuses["blow up rock"] = "" +
                "for (var i in currentRoom.items)" +
                "{" +
                    "if (currentRoom.items[i].name == 'large rock')" +
                    "{" +
                        "delete currentRoom.items[i];" +
                        "for (var x in inventory) " +
                        "{" +
                            "if (inventory[x].name == 'bomb') " +
                            "{" +
                                "delete inventory[x];" +
                            "}" +
                        "}" +
                        "for(var room in rooms)" +
                        "{" +
                            "if(room == 'Room3')" +
                            "{" +
                                "new Exit('Down', rooms[room], 'Room6', null);" +
                            "}" +
                            "else if(room == 'Room6')" +
                            "{" +
                                "new Exit('Up', rooms[room], 'Room3', null);" +
                            "}" +
                        "}" +
                        "WriteDiscription();" +
                        "AddToOutPut('<br/>You use your bomb to blow up the rock<br/> and it leaves a small opening you can crawl through.');" +
                        "AddToCurrentText(output);" +
                        "output = '';" +
                        "return;" +
                    "}" +
                "}" +
                "AddToCurrentText('<br/>There is nothing to blow up in here...');";
            var bomb = new Item("bomb", room5, true, bombuses);

            var room1exit1 = new Exit("South", room1, "Room2", null);
            var room2exit1 = new Exit("North", room2, "Room1", null);
            var room2exit2 = new Exit("East", room2, "Room3", null);
            var room3exit1 = new Exit("West", room3, "Room2", null);
            var room3exit2 = new Exit("South", room3, "Room4", null);
            var room4exit1 = new Exit("North", room4, "Room3", null);
            var room4exit2 = new Exit("South", room4, "Room5", key);
            var room5exit = new Exit("North", room5, "Room4", null);

            WriteDiscription();
            setUp = true;
        }
    </script>
</body>
</html>

JSAdventure Item Uses and Saving

Posted on May 11, 2010 at 1:30 PM

In this version I have added two major features. First is the ability to create uses for the items. For instance I made a boulder in the previous version that was not carryable. Now with the bomb in the new locked room you can blow up the boulder and reveal an exit leading down to a new room. This was all possible through JavaScript's eval. I take the string which is defined in creation of the item and call eval on it which will parse the string and execute it as though it were just plain JavaScript. I have found this somewhat useful and effective only because it allows my program to be easily extended, though there are some things that you will need to think about before using it every where. First is the fact that all eval code should only be taken from your own program and nowhere else. This is because if you were to gather it from some other source it might be liable to tampering and could cause data loss or some other hap hazard effect. The only places I have found that this was useful was in this case and in json which I have used in this update as well. Here is the code for the uses.

function Use(nameofitem, nameofuse)
{
    for (var i in inventory)
    {
        if (i === nameofitem)
        {
            var tool = inventory[i];
            for (var z in tool.listOfUses)
            {
                if (z === nameofuse)
                {
                    var func = new Function(tool.listOfUses[z]);
                    func();
                }
            }
        }
    }
}

As you can see I try not to have actual references to any of the objects and so I keep the names instead. And using the objects in JavaScript (or associative arrays, they are one in the same) I can access the item or exit or whatever that I need just from the name of the object and it’s container. Then once I have the item I iterate through the objects list of uses to find the one I want and then I execute it. It’s as simple as that, but now if I wanted I could create an admin console or something in c# to generate whatever I’d like and just convert it to json to be used as the map or objects that I can create.

The last thing that I added into this version was the use of cookies for saving state. I searched and searched all over the internet for a good serializer when I realized that it was all right under my nose! json when trying to serialize straight to and from JavaScript on the same client is amazing and it was quite straight forward too. I just take some code to serialize ( borrowed from here ) into json and then just call eval to bring it back.

jsonizer.stringify = function (obj)
{
    var type = typeof (obj);
    if (type !== "object" || obj === null)
    {
        // simple data type
        if (type === "string")
        {
            obj = '"' + obj + '"';
        }
        return String(obj);
    }
    else
    {
        // recurse array or object
        var nameOfElement;
        var v;
        var json = [];
        var isArray = (obj && obj.constructor === Array);
        for (nameOfElement in obj)
        {
            if (obj.hasOwnProperty(nameOfElement))
            {
                v = obj[nameOfElement];
                type = typeof (v);
                if (type === "string")
                {
                    v = '"' + v + '"';
                }
                else if (type === "object" && v !== null)
                {
                    v = jsonizer.stringify(v);
                }
                json.push((isArray ? "" : '"' + nameOfElement + '":') + String(v));
            }
        }
        return (isArray ? "[" : "{") + String(json) + (isArray ? "]" : "}");
    }
};

The code is a little complicated ( I still don’t exactly know all that v does, but I the basic idea is to iterate over all of the properties of the object (or associative array which allows us to for loop over them) and either return a hard coded value, or rinse and repeat on the new object. Then what you get back is all of the literals of the object that you wanted serialized. Then when I want any of it back I just eval the string and I get back the object with all of it’s literals and everything still intact.

Ok, so I lied about that being the very last thing but this one is minor. I was looking for a good source analysis program for JavaScript and stumbled over jslint. At first the site looks like some small side project that somebody just works on in their spare time, but don’t be fooled, it can pack a powerful punch! The premise is that you take your crappy JavaScript code and put it all into jslint and it will yell at you telling you that it’s crappy. It actually found over 1000 problems with my code and I fixed every single one. Now I'm not going to say that my program is perfect ( you have to realize that I started coding in JavaScript last week ) but it sure is a lot better than it was.

So if anyone cares… Here it is!

You do not have javascript enabled, please enable it and try again.

JSAdventure Items

Posted on May 6, 2010 at 1:20 AM

I have now added item support to my text adventure. I will now tentatively do a post a day on it with new features every post. This post is on the items. I made a new function called item which I can then use to create a new object as though it were a constructor like so…

function item(name, container, carryable) { 
    this.name = name;
    this.container = container;
    if (container) {
        this.container.items.push(this);
    }
    else {
        inventory.push(this);
    }
    this.carryable = carryable;
}

This does two main things: First, it allows me to create a new object with the name, container, and carryable properties set on it, and second, it makes it so that I don’t have to add the object to the inventory or list of items in the room because it does it for me. I did this mainly because I’m lazy ( As a side note I had a book that told me that was a good thing in programming. How wrong that was! ) but also because it makes it so that I don’t have to think about that ever again while I am coding. I also have been working on adding locking capabilities to exit and I made it so that some of the items can not be carryable ( is that a word? ) and will display a nice message saying go try again. Later I plan to make a property on item that allows me to assign a function that is executed through a command on items to do other things than just pickup, drop, and unlock doors. Any way if you have any suggestions, please feel free to leave a comment.

You do not have javascript enabled currently. Please enable javascript to play my game.

JavaScript Text Adventure

Posted on May 5, 2010 at 9:00 AM

I am going to start a series on JavaScript. The main reason being that it is the only way for windows users to program for the iphone.

My first project is a text adventure written in JavaScript. My first version (0.1) is going to only include a simple set of rooms and exits and only one command: go. The way that I will set up movement and actions is by links that I make on bolded text in the script. I create code in html from the script that then executes the command with the event “onclick”.

The code is quite simple and since it is in JavaScript, it will also work in my blog! Eventually I will make it so that you can also control the commands through certain key presses, similar to rogue.

Well without further ado… JSAdventure version 0.1