CS638 Fall 2001: Project Stage 3.0

Tips and Resources


   In Stage 1.0 you familiarized yourself with the client shell (the Pause option in Task 4 took a detour into the server shell). Here, you will need to familiarize yourself more completely with the server shell. The server shell controls the game state, so that is where most of your AI routines will probably go.

   Keep in mind that the server shell will automatically distribute all object positions and orientations to the client. This means that if an AI routine updates an object's position in the server shell, that will automatically happen in the client shell too. Note, however, that this will only happen for objects that are derived from BaseClass (the CRocket and CTarget classes both derive from this class). If you need to send your own messages, use the ILTClient::SendToServer() and ILTServer::SendToClient() functions. Examples of how to use these functions are already in Target Arena (e.g., when firing a rocket).

   The Update() function in CGameSrvr.cpp contains the majority of the game's logic at this point. You will have to modify this function in order to implement this project. There are several other things that you need to know in order to do this project. They are described in more detail below. As usual, the Programming Guide and API Reference are useful as a reference. However, if you have a question about something, post it to the class mailing list.

Intro to DEdit

   If you want to work with path-planning, path-finding, etc, you will probably want to place pathnodes in the Target Arena level (or in a level you create yourself). To do this, you will need to be somewhat familiar with DEdit. The Game Content Creation Guide has a useful (and short) tutorial that will help get you started. You only need to know some basic things, such as maneuvering your viewpoint, editing object properties, and processing your level. The DEdit Project file for Target Arena can be opened from within DEdit. It resides in the rez directory, and is called TargetArena.dep.

Pathnodes and Path AI

   The Target Arena distribution you used for Stage 1.0 contains several classes that may be useful to you in doing this project. Two of them are the CPathnode class and the CPathAI class.

   CPathnode is a class that has been published to DEdit. This means that you can place pathnodes in a level and they will "exist" when you run the world in Target Arena. After you place a pathnode, you can edit its properties and add up to five links to other pathnodes (this is arbitrary; if you need pathnodes to contain more links, you can change CPathnode.h and CPathnode.cpp to support the number you need). This allows you to create a pathnode graph in your level, which you can then use in your AI routines. When a pathnode is loaded by the game code, all of its links are added as LithTech handles to an array called m_ahAdjacentNodes. The CPathnode class also provides a few useful functions that you may wish to use. These functions are explained in the source.

   The server shell and game server contain code that registers pathnodes as they are loaded from the map file. In particular, all pathnodes are registered with an instance of the CPathAI class, and each one receives a unique identifier. CPathAI also includes a couple of useful functions that operate on all the pathnodes it contains. These are documented in the source.


   Also included in the distribution is a class called CFighter. It is a fighter jet that you create dynamically on the server, and can be used as the physical representation of your AI agent(s). To see how to create a fighter, take a look at the code for creating rockets in the FireRocket() function in CGameSrvr.cpp. We have provided a model and texture for use with this class. If you want to use them, set cs.m_Filename to "models/ship1hi.ltb" and cs.m_SkinNames[0] to "textures/ship.dtx" in the ObjectCreateStruct for the object you are creating.

   The declaration for this class has several components that you may use at your discretion. For example, it contains a pointer to an instance of CPathAI; in effect, it contains its own pathfinding "brain". It also has some enumerated AI states as well as information about relevant pathnodes. Keep in mind that this is only one possible way of using this class (if you decide to use it at all), since it is almost entirely defined by game code that you write yourself. In fact, you could use any object as your AI agent (e.g., smart rockets).

Object-to-Object Messaging

   LithTech provides a variety of messaging modes. One of these modes, object-to-object messaging, might be useful to you in implementing this project.

   There are a couple of ways to do it. The first is to define a function called ObjectMessageFn() for any objects derived from BaseClass (e.g., CFighter, CRocket, etc). Then, you can call this function from another object, specifying the sending object as the first parameter. This way, objects will know exactly who sent the message.

   The other option is to use the server shell as an intermediary. In this case, the object that wishes to send a message uses ILTServer::SendToServer() (note that this is different from ILTClient::SendToServer()). This message is received by the server shell in IServerShell::OnObjectMessage() and includes information about the sending object. The server shell can then perform the required behavior (e.g., passing the message on to the game server, sending a message to all objects of a particular type, etc).

   You can combine the two methods. For example, you can send a message from an object using ILTServer::SendToServer() then have the server send messages to objects using ObjectMessageFn() (and passing the original sending object as the first parameter).

Useful LithTech Functions

   There is a variety of useful functions that you may wish to use in implementing your project. For example, to check whether one object can "see" another, you might want to cast a ray from one to the other and see if it hits anything along the way (and what exactly it hits). This is done using the ILTCollisionMgr::CastRay() function.

   The LTOrientation class provides many useful functions. LTOrientation::Forward() returns an LTVector that points in the "forward" direction of the original orientation. LTVector::Right() and LTVector::Up() do the equivalent for "right" and "up". LTOrientation::RotateAboutY() performs a rotation about the world y-axis (equivalent functions are available for the other axes as well as for arbitrary axes).

   Standard operations such as cross product and dot product are implemented in the LTVector class as LTVector::Cross(LTVector) and LTVector::Dot(LTVector). Other useful functions include LTVector::Length() and LTVector::Normalize(). In addition, many standard operations (assignment, equality testing) exist as overloaded operators for the LTVector class.

   There are many other functions described in the LT API. Since there are so many different ways to approach this project, check the API if you find you need some particular function. If it's not there, the Programming Guide might explain how to perform a task in several steps.

Object Representations

   You can use ILTServer::HandleToObject() and ILTServer::ObjectToHandle() to convert an object's representation. For example, if hTarget is an HOBJECT meant to represent an instance of CTarget, and pTarget is of type CTarget*, you can write hTarget = g_pLTServer->ObjectToHandle(pTarget) and pTarget = (CTarget*)g_pLTServer->HandleToObject(hTarget).

   Why would you want to do this? The reason is that you use the two representations for different things. pTarget would be used when you want to call functions on a target object itself (for example, you have defined a function that gets the target's current hit points). hTarget would be used when you want to ask the server something about that object (such as when you get its position using g_pLTSPhysics->GetPosition(hTarget, &pos) ).

   One important note: your class must be derived from BaseClass to be convertible into an HOBJECT.

Return to Project 3 page