Home
30 April 2007 @ 06:32 pm
The Client Object, updated  
While typing up code and compiling the basic framework of things, I've developed the Client object a bit:

class Client {
	mID clientID;   // a unique identifier for the client
	ClientConn	conn;   // used for communicating with the server
	ClientModule	clientModule;   // the game data used by the server
	DisplayDevice	dDev;
	SoundDevice sDev;
	List	ClientThings;   // a list of ClientThings
	List    Gadgets;    // a list of displayed gadgets
	List    ClientMaps;       // a list of the ClientMaps for this game
	ClientMap*  currentMap; // the current map
	public:
// the usual stuff
	Client(HWND,char*);
	~Client();
// these are called by the OS-specific I/O handling code
	void    LeftClick(unsigned int, unsigned int,unsigned int);
	void    RightClick(unsigned int, unsigned int, unsigned int);
	void    LeftRelease(unsigned int, unsigned int, unsigned int);
	void    RightRelease(unsigned int, unsigned int, unsigned int);
	void    MouseMove(unsigned int, unsigned int, unsigned int);
	void    KeyPress(unsigned int);
	void    KeyRelease(unsigned int);
//	void	findServer();
//	void    passData();
//	void    getData();
	void    draw();
};


As you can see, the mouse and keyboard member objects have been replaced with member functions that will be called by the OS-specific code (which will be kept in as small a set of OS-specific files as possible to maximize portability).

mID is an unsigned long integer, used for holding identifiers. Each Client will need an identifier (clientID) so that Servers can tell which client is which.

ClientConn is the way I'll be encapsulating OS-specific socket communications. conn is the instance of this class in the Client object.

ClientModule is a class for holding the data that the Client uses, and clientModule is the instance in the Client object.

The three List objects are for holding all of the objects, maps, and gadgets that the Client creates.
 
 
20 April 2007 @ 10:23 pm
The Client Object  
The game will operate in a client-server way, even when in single-player mode, so the client will be an important part of the engine's architecture:

class Client {
    Module usedModule;
    DisplayDevice dDev;
    SoundDevice sDev;
    KeyboardDevice kDev;
    MouseDevice mDev;
    Game activeGame;
    Conn conn;
    public:
    Client();
    ~Client();
    void go();
};


usedModule is an instance of the Module object which contains all of the date that is peculiar to a specific game (graphics, sounds, scripts).

dDev, sDev, kDev, and mDev are objects which perform the various IO functions. Among other things, I will use them to encapsulate the system-specifc stuff so that as much of the engine as possible can be written in code that will run under Windows, Mac, or Linux.

activeGame is an instance of the Game object, which holds all of the client data that is specific to a single playing of a Game.

conn is the instance of the Conn class, which handles client-server communcations.

What I envision at the start of the client application is that if it is not supplied with a module file in the command line, then it will require the user to select a module file at start-up. Then it will load the specified module, create the various IO objects, and then run the first script in the loaded module. When that script exits, the Client object will be destroyed, and the application will exit.

Obviously, this first script must display the splash screen, then the main menu, and then run other scripts depending on the menu choices made. So it would look like this:

Client::Client(char* fileName) : usedModule(fileName) { }

void Client::go() {
    usedModule.runScript(FIRST_SCRIPT);
}


Or something like this.
 
 
22 October 2006 @ 08:17 pm
 
I did a lot of code layout stuff. Most of it was in the top-level organization sort of thing. One of the first things I did was to establish the division of labor between the client and the server. Basically, I am writing this as a network game, and will support single-player by having the client start up a server when user chooses a single-player game.

