Skip to main content

News

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - Radnen

16
Programming / JS Bind method for your Sphere games
So, while there are bind methods out there that conform to the ECMA standard, they are far too slow for Sphere. I tested them and this is a 5x faster method.

Code: (javascript) [Select]

// check against existing bind, since TS and SSFML have this for you.
if (!Function.prototype.bind) {
Function.prototype.bind = function(owner, arg1, arg2) {
var m = this;
return function(a1, a2) {
m.call(owner, a1 || arg1, a2 || arg2);
};
}
}


Thoughts, comments? I think for simple bound methods this is good. Yes it doesn't do exactly what bind does, but this is Sphere here, not the internet. So, I'm sure most games will play just fine with this.

It's faster for the two reasons:
1. No pesky Array.prototype.splice.call()'s
2. No "arguments" lookup. It's actually faster to hand-write the args right in. (If you need more than 2 args, just add more).
17
Libraries / Link.js v0.4.2
Link.js v0.4.2

GitHub Page: https://github.com/Radnen/link

Link.js is a very fast, lazy executed, query library. Inspired by Lazy.js and LINQ, it aims to make data manipulation easier to write and fast to execute.

Examples:
Code: (javascript) [Select]

// get n'th even number:
var numbers = [0, 1, 2, 3, 4, 5];
var n = Link(numbers).where(function(item) { return item % 2 == 0; }).get(3).toArray(); // returns [4]

// get enemy with lowest health:
var enemies = [{hp: 20}, {hp: 35}, {hp: 15}, {hp: 40}];
var n = Link(enemies).sort(function(a, b) { return a.hp - b.hp; });

// get a person on the map at a location (assume the x, y, and tile function are defined):
var n = Link(GetPersonList()).where(function(name) { return GetPersonTileX(name) == x && GetPersonTileY(name) == y; }).first();

// see if a particular person exists:
var n = Link(GetPersonList()).where(function(name) { return name == "player"; }).length() > 0;


With TypeScript things look a lot closer to LINQ (and more compact!):
Code: (javascript) [Select]

var array = [1, 2, 3, 4, 5, 6, 7, 8];
var evens = Link(array).where(n => n % 2 == 0)->each(n => Print(n));


Have fun writing your queries!

You may need Function.bind(), especially for legacy Sphere versions. For those using minisphere, you don't have to worry.

Code: (javascript) [Select]

Function.prototype.bind = function (self) {
    var args = Array.prototype.slice.call(arguments, 1), func = this;
    return function () {
        return func.apply(self, args.concat(Array.prototype.slice.call(arguments)));
    };
};
18
Resources / [code] Fix for GetPersonList
This following code has been tested and works in any game you put it in. What it does is create a cache of the person list in JS and only ever updates it when an entity dies, or gets created.



How to use:
Just copy and paste it somewhere in your code and the overrides do the rest.
19
Engine Development / Sphere SFML v0.90


Introducing Sphere-SFML
A modern day, Windows only (presently) .NET based Sphere Engine alternative using SFML, aimed to be Sphere standards compliant with over 350 unit tests and under 5,000 LOC.

What do I mean by "Sphere Standards Compliant"? I mean you can take a game from way back in 2003 and still use it in my engine with *no* added changes. You might be able to load games earlier than that, but sphere file formats have changed since then and you might be loading a game that's simply too old. This also means it's for games against the latest Sphere standard (Sphere v1.5/1.6), which coincidentally hasn't changed since around 03'. See Github Sphere Documentation for raw sphere filetype details.

Source Code:
https://github.com/Radnen/sphere-sfml

Sphere Compliance:
**Complete**
- Images: 100%
- Input: 100%
- Sounds: 100%
- Fonts: 100%
- WindowStyles: 100%
- Spritesets: 100%
- Files: 100%
- Networking: 100%

**Incomplete**
- General: 92%
- Persons: 90%
- Surfaces: 69%
- Primitives: 65%
- Map Engine: 60%

Alpha versions:
Latest: http://radnen.tengudev.com/spheresfml/sphere-sfml-0.90.zip
Other: http://radnen.tengudev.com/spheresfml/

Tips and neat additions
1. MapEngine() can take the fps as an optional parameter default = 60.
2. Hashing functions take a boolean as a second variable, that will return a SHA1 instead of an MD5 hash.
3. Along with other interesting Sphere keys, key F2 will automatically double the viewport size (giving you x2 scale).
4. Has a built-in BinaryHeap, use 'new BinaryHeap(func)' in your code to use it.
5. Has an experimental built-in method for serializing JS to XML files (for save-games etc).
20
Libraries / analogue.js
Introducing: analogue.js

