Game Development Community

dev|Pro Game Development Curriculum

Plan for Tim Gift

by Tim Gift · 08/18/2001 (8:27 pm) · 4 comments

Been working on a number of different things recently. Some web site & purchase order fixes, V12 bug fixes and some script examples and documentation.

I started working on the script doco as a separate doco file, but nobody liked that (including myself). Maintaining separate documentation from the source is a pain in the butt, and since we're going to be using doxygen to solve that problem for our C++ source, I thought I'd explore our options there for the scripting side.

This turns out to be a bit of a problem because the implementation of the scripting language, and it's class interfaces, is embedded in the C++ code and cannot be directly parsed by doxygen. Anyway, I tried a few things, and then Rick, Mark and I discussed it for a while. Mark proposed something that may do the trick, but it will require a little coding. Not much, but I'm going to sit on it for a while and make sure this is the way we want to do this. Tony Richards is also working on script documentation. We'll have to see how his work get's integrated.

In the meantime, I've appended one of the text files that I had started on. This has a rough pass at the GameBase and ShapeBase datablock properties and methods. This is by no means complete, nor is it in it's final form. But I've included here for now on the off chance that someone will find it usefull...

//----------------------------------------------------------------------------
// GameBase is the class from which all game objects are derived.
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// Datablock properties
//
// (The category field is actually mispelled in the current 1.0.0 release
// as "catagory".)
//    TypeCaseString       category = NULL;  // Used by the mission editor
//    TypeString           className;        // The datablock class name
//
// Object properties
//
//    TypeCaseSting        nameTag;          // ?
//    TypeGameBaseDataPtr  dataBlock;        // The current datablock
//
// Object Methods
//
//    DatablockId getDataBlock();
//    bool setDataBlock(DataBlock);
//
//----------------------------------------------------------------------------

function GameBase::onAdd(%this,%obj)
{
   // Called when the object is added constructed.
   echo(%this.className @ "::onAdd("@ %this @","@ %obj @")");
}

function GameBase::onRemove(%this,%obj)
{
   // Called when the object is deleted.
   echo(%this.className @ "::onRemove("@ %this @","@ %obj @")");
}

function GameBase::onNewDataBlock(%this,%obj)
{
   // Called each time the object is assigned a new datablock.
   // Most internal initialization for a GameBase object happens
   // when it's datablock is loaded.  Switching datablocks on
   // the fly can be used to change the physical representation
   // and properties of an object.
   echo(%this.className @ "::onNewDataBlock("@ %this @","@ %obj @")");
}