Right now I have the following C++ classes declared:

  • Link: This is my class for items that are in a doubly-linked list. I'd have used one of the standard C++ containers, but I always get too much bloat in the executable when I do that. It will probably look like this:

    class Link {
    	class Link *Next;
    	class Link *Prev;
    	Link();
    	~Link();
    	void remove();
    	Link *next();
    	Link *prev();
    };
    


  • List: This is a class for keeping a bunch of Links in line. It looks like this:


    class List {
    	class Link Head;
    	class Link Tail;
    	List();
    	~List();
    	class Link* first();
    	class Link* last();
    	void addHead(Link&);
    	void addTail(Link&);
    };
    


  • Anim: This class is the base class for handling the display of various things that are in the game, except for the land surface. It will handle monsters, missiles, treasure boxes, loot, doors, walls, NPCs, and just about anything else that has a visual presence on the screen. It will (through the items it manages) handle every direction faced by the item, and every frame of its posing during its passage through a given state. It will probably look like this:


    class Anim : public Link {
    	TAG	tag;
    	List	Poses;
    };
    


    Not much to it, eh?

  • The Pose class handles a bit more detail:

    class Pose : public Link {
    	TAG	state;
    	USHORT	frames;
    	USHORT	dirs;
    	
    };
    


    Anim is sub-classed:

    • Anim1: This class implements sprite-based graphic objects.
    • Anim2: This class implements polygon-based graphics obects.


  • Thing: This is the class which handles an instance of an entity of some type in the game.

    The difference between Anim and Thing is that Anim describes how a type of object will be displayed in the game, whereas the Thing class tracks each such object, and in addition to the information required for display, each Thing object will also have other user-defined data (such as health points, possessions, etc.). For instance, if the player is facing three skeletons, there will be one Anim object to determine how the skeleton is drawn, and three Thing objects to track the location and health of each skeleton. At the moment class Thing is sub-classed to:

    • ClientThing: The client-side version of Thing. It has extra members for that data that only the client-side needs.
    • ServerThing: The server-side version of Thing. It has a member which keeps track of the extra data that the mod designers put into the scripts. It will have a subclass:

      • Player: This differs from the ServerThing object in that it has a reference to the client which is passing all of the input to the server; the interpretation of this input stands in place of the AI for that ServerThing.



  • Conn: This is my class for handling the socket communcations. It is sub-classed:


    • Client: This is the object that handles things from the player's perspective. So far it has a list of the things that are to be displayed, as well as the gadgets and a specfication of which Map to draw.




  • Packet: This is the class which holds the data that is passed between the client and the server. There is a sub-class for the client-generated messages and another for the server-generated messages.




  • Gadget: Named after the same object from my old Amiga programming days, the Gadget does for Midge what controls do for Windows. It will have many of the features of Windows controls, such as being active or inactive, and each control can have scripts for mouse rollover, mouse click, and mouse release. At the moment it is a virtual class which I expect to sub-class to:

    • Button: A gadget which reacts to the mouse, either from mouse rollover, mouse click, and mouse release. Depending on the behavior specified, the object can be either static, a checkbox, a push button, or other wonderful things.
    • Edit box: This is for taking text input. I expect to subclass it as:

      • Number box: This is for entering numbers.
      • Address box: This is for entering IP addresses.
      • Password box: This is for entering passwords.


  • Game: This is the server-side object for a game that has been started by some client out there, and which other clients may have joined.

  • Tile: This is a small square of the game surface, and is one game distance unit in size. It is merely the coloring for that part of the land surface. I suppose that some of these could be animated in order to represent running water, lava, etc. There will also be a passability flag.

  • Section: This is an object designed for the automated generation of Maps. It consists of a array of references to one or more tiles, and optionally includes specifications for other objects to rest on the surface when a Map is generated using this Section. This enables Maps to be built from sections that are designed to be joined together.

  • Map: A map represents one of the areas in which action can take place. It is built from a script that is devised by the module designer. The Map object itself is merely an array of references to Tiles. The objects that are part of the play area are simply Thing objects, and are maintained in the list for the Game.

  • Generator: This is the object which handles map generation. It has a field to specify the ID of the map that it generates, and a set of instructions for building the map, including references to Section objects, and creation of the Things that are placed in the Map at the time of generation.

  • Module: A given package of graphics, sounds, and scripts which together create a game. It will be subclassed into ClientModule and ServerModule, each of which use different portions of the Module. At the moment I only plan to give them different constructors.

  • Script: This is where the soft-coded behavior (mod designer supplied) behavior of the game is implemented. The Script object itself will be nothing more than an array of script instructions, which will be compiled from the scripts supplied by the mod designer and in turn interpreted by the game engine as needed.

  • Sound: The object for producing various sounds at various times.

  • Music: The object for playing various sounds over time.
    </ul>

  • Server: This object handles the internal logic of the game; just about everything except user-interface functions. I hope that one server will be able to handle multiple games using multiple clients and multiple modules. The server has no need for the graphic or sound data, and therefore will not load it when loading a module (only the scripts and other data that drives the game mechanics).

  • Display: This is the class which will encapsulate all of the graphic work.

  • List: This is the header for the doubly-linked lists.

  • Property: This is a class that handles user-defined data for Things in the game. As matters stand, Things will have an index for the Anim they use, a field for their state, another field for the frame number within that state, a value to indicate the map in which the Thing presently is, and another two coordinates for the location of the Thing within that map. All other values, such as health points, AI settings, flags for being cursed, and so on, are needed for some items (and some modules) and not for others, so I left all of them as extensions for the mod designer. The Property class allows the mod designer to extend the data within a Thing as needed. Each Property object contains a pointer to the next Property object in the list, a field for the id of the specific setting, a member to indicate whether the setting is an integer, a floating-point value, or a string, and another member for the data itself.

    On the scripting side of thing, I will need to define a script file format for the menus. These will consist of a background graphic, a set of gadgets, and a script to go with each gadget. I imagine that some of these scripts will do nothing more than open another menu.
    </ul>

    I suppose that not defining a background graphic for a menu will direct that the existing graphics are to be used, which gives me the ability to define in-game menus (the kind that appear in D2 when the player hits the Esc key).

    Program flow

    Some of the flow ideas:

    • If the client-side application is started up without a module specified in the command line, the app searches for a list of modules and asks the user to select one.
    • Once the application has a module, it reads the data from the module that is required by the client side and then proceeds to the top-level menu for that module.
    • More about this later...
  •  
     
    17 June 2006 @ 12:04 am
    Portability  
    As I said early in the blog, portability will be a primary focus of this application. Yeah, Java is supposed to be platform-independent, but I'm not sure that Java delivers the speed that a game will need.

    But to maximize portability, all I have to do is ensure that everything platform-dependent is implemented in the smallest number of source files, and group them accordingly:

  • Client-server communications will be implemented in one object (or set of related classes), which will have its platform-dependent source all in one file.

  • I chose OpenGL because every platform supports it. All the OpenGL-specific stuff can go into the source files which control objects getting drawn.

  • Sound will be handled the same way.

  • Mouse and keyboard I/O will also be encapsulated.
  •  
     
    14 June 2006 @ 06:14 pm
    You won't believe this...  
    But here's some real code!

    class Link {
        Link*   n;
        Link*   p;
        public:
        Link();
        Link*   next();
        Link*   prev();
        void    remove();
        ~Link();
        friend class List;
    };
    
    Link::Link() { n=p=(Link*)0; }
    
    Link::~Link() {
        remove();
    }
    
    void Link::remove() {
        if(n) n->p=p;
        if(p) p->n=n;
        n=p=(Link*)0;
    }
    
    Link*   Link::next() {
        if(n==0) return 0;
        if(n->n==0) return 0;
        return n;
    }
    
    Link*   Link::prev() {
        if(p==0) return 0;
        if(p->p==0) return 0;
        return p;
    }
    
    class List {
        Link    Head;
        Link    Tail;
        public:
        List();
        Link*   first();
        Link*   last();
        void    addHead(Link*);
        void    addTail(Link*);
        bool    isEmpty();
    };
    
    List::List () {
        Head.n=&Tail;
        Tail.p=&Head;
        Head.p=Tail.n=(Link*)0;
    }
    
    Link*   List::first() {
        return Head.next();
    }
    
    Link*   List::last() {
        return Tail.prev();
    }
    
    void    List::addHead(Link* l) {
        l->p=&Head;
        l->n=Head.n;
        Head.n=l;
        l->n->p=l;
    }
    
    void    List::addTail(Link* l) {
        l->n=&Tail;
        l->p=Tail.p;
        Tail.p=l;
        l->p->n=l;
    }
    
    bool    List::isEmpty() {
        return (first()==(Link*)0);
    }
    


    This is just my standard code for managing a doubly-linked list.

    "But why aren't you using C++ Standard Containers?"

    Because I don't feel like it.
     
     
    14 June 2006 @ 06:10 pm
    Multiuser II  
    Another reason for this client-server model is the ability to ensure platform portability by dumping the nuts and bolts of the communications onto the Conn object, so that the rest of the code is shielded from it.

    Basically, all the machine-specific coding for the client-server communications will be in the implementation file for the Conn class, so that—hopefully—porting will consist of changing just that one file.

    And today I learned that to get the client and server talking, I need to learn about socket programming. Finding out that it was called socket programming took quite a bit of time on search.msn.com .
     
     
    14 June 2006 @ 05:37 pm
    Multiuser  
    I have an idea of how I'll implement multiplayer options. What I'll do is to define a class to handle server stuff, another class to handle client stuff, and a third class to handle communication between the client and the server.

    This third class can be a simple pass-through during the time that this is a single-player game, when the client and server exists in the same machine (and in the same application); later I can modify the connector class to handle network communications when real multi-player becomes a feature. I don't expect the modifications to be extreme when that happens.

    One issue with multiplayer games is the need to ensure that all players are using the same data module. This can be accomplished by having the client take a checksum of the data module, passing the resultant value to the server, which compares it to what it gets from its own copy of the module.

    My checksum technique will be to treat the whole module bytestream as if it were one humongous integer, divide that integer by a set of prime numbers between 32771 and 65521 (the primes that are 16-bit unsigned integers), and return the remainders for each divisor. If I select four of these primes, then the checksum reduces the chances of mismatched modules to less than one in a quintillion. Which ought to be good enough.
     
     
    20 March 2006 @ 11:39 pm
    Multiplay  
    I have no idea how I'm going to implement multiplayers in one game yet.
     
     
    20 March 2006 @ 10:51 pm
    Definition for anim1  
    I changed my mind on the definition of the anim1 object (sprite-style object graphics).

    anim_id anim1 { // data for a single animation object
      height;
      width;
      pose {
        state_id,direction_count,frame_count;
        body: filepath;
        // additional body entries
        head: filepath,x_offset,y_offset;
        // additional head entries
        larm: filepath,x_offset,y_offset;
        // additional left arm entries
        rarm: filepath,x_offset,y_offset;
        // additional right arm entries
      }
      // additional pose entries
    }
    


    height is the height of the object in 65536ths of world units.

    width is the width of the object in 65536ths of world units.

    Within each anim1 object there is a set of poses. Each pose object controls the appearance of the anim when it is in a given state. Most monsters will have a state for standing still, for walking, perhaps for running, for attacking (and likely a different one for each kind of attack), perhaps one for reacting from being injured, and probably one for dying. A crafty designer could have monsters that play dead...

    state_id is the state id corresponding to this pose, meaning that every object using this anim will use this pose when in this state.

    direction_count specifies the number of different directions the object can appear to face in the given state. Directions will actually be in 65536ths of a full circle (or maybe 256ths, that's not defined yet), and moving objects will move along their actual angles; the directions here are for display purposes.

    frame_count specifies the number of frames for this state.

    body: The body entry states that the body of the anim will be taken from an icon sheet in the file specified by filepath. The picture is divided into direction_count rows and frame_count columns. There can be more than one body setting; the specific one will be chosen for each unit randomly when it is generated in the game. This way skeletons can appear to have remnants of different kinds of armor, for instance. The body icons should be a consistent size from one pose to the next in the same anim so that they are all resized in the same way for display; the width and height settings at the top of the anim specify the size of the body icons.

    head, larm, and rarm: These entries state that extra graphics will be added to the body before it is displayed for each unit. There can be multiple entries with the head tag; doing so will allow the engine to generate creatures with different heads. larm and rarm will work the same way. Note that the head, larm, and rarm tags are arbitrary to some extent; if the actual graphics for the head of the creature are put into larm entries, the engine won't care. I suppose I could design the engine so that any tag but body will be taken to be an overlay, and that matching tags will be taken to represent different options for the same overlay. The offset entries are in pixels, and indicate that the icon graphics are adjusted horizontally and/or vertically before being laid over the body graphic for the object. This offset allows overlay icons to be smaller than the body icons.

    It should be apparent that the graphic files will require an alpha channel.

    State ids will be defined by the mod designer. If the creature enters a state for which there is no defined pose, the creature will not be displayed while in that state (which may be what the designer wants).

    At some point I will define the anim2 object for 3d modeled object graphics. The main difference is that the direction settings will be unnecessary, because the same 3d model can be made to face any direction and still look okay, whereas sprites essentially need a different graphic for each direction that the object appears to face. The overlays will not need the offsets either, since the precise placement of the heads and arms will be inherent in the model definition. To be pendatic, they won't really be overlaid; they will simply be extra geometry, to be rendered in the same way as the body.

    The idea behind icon sheets is that the designer can draw or render the figure in as many steps and directions as necessary, and bundle all of the separate pictures into one file; this saves a bit on the complexity of the module distribution.

    I'll need some way to define palette shifting, if I decide to implement that in the engine.
     
     
    24 February 2006 @ 07:50 pm
    Entity event functions  
    It turns out that the AI for a given creature can be implemented in only a handful of different calls. Therefore I can make things look like this:

    ai_label ai {
        onTick() { /* code to decide what happens at each clock tick */ }
        onAttack(attack) { /* code to decide the result of any attack */ }
        onMeet(intruder) { /* code to decide the result when another
                              object intrudes on this one */ }
    }
    


    I hope I can keep things this simple.
     
     
    23 February 2006 @ 09:28 pm
    Event driving  
    I'll probably go with an event-driven system of some sort. A modder would define an arrow, for instance, in this way:

    miss_arrow missile {
      use_anim arrow;
      onTick() { location+=direction*velocity; }
      onStrike() { /* code to govern behavior when striking another object */ }
    }
    


    The modder would have to write code to specify what happens in onTick() and onStrike().

    Now I will probably pre-compile such code to improve execution speed; is it worth the trouble to do all of this stuff in Java and have modders distribute Java bytecode?
     
     
    16 February 2006 @ 10:51 pm
    Overlay graphics, buttons, etc.  
    While thinking things over at work, and remembering how D2 works, I recognize that there needs to be a way for the modder to specify screen-level overlays and buttons (things to click on to do this or that). The main menu for D2 has both: A screen-sized graphic and a set of buttons.

    I don't see this being very hard. I suppose that the buttons will need to have onClick() and onRollover() functions...
     
     
    24 January 2006 @ 10:40 pm
    The anim data type  
    A major data type will be for graphically representing different objects, and I'll call it the anim, for lack of a better name.

        anim_id anim1 {
            basic {
                state_id: filepath,frames,directions,width,height ;
                state_id: filepath,frames,directions,width,height ;
                .
                .
                .
            }
        }
    


  • anim_id is a label representing the graphical data for one given creature/object type.
  • anim1 merely says what type of data this is. In this case, this is a sprite-based graphic.
  • basic introduces a block of data for the basic graphical representation, meaning that there are no palette shifts or overlays.
  • state_id, with a colon, introduces information for one of the states of the anim. state_id is a label for one of several states in which the object can be.
  • filepath is the filepath for the graphic file which contains the image data. It will be one of the formats which supports an alpha channel.
  • frames states how many frames are in the anim.
  • directions states how many different directions the anim can face.
  • width is the width of the anim, in 256ths of a meter (the unit of measurement in the game world).
  • height is the height of the anim, in 256ths of a meter.
  • And each state_id line entry ends with a semicolon.

    All of the icons for a given state will be kept in an icon sheet, which will be a single graphic file containing several smaller pictures. There will be frames rows of directions columns of smaller icons within the overall picture. This way the movement of a given monster in a given state can be edited in one file.

    This descriptor allows me a great deal of flexibility; I can model a monster state with twenty frames, in which the monster can face 16 different directions, or I can model a treasure chest which has only one frame and one direction. I can also, like in DOOM, have monsters which have more directions for one state that for another.

    The engine will at some point have the anim_id, the state_id, the frame, the direction, and the location of the object to be displayed (as determined by the game logic). It will use these data to figure out which icon sheet to use (from the object type and its state), which column (direction) and row (frame) to use from the icon sheet, and where to put it (from the location).

    I will probably allow cascading data, so that an anim block for, say, the skeleton can be supplemented, overridden, or partially overridden by subsequent anim blocks using the same anim_id.

    D2 has a feature in which monsters of the same kind are made to look slightly different by use of overlays, which enable Zealots of have different weapons from each other; I'll probably add a data field to support overlays (or individual pieces of a figure). But that's a later issue.

    D2 also has a palette shifting feature, so that the same monster can have different colors. That will be tackled later, when the basic type is working right.
  •  
     
    20 January 2006 @ 07:03 pm
    Program loading  
    I came up with a lot of ideas while I was scribbling today.

    Resource files
    I've decided that the command line for the engine will have a parameter which specifies the data files to be used.

    The data file will be created by a special utility which will take human-readable text files and turn them into something that can be loaded quickly and easily. This utility will be packaged with the engine.

    Sounds like resource files, eh? That's the idea. That way mod makers can package all of their data into one big schmoo and pass the results around.

    Splash screens
    Diablo has them—most if not all games do, in fact—and so I'll be supporting those as well.

    And characters
    While scribbling, I've decided to support both DOOM-style monster graphics (sprite-based) and Quake-style (3d model) graphics, and allow both types to be mixed in the game. The trade-off between the two is pretty clear; sprite graphics require a lot of data, but slapping them on the screen requires only one polygon to be processed, while 3d models require very little data, but can involved a few dozen polygons per figure. I'll probably implement the sprite-based ones first.
     
     
    19 January 2006 @ 11:53 pm
    Damage Types  
    I have decided that damage types will be implemented from TXT files.

    The designer can therefore implement as many damage types as he/she wishes, to include:

  • Blunt damage: Caused to flesh by blunt instruments. In Dunegons and Dragons (D&D), some creatures were invulnerable to blunt weapons.
  • Sharp damage: Caused to flesh by sharp instruments. In D&D, some creatures (skeletons) took only half damage frome edged weapons.
  • Fire damage: Caused by you-know-what. Traditionally, undead suffer more from fire than other creatures, although Diablo didn't implement this.
  • Cold damage: Another elemental type from Diablo II. In D&D, undead were completely immune to cold damage.
  • Lightning damage: Another elemental type from Diablo II.
  • Poison damage: In Diablo, this caused damage over time. In D&D, poison either didn't do anything or it had some immediate catastrophic effect (such as making the victim instantly die).
  • Acid damage: This was kind of in Diablo I.
  • Magic damage: Somehow, the magic directly destroys bodily tissues.
  • Holy damage: Caused by shafts of holy light, or whatever. Demons and undead would be more vulnerable to this.
  • Unholy damage: Caused by shafts of unholy darkness.
  • And so on.

    The designer could, as is done in D2, bundle the first two types together, and the magic/holy/unholy damage together, and skip the acid damage, or he/she could implement all ten types. On the other hand, the designer could implement red damage, blue damage, and green damage, all with completely aribitrary meaning and no necessary relationship to any known physical world.

    I do this because (a) people have complained about D2 not having as nice a damage system as other games, and (b) if I make it a data-driven item, I don't have to take blame for settling on a system only I like.

    Obviously the engine needs to keep track of each monster's (and player's) resistance to the various damage types. I don't know whether to support tracking how much of a creature's damage was taken from which damage type; in D&D, trolls regenerated damage done by ordinary weapons, but damage done by fire did not regenerate. Of course, that could be implemented by having some damage types lower the creature's HP max by the amount done to the current HP, so that regeneration would not restore the loss.

    But it would be a simple thing in the txt file for part of a monster's record to look like this:


    skeleton { poison: immune; cold: immune; fire: +50%; holy: +100%,noheal; unholy: -150%; sharp: -50% }



    This means that skeletons would be immune to cold and poison, take an extra half damage from fire, take double damage from holy shafts of light (which could not be healed), be healed by shafts of unholy darkness, and take only half damage from sharp instruments. Damage from acid, lightning, magic, and blunt weapons would be applied normally.

    And so on for other creatures.
  •  
     
    18 January 2006 @ 09:15 pm
    Concepts for the Engine  
    There are some concepts that need to be implemented:

    States
    A time-honored computing concept, most of the objects will have states, which control how the object is displayed and what it will do next. In my implementation, each state will include a frame count, which is a simple number indicating how many animation frames the object has been in that state. If nothing forces the object into a different state, then with each animation frame, all objects' frame counts will increment by one. If a state loops, then after so many frames in a given state, the frame counter will be reset to the starting value.

    In the display logic, the object ID, plus the state, plus the frame count, will together determine the pose that the object is in. Poses, combined with directions, determine the specific graphic to be displayed for the object. This is how I plan to implement animation.

    Scripts
    In order to allow quest and AI design via TXT files, I will need a scripting language. I will probably use RPN expressions because that's the simplest to implement. Scripts will control:
  • All AI
  • Quests
  • The behavior of interactive scenery (mainly to switch between different scenery choices).

    Plot coupons
    Internally, plot coupons will be integer type variables (probably an unsigned short) which record what events have happened in the game. The game object will keep a list of coupons that have been added or removed. For game designer reference, I will have a TXT file which has symbols for the plot coupons, and a descriptive line explaining what each one entails. The TXT file may contain this entry:

     kingkilled has the king been killed;
    

    In the scripts, the label kingkilled reads as true if the king has been killed, and false if the king has not been killed. The rest of the line in the reference file (up to the trailing semicolon) is ignored.

    Update:

    I've decided that the text entry for a plot-coupon will look like this:

     kingkilled plot_coupon { /*data peculiar to this plot coupon */ }
    


    Landscape tiles
    The landscapes will be built from tiles, which are small sections of landscaping that can be connected into larger sections. Each tile will have typing for its edges, such that no two tiles can be joined along their edges unless the types match. This will allow maps to be built in a pseudorandom fashion but still look natural.

    The basic graphic elements will be in graphic files, but the tiles themselves will be defined in txt files, containing the following specs (in some format):

  • The surface graphic for each piece of the tile
  • The scenery (if any) that rests on each piece of the tile
  • Any objects (loot, monsters, interactive scenery) that is placed in the tile when the map is built
  • The edge typing to control the joining of tiles

    Maps
    Maps are areas in which gameplay takes place. Maps will be defined in a TXT file which specifies:

  • The number of tiles (see above) to use in the map, and which ones to use
  • Any additional loot, monsters, and/or interactive scenery that is place in the map

    For a randomly-generated map, the program will select X tiles from a specified group of tiles and piece them together according to the map design logic. For a preset map, the tiles will simply be designed so that only one possible map can result.
  •  
     
    18 January 2006 @ 08:53 pm
    Things in the Engine  
    My note-scribbling tells me that I need to have the following kinds of things in the game, to be implemented in roughly this order:

    Landscape
    Also known as the flat part that the player walks on. In Diablo II, the landscape is generally safe to walk on; the times when it is dangerous are generally temporary situations (poison gas, fire, etc) created by an object that actually rests above the surface. I might support things like hot coals, ice, and/or mud (the last of which was in early D2 tests but which was taken out).

    Scenery
    There will be lots of buildings, cave walls, trees, and so forth. These things do nothing more than block the player's progress, or always do the same thing when the player walks through them.

    Beings
    The player(s), NPCs, monsters, hirelings, minions, and other things that have life and complicated AI.

    Missiles
    Things that fly or move based on simple AI, but which have no life and which generally vanish after a predetermined period of time. This includes poison clouds, arrows, bolts of lightning, fireballs, acid spitwads, shafts of holy light or unholy darkness, and so forth.

    Loot
    The things on the ground that the player(s) can pick up. This includes money, weapons, potions, magic items, and so on.

    Interactive Scenery
    This is the kind of scenery with which the player interacts. This includes doors, levers, magic statues, and so forth. I definitely intend to support doors which are locked and can be unlocked in some way. I would also like to support traps (and traps of the bang-you're-dead variety if someone wants to implement such).

    Everything in the game can be categorized as one of these six things.
     
     
    15 January 2006 @ 02:19 pm
    Decisions 2  
    In my notes I have a few design decisions already made.

    First
    I will not try to simulate a real world too closely. Specifically, I will not be trying to model action on the surface of a large sphere, but instead will be using—like Diablo II—a set of flat sections that are linked together. I don't see this being a problem for anybody.

    Second
    The basic spatial unit will be the meter. Internally, this will be represented in signed long integers (32-bit), scaled by 65536. The high word will be the whole part, and the lower word will be the fractional part. This allows a high degree of precision in movements (which the modder need not fully implement), and also allows each map to be 65km by 65km, which is more room than any single RPG map.

    Third
    The graphics for each creature will be sprite-based, meaning that they are simply flat images that are slapped onto the screen. Each creature will have a set of poses (different positions for the arms, legs, head, etc). Each pose will in turn have a separate figure for each direction the creature can face (N, S, E, W, NW, NE, SW, SE, NNE, NNW, SSE, SSW, ENE, ESE, WNW, WSW, etc). Each figure will have portions that are color-shifted (to provide variety), and overlays so that the monsters can have different heads, arms, and such. Sound complicated enough yet?

    The pictures will be kept in graphic files (format to be determined), and the way they come together to form a character will be set up in a TXT file.
     
     
    15 January 2006 @ 01:53 pm
    Decisions  
    In the notes I've made so far, I've come up with a few implementation decisions:

    OpenGL for rendering
    The reasons for this are (a) OpenGL exists on multiple platforms, so that this whole project can easily be ported to Linux or Mac, and (b) OpenGL is easier (for me) than DirectX.

    This decision is still open to later review, if I find that DirectX is very helpful (it does more than graphics so this may be). Many game companies use it, so there may be something there.

    High levels of data-driving
    One of the reasons that modding Diablo II has become so popular is because much of the game resides in data files that are easily modified. For instance, editing one file enabled me to take the chickens from Act I, the rabbits from Act V, and add them to Act IV so that the Underworld is now populated with rabbits and chickens. Gotta feed those demons.

    But I am interested in hard-coding (C/C++) only the barest essentials of the game engine, and leaving as much as possible to data files, to the point that all of the player characters, NPCs, monsters, items, and quests can be replaced with an entirely different set of stuff.

    Isometric view
    Part of the Diablo look-and-feel is the isometric view. I'd like to add the ability to rotate the view (some D2 combats are blocked from the player's view by walls). I intend to keep the projective feel of D2 in place (things that are closer appear larger on-screen). If performance issues allow, I'll make it possible to turn the whole thing into a first-person-shooter (aka Doom/Quake clone) by means of the data files, but if performance does not allow, the game will be a D2-style game.

    And the name of this project is
    My Isometric Display Game Engine (MIDGE), which may be prescient of the annoyances I suffer as I work on this.
     
     
    15 January 2006 @ 01:39 pm
    Starting  
    This marks my first entry in my game development blog.

    If you came here looking for my political content, I am afraid that you must go away disappointed; I've deleted it all for a project.

    Some background info:

    My wife got Diablo II for me about three years ago. I finally got around to actually playing it in late 2004, and got quite carried away with it for a while. I recently discovered modding, the common term for modifying the game to suit the player's preferences.

    On the forums at The Phrozen Keep it has been noised about that Blizzard Entertainment will not be producing Diablo III in the near future, and I piped up saying that it wouldn't be very hard for the people who do D2 modding to write up their own game. I then said that I would start a blog to track all of my design decisions.

    So now, here we are.

    Right now my tools are:

  • A clipboard with notebook paper in it.
  • My desktop and all the free utilities that the Internet has to offer.

    Updates will come as I think of them.
  •