Ever used tung's system but found it to be too slow, or that it doesn't work right at times? Well have no fear since this sleek and lightweight alternative has arrived. I call it "analogue". It's a direct code analogue of the entities on the map, that loads persist scripts and can interact with scripts exactly like how persist can.

Source: revision 10


This can be used a a direct replacement of tung's 'persist.js'.

How to use:

You make a script and store it at "../scripts/maps/your_map.js" for the map 'your_map.rmp' in the /maps directory. This logic holds true for maps in subfolders. "/maps/town/inside.rmp" would need a code stored in "/scripts/maps/town/inside.js" to function.

The code for a town looks like this:
Code: (javascript) [Select]
({
    enter: function() {
        /* code to run on entry of a map */
    },

    leave: function() {
        /* code to run on leave */
    },

    leaveNorth: function() {
        /* code to run when you leave north of the map */
        /* also: South, West, and East variants. */
    },

    // people:
    Bob: {
        talk: function() {
            /* code to run when talked to Bob */
        },

        create: function() {
            /* code to run when Bob is created */
        },

        destroy: function() {
            /* code to run when Bob is destroyed */
        },

        generate: function() {
            /* code to run when Bob generates commands */
        },

        touch: function() {
            /* code to run when Bob is touched by the player */
        },
       
    }
})

When you write code in those 'handlers', it'll directly add it to the person on the map. People also persist values, so you can give bob a property and he'll retain it, like if he were talked to and said something different on the first visit:

Code: (javascript) [Select]
    Bob: {
        visited: false,

        talk: function() {
            if (!this.visited) {
                /* do something when he wasn't visited */
            }

            this.visited = true;
        },
    }

In the code above, visiting Bob means he'll do the action in talk once. Have fun and don't shy away with persisting variables!

Alternatively you can reach the world, map, and person scopes by using three passed variables to the function calls:
Code: (javascript) [Select]
({
    event: 21324,  // some event number, or whatever

    Bob: {
        visited: false,

        talk: function(me, map, world) {
            if (!me.visited) {
                me.visited = true;
                /* do something when he wasn't visited. */
            }
            else if (world.majorEvent) {
                /* talk about some major event in the world. */
            }
            else if (map.event == 21324) {
                /* or perhaps something local to just this map. */
            }
        },
    }
})
21
So, for some reason I cannot modify values in a persist object. I set up a store, like this:

Code: (javascript) [Select]

({
    Shop: {
        items: ["item", "item", "item"],

        talk: function() {
            ShowShop(this.items);
        },
    },
});


I then commence to trade and modify the list of items so it reads: ["item", "item", "item", "item"]

Then I do this test on the persist object:

Code: (javascript) [Select]

var world = JSON.stringify(persist.getWorldState());

Debug.alert(persist.getWorldState()[GetCurrentMap()].Shop.items);
Debug.alert(JSON.parse(world)[GetCurrentMap()].Shop.items);


And I get two very different results. The JSON object will only show the original list of items, while the direct source will show all of the items. Because of this issue I can't save modified lists of stuff, and I have no idea why.

I then see inside the persist code this gem:
Code: (javascript) [Select]

    /* Tie an existing object to a prototype. */
    function tieToPrototype(obj, proto)
    {
        var protoTie = function () {};
        protoTie.prototype = proto;
        var newObj = new protoTie();
        for (var p in obj) {
            if (p in proto && typeof proto[p] == 'object')
                newObj[p] = tieToPrototype(obj[p], proto[p]);
            else
                newObj[p] = obj[p];
        }
        return newObj;
    }


And for some reason I think this may be what's interfering. If I can't solve this problem, then persist has sadly, defeated itself for me.

For one, persist will convert all arrays into objects. Ouch!

Furthermore I can't seem to do this:
Code: (javascript) [Select]

persist.map().Shop.new_var = true;


When I go through the JSON motions, the value 'new_var' that I instantiated after the load had been stripped. Despite being added in after the fact, it won't save to file, calling 'toSource()' on the object also won't unveil it in it's list of fields, however if I use the '.new_var' field it's there; it exists. Tung seemed to have removed many idiomatic Javascript features in his persist wrapper. Can someone far brighter than me in this matter help me rewrite his code to not have this behavior?