//----------------------------------------------------------------------------
// Shape Base is derived from GameBase, and is the renderable shape from
// which most of the scriptable objects are derived, including the player,
// vehicle and items classes.  Shape base provides basic shape loading,
// audio channels, animation as well as damage (and damage states), energy
// and images.  Images are light weight mountable objects.
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// Datablock Properties
//
// Shape (.dts) file to load
//
//    TypeFilename            shapeFile = NULL;
//    TypeFilename            debrisShapeName = NULL;
//
// If set to true, the server will transmit the shapeFile CRC
// to the client where it must match.
//
//    TypeBool                computeCRC = false;
//
// Explosion & debris datablocks, used when the shape is destroyed
//
//    TypeExplosionDataPtr    explosion = NULL;
//    TypeExplosionDataPtr    underwaterExplosion = NULL;
//    TypeDebrisDataPtr       debris = NULL;
//
// Physical properties. These parameters are used by derived classes.
// ShapeBase itself provides no movement or physics.
//
//    TypeF32                 mass = 1;
//    TypeF32                 drag = 0;
//    TypeF32                 density = 1;
//
// Energy properties
//
//    TypeF32                 maxEnergy = 0;        // Max allowable energy
//    TypeBool                inheritEnergyFromMount = false;
//
// Damage properties
//
//    TypeF32                 maxDamage = 1;        // Max allowable damage
//    TypeF32                 destroyedLevel = 1;   // Level at which the object blows up
//    TypeF32                 repairRate = 0.0033;  // Reserver repair rate per tick
//    TypeBool                isInvincible = false;
//
// Camera FOV limits for controllable objects
//
//    TypeF32                 cameraDefaultFov = 90;
//    TypeF32                 cameraMinFov = 5;
//    TypeF32                 cameraMaxFov = 120;
//    TypeBool                useEyePoint;
//
// 3rd person camera & observer properties
//
//    TypeF32                 cameraMaxDist = 0;
//    TypeF32                 cameraMinDist = 0.2;
//    TypeBool                firstPersonOnly = false;
//    TypeBool                observeThroughObject = false;
//
// Render options
//
//    TypeBool                emap = false;
//    TypeBool                renderWhenDestroyed = true;
//
// If this is the control object and this is set to
// true, the explosion doesn't shake the camera. (??)
//
//    TypeBool                useEyePoint = false;
//
// Informs the AI to avoid this object
//
//    TypeBool                aiAvoidThis = false;
//
//----------------------------------------------------------------------------
// Object Methods accessible from from the scripting language.
// These methods are invoked off a ShapeBase (or derived class)
// object, not the datablock.
//
// Objects have four script controlled audio channels
//
//    bool        playAudio(channel,AudioProfile);
//    bool        playAudio(channel);
//
// Object have four script controlled animation threads. The sequence #
// can be left off of playThread when playing a paused thread.
//
//    bool        playThread(thread,<sequence>);
//    bool        setThreadDir(thread,bool);
//    bool        stopThread(thread);
//    bool        pauseThread(thread);
//
// Some objects can be mounted on others, theoretically any object, but
// I believe the player is the only object that fully supports this.
// Objects are mounted onto mount nodes points specified in the shape.
//
//    bool        mountObject(object,node);
//    bool        unmountObject(object);
//    bool        unmount();
//    bool        isMounted();
//    ObjectId    getObjectMount();          // Object we are mounted on
//    int         getMountNodeObject(node);  // Returns shape on the node
//
// Functions to iterate through objects mounted on this this object
//
//    int         getMountedObjectCount();
//    int         getMountedObjectNode(index);  // Get object n's node #
//    ObjectId    getMountedObject(index);      // Get object n
//
// Datablock Images can be mounted on to objects. Images are light weight
// objects that do not exists in the world, only mounted on other other
// objects.  Images have scripted states and are used for a number of things
// including weapons.  Shapes can have up to 8 images mounted.
//
//    bool        mountImage(DataBlock,slot,<loaded=true>,<skinTag>);
//    bool        unmountImage(slot);
//    DatablockId getMountedImage(slot);
//    bool        isImageMounted(DataBlock);
//    int         getMountSlot(DataBlock);
//    String      getImageState(slot);
//    int         getSlotTransform(slot);
//    Tag         getImageSkinTag(slot);
//
// If you mount an image into a slot with an existing image in a blocking
// state, the image is placed on the pending list and will be mounted
// automatically when the current image leaves the blocked state.
// A typical blocked state is the fire animation, in this case the image
// cannot be removed until it's fire animation is done.
//
//    DatablockId getPendingImage(slot);
//
// Images have several built in flags that can be used to control scripted
// state transitions on the image.  These function don't do anything
// except set or test flags.
//
//    bool        setImageTrigger(slot,bool);
//    bool        setImageLoaded(slot,bool);
//    bool        setImageAmmo(slot,bool);
//    bool        getImageTrigger(slot);
//    bool        getImageLoaded(slot);
//    bool        getImageAmmo(slot);
//    bool        setImageTarget(slot,bool);
//    bool        getImageTarget(slot);
//
// Returns true if the current image state has set the firing flag.
//
//    bool isImageFiring(slot);
//
// Return node information from the image.  The image must have a muzzle
// node defined.
//
//    Vector      getMuzzleVector(slot);
//    Point       getMuzzlePoint(slot);
//    Point       getAIRepairPoint();
//
// Basic movement stuff..
//
//    Vector      getVelocity();
//    bool        setVelocity(vector);
//    bool        applyImpulse(origin,vector);
//
// Return information about the eye node. The "eye" node must exists in
// the dts shape.
//
//    Vector      getEyeVector();
//    Transform   getEyeTransform();
//    float       getCameraFov();
//    void        setCameraFov(fov);
//
// Energy management
//
//    void        setEnergyLevel(value);
//    float       getEnergyLevel();
//    float       getEnergyPercent();     // Used on the clients to get a 0-1 value
//    void        setRechargeRate(value); // Permanent energy/tick recharge
//    float       getRechargeRate();
//
// Damage level & states
//
//    void        setDamageLevel(value);
//    float       getDamageLevel();
//    float       getDamagePercent();        // Returns 0-1
//    bool        setDamageState(state);
//    String      getDamageState();
//    bool        isDestroyed();
//    bool        isDisabled();
//    bool        isEnabled();
//    void        setDamageVector(vec);
//
// Apply damage delta, damage is applied instantaeously, but repairs are
// applied over time based on the datblock repairRate
//
//    void        applyDamage(value);
//    void        applyRepair(value);
//    void        setRepairRate(value);      // Permanent value/tick repair
//    float       getRepairRate();
//
// Any shape base can theoritcally be controlled, in practice not all
// derived classes support this feature.  Which object a client is
// controlling is managed by the ClientConnection Object. Examples of
// controllable objects include th Player, Camera and Vehicle classes.
// Some object (such as the Player) can control other objects, so
// GetControllingObject may not necessarily return the ClienConnection
// object.  GetControllingClient follows the control chain up and 
// always returns a ClientConnection object.
//
//    ObjectId    getControllingClient();    // Returns ClientConnection
//    ObhectId    getControllingObject();
//
// Special effects.
//
//    bool        canCloak();
//    void        setCloaked(true|false);
//    bool        isCloaked();
//    void        setInvincibleMode(time, speed);              // Time in sec.
//    void        startFade(fadeTime,delayTime,bool fadeOut);  // Time in msec?
//
// Set damage flash visible to controlling client
//
//    void        setDamageFlash(flash level);        // (0-1)
//    float       getDamageFlash();
//    void        setWhiteOut(flash level);           // (0-1)
//    float       getWhiteOut();
//
// Hide removes the object from the scene.  Removing or adding
// an object from the scene is not the same as removing in from
// the sim engine.  Hiding does not generate calls to onAdd or
// onRemove.
//
//    void        hide(bool);
//    bool        isHidden();
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------