Furthermore, values if changed produce whacky outputs. When I tack on a 'visited' member, set initially to false. I always get false back from it. Even if I set it to true... unless I'm using it directly within the scope of the person or map, then it seems to work out. I have no idea why this is happening.

Edit:
Wait... It's working EVERYWHERE ELSE but that file of code. WTF?
22
Resources / [code] Simple Random Number Generator
Ever wanted to set your own seed in a random number generator? Ever wanted to see what one looks like? Well have no fear, since this simple piece of code shall show you how it looks like!



The major caveat is that it's a Lehmer Random Number Generator (which I think is what Math.random() uses anyways), which means it cycles a full period multiplier (that is modulus compatible) every (2^31-1)nth time. For most cases it is useful though. The benefit of having this separate is because Math.random() doesn't seem to allow you to set your own seed which is crucial when testing things out or making sure your gameworld is unique from someone else's, and remains the same uniqueness by storing the seed.

It's also useful for anti-cheating. Imagine a chest that has randomized loot. If the seed was selected "at random" (by using the system clock), then each time you reload your game and open that chest something different appears, which could be a good item, and so you could save-farm it for a good item. However, by storing the seed you are no longer picking "at random" anymore and you'll get the same item out of the chest each time. By choosing a different seed per game means different items per game, which means no two games are the same, but two saves of the same game will at least be the same, which is a good property to have to combat "random" cheating.

But, I myself abuse randomness all the time in games. The downside is it can be predictable. In the game Kings Bounty, the turns are based on a saved seed (which is based on the last 'n' turns you did). That means I can load the game, go into a battle and if I do the same moves I expect the same retaliations from the enemy. I can then die, reload, and then restart knowing exactly how they'll retaliate and be ready for it. So there is this downside as well! So case in point, some things need to be truly "random" while other things should not. As a game designer you choose what should and should not be stored as a seed.

There you go guys! I hope I've enlightened you on some things. :)

To use:
Code: (javascript) [Select]

// setup random generator with system-clock time.
var rand1 = new Random();

// setup random generator with fixed seed.
var rand2 = new Random(123456789);


var r = rand1.next(); // exactly the kind of number you get from Math.random()
23
Here are my thoughts:

Looks pretty cool. Smooth graphics. Definitely a step up. Integrated Kinect is interesting , but how does it figure in price-wise? You can watch television with it, but is that an added cost on top of my subscriber? And what happens if I drop cable to use Xbox as the only TV device? Will it even work then? Skype support is certainly interesting. The voice commands are cool, but how effective are they really? The controller looks freaking awesome, it seems they didn't try to reinvent the wheel but just added polish to it instead.

The cloud support is interesting. I like how they want servers to do a lot of offloaded calculations. Trouble is: they claim it's an offline console, but games that must rely on these servers, well, can't be played offline. Blu-ray discs are awesome, we now get huge game sizes. But at what cost? Games must now be installed to the HDD, which is bad since the last time I did that took 30 minutes. Unless it can zip through 40GB's in a minute then it's not worth waiting for the download: picture going to a friends house to play that game. Before you just brought a disc and there it was. Now you'll have to sit through an install screen. What's worse: they may not have internet or a very slow connection.

Xbox is also trying to be many things. If it's not about games then they are going to scatter their audience. Who is their target audience? And if they don't have one I wonder how good it'll sell? Already I'm seeing the other entertainment stuff becoming a little used add-on. I'm skeptical on that front.

I think it's pretty cool. Now what about it's price? That means everything to me right now.
24
Site Comments / Markdown for forum posts
Is it possible to do this with smf? I think the Markdown syntax is the easiest I have ever used when formatting text, primarily because it's just... natural!

I might be asking too much...  :D
25
Editor Development / The Sphere Studio v1.2.1
Sphere Studio
Welcome to my Ultimate Sphere Editor for Microsoft .NET 4.5 Platforms!

Features:

  • Plugins!!

  • Smooth Map Editor

  • All Sphere Formats can be opened and edited

  • Syntax Highlighting

  • Full Sphere 1.6 Code Completion

  • Multiple-folder Game Management Page

  • Dockable Layout

  • Mirror Drawing Image Editor

  • Sphere JS debugger! (currently minisphere has the only support)

  • Project build tool

  • Project settings & user settings

  • ...And lots more!



Links
Website: http://radnen.tengudev.com/editor.html
Download: https://github.com/Radnen/spherestudio/releases/tag/1.2.1
Github: https://github.com/Radnen/spherestudio
26
Off-Topic Discussions / Radnen's Hub
Hey guys, I've made myself a home for my Sphere games - finally! It's at my space on tengudev, you can visit it here: http://radnen.tengudev.com

So, for now on I'll be updating that website whenever I make or do something new. You'll find all of the downloads and other latest pieces of news of my projects there.

Have fun browsing!
27
Resources / [code] Object Serialization
This piece of code is from my radlib library, but I'm putting it here because others might benefit from having this in their game, whether or not they want the full RadLib library.

These two functions, Serialize and Deserialize will store/recall JS objects, restoring their prototypes and non-serializable sphere objects. In Serialize, a new property is tacked on to an object: "zztype", it stores the constructor of the object that created it. Deserialize will call that constructor and then proceed to fill in the stored fields. The reason for this is twofold, one, when the object is re-created it becomes an object of the type of it's constructor rather than 'object' (JSON stringify/parse will turn all objects into general JS objects and strip the methods off of them), two, any sphere objects such as images will be reattached since usually they are created in the constructor function and since they are only used for display: we don't tend to store images/fonts/windowstyles, so they don't have to be saved.

Both Serialize and Deserialize do a deep inspection/clone, so nested objects are also affected.

Code: (javascript) [Select]

/**
* Serialize(obj : object);
*  - Use this to JSON an object; AND preserve the data type.
**/
function Serialize(obj)
{
function Make(obj) {
var o = { zztype: obj.constructor.name };
for (var i in obj) {
if (!(obj[i] instanceof Array) && typeof obj[i] == "object")
o[i] = Make(obj[i]);
else
o[i] = obj[i];
}
return o;
}

return JSON.stringify(Make(obj));
}

/**
* Deserialize(s : string);
*  - Use this to parse a JSON object; AND restore the methods.
**/
function Deserialize(s)
{
function Make(o) {
var obj = new this[o.zztype]();
for (var i in o) {
if (!(o[i] instanceof Array) && o[i] typeof "object")
obj[i] = Make(o[i]);
else
obj[i] = o[i];
}
delete obj.zztype;
return obj;
}

return Make(JSON.parse(s));
}


Therefore, you can now make a class like so:

Code: (javascript) [Select]

function Item() {
  this.image = LoadImage("dagger.png"); // an image... which can't be saved to file...
  this.damage = 5; // this however can; even with JSON.
}

// but this method will be stripped during JSON creation
Item.prototype.swing = function() {
  Print("Did " + this.damage + " damage!");
}

var item = new Item();
item.damage += 2; // I upgraded it!!

// serialization keeps an object, well the same object!
var s = Serialize(item);
File.save("item", s); // now I saved it to file!

var o = File.recall("item", "");
item = Deserialize(o);

item.swing(); // prints "Did 7 damage!"
item instanceof Item // returns true


This is great for games where the inventory changes and the items must each be saved. Or other properties such as player stats, and world variables, etc. Have fun!

(edited for proper highlighting ~neo)
28
Libraries / RadLib
Hey guys, I'm going to introduce you to a new a powerful game creation library for sphere called radlib!



What is it?
RadLib is a library intended to aid the development of Sphere games. I looked at the most common pieces of code between all of my game projects and developed a library that I could use to have instant access to those features.

What's in it?
Everything! You have various distinct classes:

Assert: To check code statements, tests.
Audio: To play sounds, music.
Color: Various colors.
Debug: To log messages; display errors.
Game: To wrap update/render scripts of map engine.
Input: Keyboard and Joystick interface.
Lib: General Library values
Mouse: Mouse interface.
Resources: Manager of game resources.
StateManager: Game state manager.

Plus many, many other classes and features.

Where can I get it?
You can check out the bleeding-edge version at github here: https://github.com/Radnen/radlib

No official version has been announced, but it will likely release as several different versions:
- Release: JsMin version of the source; no help provided.
- Development: Full code, not JSMin'd, and all comments available.
- RadGui: As a separate release from the core package
- Full suite: Core library with all sub-libraries, such as RadGui
29
Site Comments / What about botters?
Are we protected from bot accounts? Already we have one: http://forums.spheredev.org/index.php?action=profile;u=7

I'm just curious. Now that N E O (neologix) is an admin, I'm sure everything he wanted to do to combat such attempts can now be done. I hope, that is.