function ShapeBase::onDamage(%this,%obj)
{
   // Called whenever the object's damage level changes.
   echo(%this.className @ "::onDamage("@ %this @","@ %obj @")");
}


//----------------------------------------------------------------------------

function ShapeBase::onDestroyed(%this,%obj,%lastState)
{
   // When a shape's damage level exceeds the dataBlock destroyedLevel
   // value, then it's damage hulk shape is displayed and this
   // script called.
   echo(%this.className @ "::onDestroyed("@ %this @","@ %obj @","@ %lastState @")");
}

function ShapeBase::onDisabled(%this,%obj,%lastState)
{
   // Shapes have a enabled/disable state, many internal operations
   // don't function unless the object is enabled.  If the object
   // is destroyed, it will be disable automatically, otherwise
   // the setDamageState object method can be used to manage states.
   echo(%this.className @ "::onDisabled("@ %this @","@ %obj @","@ %lastState @")");
}

function ShapeBase::onEnabled(%this,%obj,%lastState)
{
   // Shapes have a enabled/disable state, many internal operations
   // don't function unless the object is enabled.  If the object
   // is destroyed, it will be disable automatically, otherwise
   // the setDamageState object method can be used to manage states.
   echo(%this.className @ "::onEnabled("@ %this @","@ %obj @","@ %lastState @")");
}


//----------------------------------------------------------------------------

function ShapeBase::onTrigger(%this,%obj,%trigger,%state)
{
   // If this object is being controlled by a connection object it will
   // recieve move events. This function is called whenever a trigger
   // move state changes.
   echo(%this.className @ "::onTrigger("@ %this @ "," @ %obj @ "," @ %trigger @ "," @ %state @ ")");
}


//----------------------------------------------------------------------------

function ShapeBase::onCollision(%this,%obj,%collider)
{
   // Called when the collider object collides with the shape
   echo(%this.className @ "::onCollision("@ %this @ "," @ %obj @ "," @ %collider @ ")");
}

function ShapeBase::onImpact(%this,%obj,%obstacle,%vel,%speed)
{
   // This function is only called when an object impacts another
   // and it's velocity exceeds the datablock's minImpactSpeed.
   // Not all objects support this call, though Player does.
   echo(%this.className @ "::onImpact("@ %this @ "," @ %obj @ "," @ %obstacle @ "," @ %vel @ "," @ %speed @ ")");
}


//----------------------------------------------------------------------------

function ShapeBase::onMount(%this,%obj,%mount,%node)
{
   // Called when the object is mounted on the %mount object at %node
   // Objects are mounted useing the mountObject method.
   echo(%this.className @ "::onMount("@ %this @ "," @ %obj @ "," @ %mount @ "," @ %node @ ")");
}


function ShapeBase::onUnount(%this,%obj,%mount,%node)
{
   // Called when the object is unmounted from the %mount object.
   // %node being the nod it was mounted on.
   // Objects are mounted useing the unmountObject method.
   echo(%this.className @ "::onMount("@ %this @ "," @ %obj @ "," @ %mount @ "," @ %node @ ")");
}


//----------------------------------------------------------------------------

function ShapeBase::onEndSequence(%this,%obj,%mount,%node)
{
   // Shape base objects can have up to four script controlled
   // animations threads.  These are operated by the playThread,
   // stopThread, pauseThread and setThreadDir.  This function
   // is called when a non-cyclic animation reaches the end of
   // it's animation.
   echo(%this.className @ "::onCollision("@ %this @ "," @ %obj @ "," @ %mount @ "," @ %node @ ")");
}

#1
08/18/2001 (8:41 pm)
Thank you so much, this is JUST what I needed!
#2
08/19/2001 (7:41 am)
Whooo! good stuff. One point.. why is there a limit on the stuff like images attached to mount points? it'd be nicer to have a vector of mount points and a vector of images per mount point.

Its not really an issue now, but I'd hope we can get rid of any hard-coded limits over time so that there are less restrictions on what we do with the engine.

I'd personally like to see some of these variables like energy removed from the base class and moved higher up the class heirarchy. But I guess thats another issue (one of architecture) and really aint that important :))

Great work Tim, this kind of thing really gives us a better idea how things are internally.

Phil.
#3
08/19/2001 (9:18 am)
Yes, energy does seem a little out of place in shapeBase. In Tribes it worked well, since almost all objects deal with energy, but it probably doesn't make sense for many games. As for the image and audio channel limits, the fixed limits make for a nice small number of index bits which make network management easier.

(made a few additions to the doc)
#4
08/19/2001 (3:01 pm)
Aha, fair enough, forgot about the networking issues.

Phil.