Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
DZDrone.c
/* |
* File: DZDrone.c |
* |
* Contents: A drone object represents the position of an player or drone. |
* |
* Copyright © 1996 Apple Computer, Inc. |
*/ |
#include <assert.h> |
#include <math.h> |
#include <stdlib.h> |
#include <Components.h> |
#include <Dialogs.h> |
#include <Events.h> |
#include <QuickDraw.h> |
#include <Resources.h> |
#include <Sound.h> |
#include <SoundComponents.h> |
#include <SoundInput.h> |
#include <ToolUtils.h> |
#include <Types.h> |
#include <QD3D.h> |
#include <QD3DCamera.h> |
#include <QD3DDrawContext.h> |
#include <QD3DGeometry.h> |
#include <QD3DMath.h> |
#include <QD3DPick.h> |
#include <QD3DSet.h> |
#include <QD3DShader.h> |
#include <QD3DStyle.h> |
#include <QD3DTransform.h> |
#include <QD3DView.h> |
#include "SoundSprocket.h" |
#include "DZDisplay.h" |
#include "DZDrone.h" |
#include "DZGame.h" |
#include "DZResource.h" |
#include "DZSound.h" |
#include "DZThumbprint.h" |
#include "DZUtils.h" |
#ifndef SELF_DRONE_HAS_FRICTION |
#define SELF_DRONE_HAS_FRICTION 1 |
#endif |
#define IS_SELF_DRONE(inDrone) (inDrone->thumbprint == kThumbprint_SelfDrone) |
#define IS_AUTO_DRONE(inDrone) (inDrone->thumbprint == kThumbprint_AutoDrone) |
#define IS_BULLET_DRONE(inDrone) (inDrone->thumbprint == kThumbprint_BulletDrone) |
#define IS_DRONE(inDrone) (IS_SELF_DRONE(inDrone) || IS_AUTO_DRONE(inDrone) || IS_BULLET_DRONE(inDrone)) |
#define SELF_DRONE_INITIAL_SPEED 0.50 // In units per second |
#define SELF_DRONE_MAX_ACCEL 10.0 // In units per second per second |
#define SELF_DRONE_FRICTION 0.80 // as a percentage (1.00 would be no friction) |
#define AUTO_DRONE_LEAD 5.0 // Drone target leads by this distance (in units) |
#define AUTO_DRONE_ACCEL 2.0 // Drone acceleration (units per second per second) |
#define AUTO_DRONE_TURN_RATE 1.8 // In radians per second |
#define AUTO_DRONE_BURN_TIME 3.0 // In seconds |
#define AUTO_DRONE_REST_TIME 1.0 // In seconds |
#define AUTO_DRONE_EXPLOSION_TIME 3.0 // In seconds |
#define AUTO_DRONE_FADE_TIME 0.25 // Fraction of AUTO_DRONE_EXPLOSION_TIME for fade |
#define AUTO_DRONE_MIN_SCALE 0.2 // Initial scale for explosion |
#define AUTO_DRONE_IDLE_REF_DIST 2.0 |
#define AUTO_DRONE_BURN_REF_DIST 5.0 |
#define AUTO_DRONE_EXPL_REF_DIST 30.0 |
#define BULLET_DRONE_OFFSET 0.2 // Offset from self to bullet initial position |
#define BULLET_DRONE_SPEED 50.0 // In units per second |
#define BULLET_DRONE_LIMIT 50.0 // Maximum length of a bullet |
#define HUD_SCALE 0.02 // Scale of HUD |
#define HUD_HEIGHT 0.5 // cos(angle) at which to consider out-of-plane |
enum { |
kDroneDrawContextSize = 5 // Used for picking |
}; |
typedef enum TDroneOrder { // In order of evaluation |
kDroneOrder_Self, |
kDroneOrder_Auto, |
kDroneOrder_Bullet |
} TDroneOrder; |
typedef void (*TDroneMoveMethod)( |
TDroneObject inDrone); |
typedef void (*TDroneUpdateSoundMethod)( |
TDroneObject inDrone); |
typedef void (*TDroneSubmitMethod)( |
TDroneObject inDrone, |
Boolean inHUDVisible, |
TQ3ViewObject inView); |
typedef void (*TDronePickSubmitMethod)( |
TDroneObject inDrone, |
TQ3ViewObject inView); |
typedef void (*TDroneHitMethod)( |
TDroneObject inDrone); |
typedef enum TAutoSound { |
kAutoSound_None, |
kAutoSound_Idle, |
kAutoSound_Burn, |
kAutoSound_Explosion |
} TAutoSound; |
typedef enum TAutoMode { |
kAutoMode_Idle, |
kAutoMode_Burn, |
kAutoMode_Rest, |
kAutoMode_Explosion |
} TAutoMode; |
typedef struct TDroneData { |
TThumbprint thumbprint; // For validation |
TDroneMoveMethod moveMethod; // Method: Drone_Move |
TDroneUpdateSoundMethod updateSoundMethod; // Method: Drone_UpdateSound |
TDroneSubmitMethod submitMethod; // Method: Drone_Submit |
TDronePickSubmitMethod pickSubmitMethod; // Method: Drone_PickSubmit |
TDroneHitMethod hitMethod; // Method: Drone_Hit |
TDroneObject prev; // The global list of drones |
TDroneObject next; |
TDroneOrder order; // Sort key |
Boolean mark; // Is this drone marked to die? |
TQ3Point3D position; // Current position |
TQ3Point3D position1; // Previous position |
TQ3Vector3D velocity; // Change in position over time |
TQ3Vector3D velocity1; // Previous velocity |
TQ3Vector3D acceleration; // Change in velocity over time |
TQ3Vector3D direction; // Forward (model X axis) |
TQ3Vector3D up; // Vertical (model Y axis) |
TQ3Vector3D cross; // Horizontal (model Z axis) |
TQ3Object geometry; // The shape of the drone |
SndChannelPtr autoSndChannel; // Auto: Sound channel |
SSpSourceReference autoSource; // Auto: 3D sound source |
TAutoSound autoSound; // Auto: Sound currently playing |
TDroneObject autoInterest; // Auto: Drone that we're looking at |
TQ3Vector3D autoVelocity; // Auto: Drone velocity (instantaneous) |
TAutoMode autoMode; // Auto: Current state |
unsigned long autoModeTimeout; // Auto: When does mode expire? |
float autoDistance; // Auto: Last distance from target |
float autoExplosion; // Auto: 0=start; 1=end of explosion |
TQ3Point3D bulletOrigin; // Bullet: Starting position of the bullet |
} TDroneData; |
static TDroneObject gDroneList = NULL; |
static TQ3Object gDroneAutoGeometry = NULL; |
static TQ3Object gDroneAutoBurnGeometry = NULL; |
static TQ3Object gDroneAutoExplosionGeometry = NULL; |
static TQ3AttributeSet gDroneBulletColor = NULL; |
static TQ3ShaderObject gDroneNULLIllumination = NULL; |
static TQ3ViewObject gDroneView = NULL; |
static TQ3DrawContextObject gDroneDrawContext = NULL; |
static TQ3CameraObject gDroneCamera = NULL; |
static TQ3PickObject gDronePick = NULL; |
static SndListHandle gDroneAutoSndIdle = NULL; |
static SndListHandle gDroneAutoSndBurn = NULL; |
static SndListHandle gDroneAutoSndExplosion = NULL; |
static long gDroneAutoSndIdleOffset = 0; |
static long gDroneAutoSndBurnOffset = 0; |
static long gDroneAutoSndExplosionOffset = 0; |
static TQ3GeometryObject gDroneAutoMarkerEqual = NULL; |
static TQ3GeometryObject gDroneAutoMarkerAbove = NULL; |
static TQ3GeometryObject gDroneAutoMarkerBelow = NULL; |
static unsigned char gDroneAutoMarkerDataEqual[8] = |
{0x38, 0x44, 0x82, 0x92, 0x82, 0x44, 0x38, 0x00}; |
static unsigned char gDroneAutoMarkerDataAbove[8] = |
{0x38, 0x54, 0x92, 0xFE, 0x92, 0x54, 0x38, 0x00}; |
static unsigned char gDroneAutoMarkerDataBelow[8] = |
{0x38, 0x44, 0x82, 0xFE, 0x82, 0x44, 0x38, 0x00}; |
static Boolean gDroneAutoCheckFilterVersion = true; |
static TDroneObject Drone_New( |
TDroneOrder inOrder); |
static void SelfDrone_Move( |
TDroneObject inDrone); |
static void AutoDrone_Move( |
TDroneObject inDrone); |
static void BulletDrone_Move( |
TDroneObject inDrone); |
static void AutoDrone_UpdateSound( |
TDroneObject inDrone); |
static void AutoDrone_Submit( |
TDroneObject inDrone, |
Boolean inHUDVisible, |
TQ3ViewObject inView); |
static void BulletDrone_Submit( |
TDroneObject inDrone, |
Boolean inHUDVisible, |
TQ3ViewObject inView); |
static void Drone_PickSubmit( |
TDroneObject inDrone, |
TQ3ViewObject inView); |
static void AutoDrone_PickSubmit( |
TDroneObject inDrone, |
TQ3ViewObject inView); |
static void Drone_Hit( |
TDroneObject inDrone); |
static void AutoDrone_Hit( |
TDroneObject inDrone); |
void Drone_GetMatrix( |
TDroneObject inDrone, |
TQ3Matrix4x4* outMatrix); |
/* ============================================================================= |
* Drone_Init (external) |
* |
* Initializes the drone stuff. |
* ========================================================================== */ |
void Drone_Init( |
void) |
{ |
TQ3ColorRGB color; |
TQ3PixmapDrawContextData pixmapDrawContextData; |
TQ3ViewAngleAspectCameraData viewAngleCameraData; |
TQ3WindowPointPickData windowPointPickData; |
TQ3MarkerData markerData; |
// Set up the autopilot drone geometry |
gDroneAutoGeometry = Get3DMFResource(k3DMFID_AutoDrone); |
assert(gDroneAutoGeometry != NULL); |
// Set up the autopilot drone burn geometry |
gDroneAutoBurnGeometry = Get3DMFResource(k3DMFID_AutoDroneBurn); |
assert(gDroneAutoBurnGeometry != NULL); |
// Set up the autopilot drone explosion geometry |
gDroneAutoExplosionGeometry = Get3DMFResource(k3DMFID_AutoDroneExplosion); |
assert(gDroneAutoExplosionGeometry != NULL); |
// Read in the autopilot drone sounds |
gDroneAutoSndIdle = (SndListHandle) GetResource('snd ', kSndID_AutoIdle); |
assert(gDroneAutoSndIdle != NULL); |
gDroneAutoSndBurn = (SndListHandle) GetResource('snd ', kSndID_AutoBurn); |
assert(gDroneAutoSndBurn != NULL); |
gDroneAutoSndExplosion = (SndListHandle) GetResource('snd ', kSndID_AutoExplosion); |
assert(gDroneAutoSndExplosion != NULL); |
GetSoundHeaderOffset(gDroneAutoSndIdle, &gDroneAutoSndIdleOffset); |
GetSoundHeaderOffset(gDroneAutoSndBurn, &gDroneAutoSndBurnOffset); |
GetSoundHeaderOffset(gDroneAutoSndExplosion, &gDroneAutoSndExplosionOffset); |
// Set up the bullet drone line color |
gDroneBulletColor = Q3AttributeSet_New(); |
assert(gDroneBulletColor != NULL); |
color.r = 1.0; |
color.g = 0.8; |
color.b = 0.1; |
Q3AttributeSet_Add(gDroneBulletColor, kQ3AttributeTypeDiffuseColor, &color); |
// Create the bullet null illum shader |
gDroneNULLIllumination = Q3NULLIllumination_New(); |
assert(gDroneNULLIllumination != NULL); |
// Create the view that we use for bullet collision detection |
gDroneView = Q3View_New(); |
assert(gDroneView != NULL); |
// Create its draw context |
pixmapDrawContextData.drawContextData.clearImageMethod = kQ3ClearMethodWithColor; |
pixmapDrawContextData.drawContextData.clearImageColor.a = 1.0; |
pixmapDrawContextData.drawContextData.clearImageColor.r = 0.0; |
pixmapDrawContextData.drawContextData.clearImageColor.g = 0.0; |
pixmapDrawContextData.drawContextData.clearImageColor.b = 0.0; |
pixmapDrawContextData.drawContextData.paneState = kQ3False; |
pixmapDrawContextData.drawContextData.maskState = kQ3False; |
pixmapDrawContextData.drawContextData.doubleBufferState = kQ3False; |
pixmapDrawContextData.pixmap.width = kDroneDrawContextSize; |
pixmapDrawContextData.pixmap.height = kDroneDrawContextSize; |
pixmapDrawContextData.pixmap.rowBytes = pixmapDrawContextData.pixmap.width*4; |
pixmapDrawContextData.pixmap.pixelSize = 32; |
pixmapDrawContextData.pixmap.pixelType = kQ3PixelTypeRGB32; |
pixmapDrawContextData.pixmap.bitOrder = kQ3EndianBig; |
pixmapDrawContextData.pixmap.byteOrder = kQ3EndianBig; |
pixmapDrawContextData.pixmap.image = malloc(pixmapDrawContextData.pixmap.height*pixmapDrawContextData.pixmap.rowBytes); |
gDroneDrawContext = Q3PixmapDrawContext_New(&pixmapDrawContextData); |
assert(gDroneDrawContext != NULL); |
Q3View_SetDrawContext(gDroneView, gDroneDrawContext); |
// Create its camera |
viewAngleCameraData.cameraData.placement.cameraLocation.x = 0.0; |
viewAngleCameraData.cameraData.placement.cameraLocation.y = 0.0; |
viewAngleCameraData.cameraData.placement.cameraLocation.z = 0.0; |
viewAngleCameraData.cameraData.placement.pointOfInterest.x = 1.0; |
viewAngleCameraData.cameraData.placement.pointOfInterest.y = 0.0; |
viewAngleCameraData.cameraData.placement.pointOfInterest.z = 0.0; |
viewAngleCameraData.cameraData.placement.upVector.x = 0.0; |
viewAngleCameraData.cameraData.placement.upVector.y = 1.0; |
viewAngleCameraData.cameraData.placement.upVector.z = 0.0; |
viewAngleCameraData.cameraData.range.hither = 0.1; |
viewAngleCameraData.cameraData.range.yon = BULLET_DRONE_LIMIT; |
viewAngleCameraData.cameraData.viewPort.origin.x = -1.0; |
viewAngleCameraData.cameraData.viewPort.origin.y = 1.0; |
viewAngleCameraData.cameraData.viewPort.width = 2.0; |
viewAngleCameraData.cameraData.viewPort.height = 2.0; |
viewAngleCameraData.fov = 0.1; |
viewAngleCameraData.aspectRatioXToY = pixmapDrawContextData.pixmap.width/pixmapDrawContextData.pixmap.height; |
gDroneCamera = Q3ViewAngleAspectCamera_New(&viewAngleCameraData); |
assert(gDroneCamera != NULL); |
Q3View_SetCamera(gDroneView, gDroneCamera); |
// Create the pick object |
windowPointPickData.data.sort = kQ3PickSortNearToFar; |
windowPointPickData.data.mask = kQ3PickDetailMaskPickID | kQ3PickDetailMaskDistance; |
windowPointPickData.data.numHitsToReturn = kQ3ReturnAllHits; |
windowPointPickData.point.x = 0.5*pixmapDrawContextData.pixmap.width; |
windowPointPickData.point.y = 0.5*pixmapDrawContextData.pixmap.height; |
windowPointPickData.vertexTolerance = 0.0; |
windowPointPickData.edgeTolerance = 0.0; |
gDronePick = Q3WindowPointPick_New(&windowPointPickData); |
assert(gDronePick != NULL); |
// Create the autodrone markers |
markerData.location.x = 0.0; |
markerData.location.y = 0.0; |
markerData.location.z = 0.0; |
markerData.xOffset = -3; |
markerData.yOffset = -3; |
markerData.bitmap.width = 8; |
markerData.bitmap.height = 8; |
markerData.bitmap.rowBytes = 1; |
markerData.bitmap.bitOrder = kQ3EndianBig; |
markerData.markerAttributeSet = Q3AttributeSet_New(); |
assert(markerData.markerAttributeSet != NULL); |
color.r = 1.0; |
color.g = 1.0; |
color.b = 0.4; |
Q3AttributeSet_Add(markerData.markerAttributeSet, kQ3AttributeTypeDiffuseColor, &color); |
markerData.bitmap.image = (unsigned char*) gDroneAutoMarkerDataEqual; |
gDroneAutoMarkerEqual = Q3Marker_New(&markerData); |
assert(gDroneAutoMarkerEqual != NULL); |
markerData.bitmap.image = (unsigned char*) gDroneAutoMarkerDataAbove; |
gDroneAutoMarkerAbove = Q3Marker_New(&markerData); |
assert(gDroneAutoMarkerAbove != NULL); |
markerData.bitmap.image = (unsigned char*) gDroneAutoMarkerDataBelow; |
gDroneAutoMarkerBelow = Q3Marker_New(&markerData); |
assert(gDroneAutoMarkerBelow != NULL); |
Q3Object_Dispose(markerData.markerAttributeSet); |
markerData.markerAttributeSet = NULL; |
} |
/* ============================================================================= |
* Drone_Exit (external) |
* |
* Prepares for exit. |
* ========================================================================== */ |
void Drone_Exit( |
void) |
{ |
while (gDroneList != NULL) |
{ |
Drone_Dispose(gDroneList); |
} |
if (gDroneAutoGeometry != NULL) |
{ |
Q3Object_Dispose(gDroneAutoGeometry); |
gDroneAutoGeometry = NULL; |
} |
if (gDroneAutoBurnGeometry != NULL) |
{ |
Q3Object_Dispose(gDroneAutoBurnGeometry); |
gDroneAutoBurnGeometry = NULL; |
} |
if (gDroneAutoExplosionGeometry != NULL) |
{ |
Q3Object_Dispose(gDroneAutoExplosionGeometry); |
gDroneAutoExplosionGeometry = NULL; |
} |
if (gDroneAutoSndIdle != NULL) |
{ |
ReleaseResource((Handle) gDroneAutoSndIdle); |
gDroneAutoSndIdle = NULL; |
} |
if (gDroneAutoSndBurn != NULL) |
{ |
ReleaseResource((Handle) gDroneAutoSndBurn); |
gDroneAutoSndBurn = NULL; |
} |
if (gDroneAutoSndExplosion != NULL) |
{ |
ReleaseResource((Handle) gDroneAutoSndExplosion); |
gDroneAutoSndExplosion = NULL; |
} |
if (gDroneBulletColor != NULL) |
{ |
Q3Object_Dispose(gDroneBulletColor); |
gDroneBulletColor = NULL; |
} |
if (gDroneNULLIllumination != NULL) |
{ |
Q3Object_Dispose(gDroneNULLIllumination); |
gDroneNULLIllumination = NULL; |
} |
if (gDroneView != NULL) |
{ |
Q3Object_Dispose(gDroneView); |
gDroneView = NULL; |
} |
if (gDroneDrawContext != NULL) |
{ |
Q3Object_Dispose(gDroneDrawContext); |
gDroneDrawContext = NULL; |
} |
if (gDroneCamera != NULL) |
{ |
Q3Object_Dispose(gDroneCamera); |
gDroneCamera = NULL; |
} |
if (gDronePick != NULL) |
{ |
Q3Object_Dispose(gDronePick); |
gDronePick = NULL; |
} |
if (gDroneAutoMarkerEqual != NULL) |
{ |
Q3Object_Dispose(gDroneAutoMarkerEqual); |
gDroneAutoMarkerEqual = NULL; |
} |
if (gDroneAutoMarkerAbove != NULL) |
{ |
Q3Object_Dispose(gDroneAutoMarkerAbove); |
gDroneAutoMarkerAbove = NULL; |
} |
if (gDroneAutoMarkerBelow != NULL) |
{ |
Q3Object_Dispose(gDroneAutoMarkerBelow); |
gDroneAutoMarkerBelow = NULL; |
} |
} |
/* ============================================================================= |
* Drone_New (internal) |
* |
* Creates a new drone. |
* ========================================================================== */ |
TDroneObject Drone_New( |
TDroneOrder inOrder) |
{ |
TDroneObject drone; |
TDroneObject prev; |
TDroneObject next; |
// Allocate the memory |
drone = (TDroneObject) malloc(sizeof(TDroneData)); |
assert(drone != NULL); |
drone->thumbprint = kThumbprint_Dead; // until finished with it |
// Find where to insert it |
prev = NULL; |
next = gDroneList; |
while (next != NULL && next->order < inOrder) |
{ |
prev = next; |
next = next->next; |
} |
// Link it into the list |
drone->prev = prev; |
drone->next = next; |
if (prev != NULL) |
{ |
prev->next = drone; |
} |
else |
{ |
gDroneList = drone; |
} |
if (next != NULL) |
{ |
next->prev = drone; |
} |
// Fill in the defaults |
drone->moveMethod = NULL; |
drone->updateSoundMethod = NULL; |
drone->submitMethod = NULL; |
drone->pickSubmitMethod = NULL; |
drone->hitMethod = NULL; |
drone->order = inOrder; |
drone->mark = false; |
drone->position.x = 0.0; |
drone->position.y = 0.0; |
drone->position.z = 0.0; |
drone->position1.x = 0.0; |
drone->position1.y = 0.0; |
drone->position1.z = 0.0; |
drone->velocity.x = 0.0; |
drone->velocity.y = 0.0; |
drone->velocity.z = 0.0; |
drone->velocity1.x = 0.0; |
drone->velocity1.y = 0.0; |
drone->velocity1.z = 0.0; |
drone->acceleration.x = 0.0; |
drone->acceleration.y = 0.0; |
drone->acceleration.z = 0.0; |
drone->direction.x = 1.0; |
drone->direction.y = 0.0; |
drone->direction.z = 0.0; |
drone->up.x = 0.0; |
drone->up.y = 1.0; |
drone->up.z = 0.0; |
drone->cross.x = 0.0; |
drone->cross.y = 0.0; |
drone->cross.z = 1.0; |
drone->geometry = NULL; |
drone->autoSndChannel = NULL; |
drone->autoSource = NULL; |
drone->autoSound = kAutoSound_None; |
drone->autoInterest = NULL; |
drone->autoVelocity.x = 0.0; |
drone->autoVelocity.y = 0.0; |
drone->autoVelocity.z = 0.0; |
drone->autoMode = kAutoMode_Idle; |
drone->autoModeTimeout = 0; |
drone->autoDistance = 0.0; |
drone->autoExplosion = 0.0; |
drone->bulletOrigin.x = 0.0; |
drone->bulletOrigin.y = 0.0; |
drone->bulletOrigin.z = 0.0; |
return drone; |
} |
/* ============================================================================= |
* SelfDrone_New (external) |
* |
* Creates a new drone whose movement pattern is defined by user controls. |
* ========================================================================== */ |
TDroneObject SelfDrone_New( |
void) |
{ |
TDroneObject drone; |
// Create the basic drone |
drone = Drone_New(kDroneOrder_Self); |
assert(drone != NULL); |
// Fill in the fields |
drone->moveMethod = SelfDrone_Move; |
Q3Vector3D_Scale(&drone->direction, SELF_DRONE_INITIAL_SPEED, &drone->autoVelocity); |
// Validate it |
drone->thumbprint = kThumbprint_SelfDrone; |
return drone; |
} |
// **************************** GetSSpFilterVersion **************************** |
// Finds the manufacturer and version number of the SoundSprocket filter that |
// may be installed. inManufacturer should be the manufacturer code specified |
// at the installation time, which may be zero to allow any manufacturer. |
// If no error is encountered, outManufacturer is set to the actual manufacturer |
// code and outMajorVersion and outMinorVersion are set to the component |
// specification level and manufacturer's implementation revision, respectively. |
static OSStatus GetSSpFilterVersion( |
OSType inManufacturer, |
OSType* outManufacturer, |
UInt32* outMajorVersion, |
UInt32* outMinorVersion) |
{ |
OSStatus err; |
ComponentDescription description; |
Component componentRef; |
UInt32 vers; |
// Set up the component description |
description.componentType = kSoundEffectsType; |
description.componentSubType = kSSpLocalizationSubType; |
description.componentManufacturer = inManufacturer; |
description.componentFlags = 0; |
description.componentFlagsMask = 0; |
// Find a component matching the description |
componentRef = FindNextComponent(nil, &description); |
if (componentRef == nil) return couldntGetRequiredComponent; |
// Get the component description (for the manufacturer code) |
err = GetComponentInfo(componentRef, &description, nil, nil, nil); |
if (err != noErr) return err; |
// Get the version composite |
vers = (UInt32) GetComponentVersion((ComponentInstance) componentRef); |
// Return the results |
*outManufacturer = description.componentManufacturer; |
*outMajorVersion = HiWord(vers); |
*outMinorVersion = LoWord(vers); |
return noErr; |
} |
/* ============================================================================= |
* AutoDrone_New (external) |
* |
* Creates a new drone whose movement pattern is under automatic control. |
* ========================================================================== */ |
TDroneObject AutoDrone_New( |
TDroneObject inDroneOfInterest) |
{ |
OSStatus err; |
TDroneObject drone; |
TQ3Vector3D orientation; |
SoundComponentLink link; |
OSType manufacturer; |
UInt32 majorVersion; |
UInt32 minorVersion; |
assert(inDroneOfInterest != NULL && IS_DRONE(inDroneOfInterest)); |
// Create the basic drone |
drone = Drone_New(kDroneOrder_Auto); |
assert(drone != NULL); |
// Fill in the fields |
drone->moveMethod = AutoDrone_Move; |
drone->updateSoundMethod = AutoDrone_UpdateSound; |
drone->submitMethod = AutoDrone_Submit; |
drone->pickSubmitMethod = AutoDrone_PickSubmit; |
drone->hitMethod = AutoDrone_Hit; |
// Allocate the sound channel and set up for 3D localized sound |
drone->autoSndChannel = NULL; |
SndNewChannel(&drone->autoSndChannel, sampledSynth, initMono, NULL); |
assert(drone->autoSndChannel != NULL); |
SSpSource_New(&drone->autoSource); |
assert(drone->autoSource != NULL); |
link.description.componentType = kSoundEffectsType; |
link.description.componentSubType = kSSpLocalizationSubType; |
link.description.componentManufacturer = 0; |
link.description.componentFlags = 0; |
link.description.componentFlagsMask = 0; |
link.mixerID = nil; |
link.linkID = nil; |
SndSetInfo(drone->autoSndChannel, siPreMixerSoundComponent, &link); |
// Verify that the right version filter was installed |
if (gDroneAutoCheckFilterVersion) |
{ |
err = GetSSpFilterVersion( |
link.description.componentManufacturer, |
&manufacturer, |
&majorVersion, |
&minorVersion); |
if (err != noErr) |
{ |
// Filter must not be installed |
// Note: A normal application would bail on 3D sound here |
StopAlert(kAlrtID_FilterNotInstalled, NULL); |
} |
else |
{ |
// The major version represents the component specification level |
if (majorVersion < 1) |
{ |
//¥ if we couldn't handle some old version, we could bail here. |
StopAlert(kAlrtID_FilterVersion, NULL); |
// Note: A normal application would bail on 3D sound here |
gSoundOn = false; |
} |
else |
{ |
// The minor version specifies the manufacturer's implementation revision |
//¥ could do something here is we needed to handle tweaks for specific |
//¥ manufacturers or versions. |
} |
} |
gDroneAutoCheckFilterVersion = false; |
} |
if (gSoundOn) |
{ |
// The sound is loudest out the back of the model |
Q3Vector3D_Set(&orientation, -1.0, 0.0, 0.0); |
SSpSource_SetOrientation(drone->autoSource, &orientation); |
} |
drone->autoInterest = inDroneOfInterest; |
drone->geometry = Q3Shared_GetReference(gDroneAutoGeometry); |
drone->position.x += Random()*0.0001 + AUTO_DRONE_LEAD; |
drone->position.y += Random()*0.0001; |
drone->position.z += Random()*0.0001; |
drone->autoVelocity.x += Random()*0.0001; |
drone->autoVelocity.y += Random()*0.0001; |
drone->autoVelocity.z += Random()*0.0001; |
// Validate it |
drone->thumbprint = kThumbprint_AutoDrone; |
return drone; |
} |
/* ============================================================================= |
* BulletDrone_New (external) |
* |
* Creates a new drone whose behavior is projectile. |
* ========================================================================== */ |
TDroneObject BulletDrone_New( |
const TQ3Point3D* inPosition, |
const TQ3Vector3D* inDirection) |
{ |
TDroneObject drone; |
assert(inPosition != NULL); |
assert(inDirection != NULL); |
// Create the basic drone |
drone = Drone_New(kDroneOrder_Bullet); |
assert(drone != NULL); |
// Fill in the fields |
drone->moveMethod = BulletDrone_Move; |
drone->submitMethod = BulletDrone_Submit; |
drone->position = *inPosition; |
drone->direction = *inDirection; |
drone->bulletOrigin = *inPosition; |
// Validate it |
drone->thumbprint = kThumbprint_BulletDrone; |
return drone; |
} |
/* ============================================================================= |
* Drone_Dispose (external) |
* |
* Disposes of the drone. |
* ========================================================================== */ |
void Drone_Dispose( |
TDroneObject inDrone) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
// Unlink it from the list |
if (inDrone->prev != NULL) |
{ |
inDrone->prev->next = inDrone->next; |
} |
else |
{ |
gDroneList = inDrone->next; |
} |
if (inDrone->next != NULL) |
{ |
inDrone->next->prev = inDrone->prev; |
} |
// Dispose stuff |
if (inDrone->geometry != NULL) |
{ |
Q3Object_Dispose(inDrone->geometry); |
inDrone->geometry = NULL; |
} |
// Free the sound channel |
//¥ This rightly belongs in AutoDrone_Dispose |
if (inDrone->autoSource != NULL) |
{ |
SSpSource_Dispose(inDrone->autoSource); |
inDrone->autoSource = NULL; |
} |
if (inDrone->autoSndChannel != NULL) |
{ |
SndDisposeChannel(inDrone->autoSndChannel, true); |
inDrone->autoSndChannel = NULL; |
} |
// Dispose of the memory |
inDrone->thumbprint = kThumbprint_Dead; |
free(inDrone); |
} |
/* ============================================================================= |
* Drone_Next (external) |
* |
* If inDrone is NULL, then the head of the drone list is returned. If inDrone |
* is non-NULL, then the next drone in the list is returned. If inDrone is the |
* last drone, then NULL is returned. |
* ========================================================================== */ |
TDroneObject Drone_Next( |
TDroneObject inDrone) |
{ |
TDroneObject result; |
if (inDrone != NULL) |
{ |
assert(IS_DRONE(inDrone)); |
result = inDrone->next; |
} |
else |
{ |
result = gDroneList; |
} |
return result; |
} |
/* ============================================================================= |
* Drone_Move (external) |
* |
* Moves the drone forward one time step. This may mark the drone for death. |
* ========================================================================== */ |
void Drone_Move( |
TDroneObject inDrone) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
// Move the drone by its own rules |
assert(inDrone->moveMethod != NULL); |
(inDrone->moveMethod)(inDrone); |
// Drone is still alive -- compute the velocity and acceleration |
Q3Point3D_Subtract(&inDrone->position, &inDrone->position1, &inDrone->velocity); |
Q3Vector3D_Scale(&inDrone->velocity, gGameFramesPerSecond, &inDrone->velocity); |
inDrone->position1 = inDrone->position; |
Q3Vector3D_Subtract(&inDrone->velocity, &inDrone->velocity1, &inDrone->acceleration); |
Q3Vector3D_Scale(&inDrone->acceleration, gGameFramesPerSecond, &inDrone->acceleration); |
inDrone->velocity1 = inDrone->velocity; |
// Reorthogonalize the up and cross vectors |
assert(fabs(Q3Vector3D_Length(&inDrone->direction) - 1.0) < 0.05); |
Q3Vector3D_Cross(&inDrone->direction, &inDrone->up, &inDrone->cross); |
Q3Vector3D_Normalize(&inDrone->cross, &inDrone->cross); |
Q3Vector3D_Cross(&inDrone->cross, &inDrone->direction, &inDrone->up); |
} |
/* ============================================================================= |
* AutoDrone_Move (internal) |
* |
* Moves the drone forward one time step. The autopilot drone has a constant |
* thrust along its direction of orientation. The direction is controlled to |
* point just in front of the drone of interest. |
* ========================================================================== */ |
void AutoDrone_Move( |
TDroneObject inDrone) |
{ |
TQ3Vector3D newDirection; |
TQ3Vector3D v1; |
TQ3Vector3D v2; |
TQ3Point3D target; |
float distance; |
float turnRate; |
float limit; |
TAutoSound newSound; |
SndCommand sndCommand; |
long base; |
TQ3Matrix4x4 matrix; |
assert(inDrone != NULL && IS_AUTO_DRONE(inDrone)); |
// Figure out new direction |
if (inDrone->autoMode == kAutoMode_Explosion) |
{ |
// Point the explosion geometry at the camera |
//¥ NOTE: For now, we assume that the camera is at the drone of interest |
//¥ This is wrong for two reasons. First, the camera could actually be |
//¥ elsewhere. Second, this assumes that the drone of interest moves |
//¥ before this drone. |
Q3Point3D_Subtract( |
&inDrone->autoInterest->position, |
&inDrone->position, |
&newDirection); |
Q3Vector3D_Normalize(&newDirection, &inDrone->direction); |
} |
else |
{ |
// Find a point in front of the drone of interest |
assert(IS_DRONE(inDrone->autoInterest)); |
Q3Vector3D_Scale(&inDrone->autoInterest->direction, AUTO_DRONE_LEAD, &v1); |
Q3Point3D_Vector3D_Add(&inDrone->autoInterest->position, &v1, &target); |
// Point toward the target |
Q3Point3D_Subtract(&target, &inDrone->position, &newDirection); |
Q3Vector3D_Normalize(&newDirection, &newDirection); |
// Limit the turn rate |
turnRate = acosf(Q3Vector3D_Dot(&inDrone->direction, &newDirection)); |
limit = AUTO_DRONE_TURN_RATE*gGameInterval; |
if (turnRate > limit) |
{ |
// Limit the turn |
// Note: this should actually be spherical interpolation -- but linear is close enough |
turnRate = limit/turnRate; |
Q3Vector3D_Scale(&inDrone->direction, 1.0-turnRate, &v1); |
Q3Vector3D_Scale(&newDirection, turnRate, &v2); |
Q3Vector3D_Add(&v1, &v2, &inDrone->direction); |
Q3Vector3D_Normalize(&inDrone->direction, &inDrone->direction); |
} |
else |
{ |
// It's OK to make the desired turn |
inDrone->direction = newDirection; |
} |
} |
// Figure out new position |
switch (inDrone->autoMode) |
{ |
case kAutoMode_Idle: // Start a burn if we are getting farther from the target |
// Start burn if we are getting farther from the target |
distance = Q3Point3D_Distance(&inDrone->position, &target); |
if (inDrone->autoDistance > distance) |
{ |
// Getting closer to target -- don't change |
inDrone->autoDistance = distance; |
} |
else |
{ |
// Getting farther from target -- start a burn |
inDrone->autoMode = kAutoMode_Burn; |
inDrone->autoModeTimeout = TickCount() + (unsigned long) (AUTO_DRONE_BURN_TIME*60); |
} |
break; |
case kAutoMode_Burn: // Accelerate toward the target |
// Continue the burn? |
if (TickCount() <= inDrone->autoModeTimeout) |
{ |
// Still burning -- change the velocity by accelerating toward the target |
Q3Vector3D_Scale(&inDrone->direction, gGameInterval*AUTO_DRONE_ACCEL, &v1); |
Q3Vector3D_Add(&inDrone->autoVelocity, &v1, &inDrone->autoVelocity); |
} |
else |
{ |
// Switch to rest mode |
inDrone->autoMode = kAutoMode_Rest; |
inDrone->autoModeTimeout = TickCount() + (unsigned long) (AUTO_DRONE_REST_TIME*60); |
} |
break; |
case kAutoMode_Rest: // Don't use the engine for a while |
// Continue the rest? |
if (TickCount() <= inDrone->autoModeTimeout) |
{ |
// Still resting |
// (do nothing) |
} |
else |
{ |
// Switch to idle mode |
inDrone->autoMode = kAutoMode_Idle; |
inDrone->autoDistance = Q3Point3D_Distance(&inDrone->position, &target); |
} |
break; |
case kAutoMode_Explosion: // Show the explosion for a while |
// Continue the explosion? |
inDrone->autoExplosion += gGameInterval/AUTO_DRONE_EXPLOSION_TIME; |
if (inDrone->autoExplosion <= 1.0) |
{ |
// Still exploding |
inDrone->autoVelocity.x = |
inDrone->autoVelocity.y = |
inDrone->autoVelocity.z = 0.0; |
} |
else |
{ |
// Kill the drone |
Drone_SetMark(inDrone, true); |
} |
break; |
default: |
assert(0); |
} |
// Move along the new velocity vector |
Q3Vector3D_Scale(&inDrone->autoVelocity, gGameInterval, &v1); |
Q3Point3D_Vector3D_Add(&inDrone->position, &v1, &inDrone->position); |
if (gSoundOn) |
{ |
// Choose the next sound to play |
switch (inDrone->autoMode) |
{ |
case kAutoMode_Idle: |
case kAutoMode_Rest: |
newSound = kAutoSound_Idle; |
break; |
case kAutoMode_Burn: |
newSound = kAutoSound_Burn; |
break; |
break; |
case kAutoMode_Explosion: |
newSound = kAutoSound_Explosion; |
break; |
default: |
assert(0); |
} |
// Change the sound |
if (inDrone->autoSound != newSound) |
{ |
// Stop the old sound |
if (inDrone->autoSound != kAutoSound_None) |
{ |
sndCommand.cmd = quietCmd; |
sndCommand.param1 = 0; |
sndCommand.param2 = 0; |
SndDoImmediate(inDrone->autoSndChannel, &sndCommand); |
} |
inDrone->autoSound = newSound; |
// Play the new sound |
switch (inDrone->autoSound) |
{ |
case kAutoSound_None: |
base = 0; |
break; |
case kAutoSound_Idle: |
base = (long) *gDroneAutoSndIdle + gDroneAutoSndIdleOffset; |
SSpSource_SetAngularAttenuation(inDrone->autoSource, 0.0, 0.0); |
SSpSource_SetReferenceDistance(inDrone->autoSource, AUTO_DRONE_IDLE_REF_DIST); |
break; |
case kAutoSound_Burn: |
base = (long) *gDroneAutoSndBurn + gDroneAutoSndBurnOffset; |
SSpSource_SetAngularAttenuation(inDrone->autoSource, 1.5, -12.0); |
SSpSource_SetReferenceDistance(inDrone->autoSource, AUTO_DRONE_BURN_REF_DIST); |
break; |
case kAutoSound_Explosion: |
base = (long) *gDroneAutoSndExplosion + gDroneAutoSndExplosionOffset; |
SSpSource_SetAngularAttenuation(inDrone->autoSource, 0.0, 0.0); |
SSpSource_SetReferenceDistance(inDrone->autoSource, AUTO_DRONE_EXPL_REF_DIST); |
break; |
default: |
assert(0); |
} |
if (base != 0) |
{ |
// Install the sound |
sndCommand.cmd = soundCmd; |
sndCommand.param1 = 0; |
sndCommand.param2 = base; |
SndDoImmediate(inDrone->autoSndChannel, &sndCommand); |
// Play it indefinitely |
sndCommand.cmd = freqCmd; |
sndCommand.param1 = 0; |
sndCommand.param2 = 60; |
SndDoImmediate(inDrone->autoSndChannel, &sndCommand); |
} |
} |
// Change the sound source location |
Drone_GetMatrix(inDrone, &matrix); |
SSpSource_SetTransform(inDrone->autoSource, &matrix); |
} |
} |
/* ============================================================================= |
* BulletDrone_Move (internal) |
* |
* Moves the drone forward one time step. |
* ========================================================================== */ |
void BulletDrone_Move( |
TDroneObject inDrone) |
{ |
TQ3Vector3D v; |
float prevDistance; |
float currDistance; |
TQ3CameraPlacement placement; |
TDroneObject target; |
unsigned long count; |
unsigned long index; |
assert(inDrone != NULL && IS_BULLET_DRONE(inDrone)); |
// Move the bullet |
prevDistance = Q3Point3D_Distance(&inDrone->position, &inDrone->bulletOrigin); |
Q3Vector3D_Scale(&inDrone->direction, gGameInterval*BULLET_DRONE_SPEED, &v); |
Q3Point3D_Vector3D_Add(&inDrone->position, &v, &inDrone->position); |
currDistance = Q3Point3D_Distance(&inDrone->position, &inDrone->bulletOrigin); |
// Time to expire? |
if (currDistance > BULLET_DRONE_LIMIT) |
{ |
// Mark the drone to die |
Drone_SetMark(inDrone, true); |
} |
else |
{ |
// Set up for collision detection |
placement.cameraLocation = inDrone->bulletOrigin; |
placement.upVector = inDrone->up; |
Q3Point3D_Vector3D_Add(&inDrone->bulletOrigin, &inDrone->direction, &placement.pointOfInterest); |
Q3Camera_SetPlacement(gDroneCamera, &placement); |
// Collision detection with all target drones |
Q3View_StartPicking(gDroneView, gDronePick); |
do |
{ |
for (target = Drone_Next(NULL); target != NULL; target = Drone_Next(target)) |
{ |
// Submit the drone geometry, along with a PickID that is the object reference |
Q3PickIDStyle_Submit((unsigned long) target, gDroneView); |
Drone_PickSubmit(target, gDroneView); |
} |
} |
while (Q3View_EndPicking(gDroneView) == kQ3ViewStatusRetraverse); |
// Check the hit list |
Q3Pick_GetNumHits(gDronePick, &count); |
for (index = 0; index < count; index++) |
{ |
UInt32 pickGood, maskGood; |
Q3Pick_GetPickDetailData(gDronePick, index, kQ3PickDetailMaskPickID, &pickGood); |
Q3Pick_GetPickDetailData(gDronePick, index, kQ3PickDetailMaskDistance, &maskGood); |
if (pickGood && maskGood) |
{ |
Q3Pick_GetPickDetailData(gDronePick, index, kQ3PickDetailMaskPickID, &target); |
if (target != NULL && IS_DRONE(target)) |
{ |
// Got a valid hit -- check its range |
//¥ Should it be a bullet or a laser? |
// if ((1 || prevDistance <= hitData.distance) && hitData.distance <= currDistance) |
if (true) |
{ |
// Hit it! |
Drone_Hit(target); |
// Kill the bullet |
Drone_SetMark(inDrone, true); |
break; |
} |
} |
} |
// Q3Hit_EmptyData(&hitData); |
} |
// Empty out the pick hits |
Q3Pick_EmptyHitList(gDronePick); |
} |
} |
/* ============================================================================= |
* Drone_UpdateSound (external) |
* |
* Updates localized sounds for this drone. The default method does nothing. |
* ========================================================================== */ |
void Drone_UpdateSound( |
TDroneObject inDrone) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
if (inDrone->updateSoundMethod != NULL) |
{ |
(inDrone->updateSoundMethod)(inDrone); |
} |
} |
/* ============================================================================= |
* AutoDrone_UpdateSound (external) |
* |
* Updates localized sounds for this autopilot drone. |
* ========================================================================== */ |
void AutoDrone_UpdateSound( |
TDroneObject inDrone) |
{ |
SSpLocalizationData snd3DInfo; |
assert(inDrone != NULL && IS_AUTO_DRONE(inDrone)); |
if (gSoundOn) |
{ |
SSpSource_CalcLocalization(inDrone->autoSource, Sound_GetListener(), &snd3DInfo); |
SndSetInfo(inDrone->autoSndChannel, siSSpLocalization, &snd3DInfo); |
} |
} |
/* ============================================================================= |
* Drone_Submit (external) |
* |
* Submits the drone for drawing. |
* ========================================================================== */ |
void Drone_Submit( |
TDroneObject inDrone, |
Boolean inHUDVisible, |
TQ3ViewObject inView) |
{ |
TQ3Matrix4x4 matrix; |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
if (inDrone->submitMethod != NULL) |
{ |
// Use the submit method |
(inDrone->submitMethod)(inDrone, inHUDVisible, inView); |
} |
else if (inDrone->geometry != NULL) |
{ |
// Submit the geometry |
Drone_GetMatrix(inDrone, &matrix); |
Q3Push_Submit(inView); |
Q3MatrixTransform_Submit(&matrix, inView); |
Q3Object_Submit(inDrone->geometry, inView); |
Q3Pop_Submit(inView); |
} |
} |
/* ============================================================================= |
* AutoDrone_Submit (internal) |
* |
* Submits the bullet drone for drawing. |
* ========================================================================== */ |
void AutoDrone_Submit( |
TDroneObject inDrone, |
Boolean inHUDVisible, |
TQ3ViewObject inView) |
{ |
TQ3Matrix4x4 matrix; |
TQ3ColorRGB transparency; |
TQ3Point3D position; |
TQ3Vector3D direction; |
TQ3Vector3D up; |
TQ3Vector3D right; |
TQ3Vector3D v; |
TQ3Vector3D v1; |
TQ3Vector3D v2; |
float height; |
TQ3GeometryObject marker; |
assert(inDrone != NULL && IS_AUTO_DRONE(inDrone)); |
assert(inView != NULL); |
// Draw the drone |
Q3Push_Submit(inView); |
Drone_GetMatrix(inDrone, &matrix); |
Q3MatrixTransform_Submit(&matrix, inView); |
switch (inDrone->autoMode) |
{ |
case kAutoMode_Burn: |
Q3Object_Submit(gDroneAutoBurnGeometry, inView); |
/* FALL THROUGH TO SUBMIT DRONE GEOMETRY */ |
case kAutoMode_Rest: |
case kAutoMode_Idle: |
Q3Object_Submit(inDrone->geometry, inView); |
break; |
case kAutoMode_Explosion: |
// Grow the explosion |
v.x = v.y = v.z = (1.0-AUTO_DRONE_MIN_SCALE)*inDrone->autoExplosion + AUTO_DRONE_MIN_SCALE; |
Q3ScaleTransform_Submit(&v, inView); |
// Fade at the end |
if (inDrone->autoExplosion > (1.0-AUTO_DRONE_FADE_TIME)) |
{ |
transparency.r = |
transparency.g = |
transparency.b = (-1.0/AUTO_DRONE_FADE_TIME)*inDrone->autoExplosion + (1.0/AUTO_DRONE_FADE_TIME); |
Q3Attribute_Submit(kQ3AttributeTypeTransparencyColor, &transparency, inView); |
} |
// Submit the explosion geometry |
Q3Object_Submit(gDroneAutoExplosionGeometry, inView); |
break; |
default: |
assert(0); |
} |
Q3Pop_Submit(inView); |
// Draw the HUD marker for the drone |
if (inHUDVisible && inDrone->autoMode != kAutoMode_Explosion) |
{ |
Display_GetViewerPosition(&position, &direction, &up); |
Q3Vector3D_Cross(&direction, &up, &right); |
Q3Point3D_Subtract(&inDrone->position, &position, &v); |
Q3Vector3D_Scale(&up, HUD_SCALE*Q3Vector3D_Dot(&direction, &v), &v1); |
Q3Vector3D_Scale(&right, HUD_SCALE*Q3Vector3D_Dot(&right, &v), &v2); |
Q3Point3D_Vector3D_Add(&position, &direction, &position); |
Q3Point3D_Vector3D_Add(&position, &v1, &position); |
Q3Point3D_Vector3D_Add(&position, &v2, &position); |
Q3Vector3D_Normalize(&v, &v); |
height = Q3Vector3D_Dot(&up, &v); |
if (height >= HUD_HEIGHT) |
{ |
marker = gDroneAutoMarkerAbove; |
} |
else if (height <= -HUD_HEIGHT) |
{ |
marker = gDroneAutoMarkerBelow; |
} |
else |
{ |
marker = gDroneAutoMarkerEqual; |
} |
Q3Marker_SetPosition(marker, &position); |
Q3Object_Submit(marker, inView); |
} |
} |
/* ============================================================================= |
* BulletDrone_Submit (internal) |
* |
* Submits the bullet drone for drawing. |
* ========================================================================== */ |
void BulletDrone_Submit( |
TDroneObject inDrone, |
Boolean inHUDVisible, |
TQ3ViewObject inView) |
{ |
TQ3LineData lineData; |
assert(inDrone != NULL && IS_BULLET_DRONE(inDrone)); |
assert(inView != NULL); |
lineData.vertices[0].point = inDrone->bulletOrigin; |
lineData.vertices[0].attributeSet = NULL; |
lineData.vertices[1].point = inDrone->position; |
lineData.vertices[1].attributeSet = NULL; |
lineData.lineAttributeSet = NULL; |
Q3Push_Submit(inView); |
Q3Object_Submit(gDroneNULLIllumination, inView); |
Q3Object_Submit(gDroneBulletColor, inView); |
Q3Line_Submit(&lineData, inView); |
Q3Pop_Submit(inView); |
} |
/* ============================================================================= |
* Drone_PickSubmit (internal) |
* |
* Submits the drone for picking against a bullet. It forwards to the actual |
* drone hit method, if any. |
* ========================================================================== */ |
void Drone_PickSubmit( |
TDroneObject inDrone, |
TQ3ViewObject inView) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
if (inDrone->pickSubmitMethod != NULL) |
{ |
(*inDrone->pickSubmitMethod)(inDrone, inView); |
} |
} |
/* ============================================================================= |
* AutoDrone_PickSubmit (internal) |
* |
* Submits the autopilot drone for picking against a bullet. |
* ========================================================================== */ |
void AutoDrone_PickSubmit( |
TDroneObject inDrone, |
TQ3ViewObject inView) |
{ |
TQ3Matrix4x4 matrix; |
assert(inDrone != NULL && IS_AUTO_DRONE(inDrone)); |
assert(inView != NULL); |
// Draw the drone |
if (inDrone->autoMode != kAutoMode_Explosion) |
{ |
Q3Push_Submit(inView); |
Drone_GetMatrix(inDrone, &matrix); |
Q3MatrixTransform_Submit(&matrix, inView); |
Q3Object_Submit(gDroneAutoBurnGeometry, inView); |
Q3Pop_Submit(inView); |
} |
} |
/* ============================================================================= |
* Drone_Hit (internal) |
* |
* Called when this drone is hit. It forwards to the actual drone hit method, |
* if any. |
* ========================================================================== */ |
void Drone_Hit( |
TDroneObject inDrone) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
if (inDrone->hitMethod != NULL) |
{ |
(*inDrone->hitMethod)(inDrone); |
} |
} |
/* ============================================================================= |
* AutoDrone_Hit (internal) |
* |
* Called when this autopilot drone is hit. It puts the drone into |
* explosion mode. |
* ========================================================================== */ |
void AutoDrone_Hit( |
TDroneObject inDrone) |
{ |
assert(inDrone != NULL && IS_AUTO_DRONE(inDrone)); |
inDrone->autoMode = kAutoMode_Explosion; |
inDrone->autoExplosion = 0.0; |
} |
/* ============================================================================= |
* Drone_SetMark (external) |
* |
* Changes the drone's mark to the given value. The mark is used to indicate |
* which drones should die. |
* ========================================================================== */ |
void Drone_SetMark( |
TDroneObject inDrone, |
Boolean inMark) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
inDrone->mark = inMark; |
} |
/* ============================================================================= |
* Drone_GetMark (external) |
* |
* Returns the drone's mark. |
* ========================================================================== */ |
Boolean Drone_GetMark( |
TDroneObject inDrone) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
return inDrone->mark; |
} |
/* ============================================================================= |
* Drone_GetPosition (external) |
* |
* Returns the current position in outPosition. |
* ========================================================================== */ |
void Drone_GetPosition( |
TDroneObject inDrone, |
TQ3Point3D* outPosition) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
assert(outPosition != NULL); |
*outPosition = inDrone->position; |
} |
/* ============================================================================= |
* Drone_GetVelocity (external) |
* |
* Returns the current velocity in outVelocity |
* ========================================================================== */ |
void Drone_GetVelocity( |
TDroneObject inDrone, |
TQ3Vector3D* outVelocity) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
assert(outVelocity != NULL); |
*outVelocity = inDrone->velocity; |
} |
/* ============================================================================= |
* Drone_GetDirection (external) |
* |
* Returns the current direction in outDirection. |
* ========================================================================== */ |
void Drone_GetDirection( |
TDroneObject inDrone, |
TQ3Vector3D* outDirection) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
assert(outDirection != NULL); |
*outDirection = inDrone->direction; |
} |
/* ============================================================================= |
* Drone_GetUp (external) |
* |
* Returns the current up vector in outUp. |
* ========================================================================== */ |
void Drone_GetUp( |
TDroneObject inDrone, |
TQ3Vector3D* outUp) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
assert(outUp != NULL); |
*outUp = inDrone->up; |
} |
/* ============================================================================= |
* Drone_GetMatrix (external) |
* |
* Returns the matrix that transforms to the drone position and orientation. |
* ========================================================================== */ |
void Drone_GetMatrix( |
TDroneObject inDrone, |
TQ3Matrix4x4* outMatrix) |
{ |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
assert(outMatrix != NULL); |
outMatrix->value[0][0] = inDrone->direction.x; |
outMatrix->value[0][1] = inDrone->direction.y; |
outMatrix->value[0][2] = inDrone->direction.z; |
outMatrix->value[1][0] = inDrone->up.x; |
outMatrix->value[1][1] = inDrone->up.y; |
outMatrix->value[1][2] = inDrone->up.z; |
outMatrix->value[2][0] = inDrone->cross.x; |
outMatrix->value[2][1] = inDrone->cross.y; |
outMatrix->value[2][2] = inDrone->cross.z; |
outMatrix->value[3][0] = inDrone->position.x; |
outMatrix->value[3][1] = inDrone->position.y; |
outMatrix->value[3][2] = inDrone->position.z; |
outMatrix->value[0][3] = 0.0; |
outMatrix->value[1][3] = 0.0; |
outMatrix->value[2][3] = 0.0; |
outMatrix->value[3][3] = 1.0; |
} |
/* ============================================================================= |
* Drone_Fire (external) |
* |
* Called each time the fire button is pressed. |
* ========================================================================== */ |
void Drone_Fire( |
TDroneObject inDrone) |
{ |
TQ3Vector3D up; |
TQ3Vector3D cross; |
TQ3Point3D origin; |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
// Find the offsets |
Q3Vector3D_Scale(&inDrone->up, BULLET_DRONE_OFFSET, &up); |
Q3Vector3D_Scale(&inDrone->cross, BULLET_DRONE_OFFSET, &cross); |
// Fire one |
Q3Point3D_Vector3D_Subtract(&inDrone->position, &up, &origin); |
Q3Point3D_Vector3D_Subtract(&origin, &cross, &origin); |
BulletDrone_New(&origin, &inDrone->direction); |
// Fire two |
Q3Point3D_Vector3D_Subtract(&inDrone->position, &up, &origin); |
Q3Point3D_Vector3D_Add(&origin, &cross, &origin); |
BulletDrone_New(&origin, &inDrone->direction); |
} |
/* ============================================================================= |
* Drone_Silence (external) |
* |
* Silences any drone sounds. |
* ========================================================================== */ |
void Drone_Silence( |
TDroneObject inDrone) |
{ |
SndCommand sndCommand; |
assert(inDrone != NULL && IS_DRONE(inDrone)); |
//¥ We should really do this as AutoDrone_Silence, but whatever... |
if (inDrone->autoSndChannel != NULL) |
{ |
// Purge any pending commands |
sndCommand.cmd = flushCmd; |
sndCommand.param1 = 0; |
sndCommand.param2 = 0; |
SndDoImmediate(inDrone->autoSndChannel, &sndCommand); |
// Quiet the current sound |
sndCommand.cmd = quietCmd; |
sndCommand.param1 = 0; |
sndCommand.param2 = 0; |
SndDoImmediate(inDrone->autoSndChannel, &sndCommand); |
} |
} |
/* ============================================================================= |
* SelfDrone_Move (internal) |
* |
* Moves the drone forward one time step. |
* ========================================================================== */ |
void SelfDrone_Move( |
TDroneObject inDrone) |
{ |
TQ3Vector3D v; |
assert(inDrone != NULL && IS_SELF_DRONE(inDrone)); |
// Move along the velocity vector |
Q3Vector3D_Scale(&inDrone->autoVelocity, gGameInterval, &v); |
Q3Point3D_Vector3D_Add(&inDrone->position, &v, &inDrone->position); |
#if SELF_DRONE_HAS_FRICTION |
// automatically slow ship down if no thrust (like friction) |
Q3Vector3D_Scale(&inDrone->autoVelocity, SELF_DRONE_FRICTION, &inDrone->autoVelocity); |
#endif |
} |
/* ============================================================================= |
* SelfDrone_Thrust (external) |
* |
* Increases the velocity of the drone. |
* ========================================================================== */ |
void SelfDrone_Thrust( |
TDroneObject inDrone, |
float inThrust) |
{ |
TQ3Vector3D v; |
assert(inDrone != NULL && IS_SELF_DRONE(inDrone)); |
// change the velocity by accelerating inThrust amount |
Q3Vector3D_Scale(&inDrone->direction, inThrust*SELF_DRONE_MAX_ACCEL, &v); |
Q3Vector3D_Add(&inDrone->autoVelocity, &v, &inDrone->autoVelocity); |
} |
/* ============================================================================= |
* SelfDrone_DampVelocity (external) |
* |
* Increases the velocity of the drone. |
* ========================================================================== */ |
void SelfDrone_DampVelocity( |
TDroneObject inDrone, |
float inDampingPercentage) |
{ |
assert(inDrone != NULL && IS_SELF_DRONE(inDrone)); |
// automatically slow ship down if no thrust (like friction) |
Q3Vector3D_Scale(&inDrone->autoVelocity, inDampingPercentage, &inDrone->autoVelocity); |
} |
/* ============================================================================= |
* SelfDrone_AllStop (external) |
* |
* Increases the velocity of the drone. |
* ========================================================================== */ |
void SelfDrone_InstantStop( |
TDroneObject inDrone) |
{ |
assert(inDrone != NULL && IS_SELF_DRONE(inDrone)); |
// automatically slow ship down if no thrust (like friction) |
Q3Vector3D_Scale(&inDrone->autoVelocity, 0.0, &inDrone->autoVelocity); |
} |
/* ============================================================================= |
* SelfDrone_Pitch (external) |
* |
* Changes the direction of the ship by the given angles, in radians. |
* ========================================================================== */ |
void SelfDrone_Pitch( |
TDroneObject inDrone, |
float inPitchAngle) |
{ |
TQ3Vector3D v1; |
TQ3Vector3D v2; |
assert(inDrone != NULL && IS_SELF_DRONE(inDrone)); |
if (inPitchAngle != 0.0) |
{ |
Q3Vector3D_Scale(&inDrone->direction, cosf(inPitchAngle), &v1); |
Q3Vector3D_Scale(&inDrone->up, sinf(inPitchAngle), &v2); |
Q3Vector3D_Add(&v1, &v2, &inDrone->direction); |
} |
} |
/* ============================================================================= |
* SelfDrone_Yaw (external) |
* |
* Changes the direction of the ship by the given angles, in radians. |
* ========================================================================== */ |
void SelfDrone_Yaw( |
TDroneObject inDrone, |
float inYawAngle) |
{ |
TQ3Vector3D v1; |
TQ3Vector3D v2; |
assert(inDrone != NULL && IS_SELF_DRONE(inDrone)); |
if (inYawAngle != 0.0) |
{ |
Q3Vector3D_Scale(&inDrone->direction, cosf(inYawAngle), &v1); |
Q3Vector3D_Scale(&inDrone->cross, sinf(inYawAngle), &v2); |
Q3Vector3D_Add(&v1, &v2, &inDrone->direction); |
} |
} |
/* ============================================================================= |
* SelfDrone_Roll (external) |
* |
* Changes the direction of the ship by the given angles, in radians. |
* ========================================================================== */ |
void SelfDrone_Roll( |
TDroneObject inDrone, |
float inRollAngle) |
{ |
TQ3Vector3D v1; |
TQ3Vector3D v2; |
assert(inDrone != NULL && IS_SELF_DRONE(inDrone)); |
if (inRollAngle != 0.0) |
{ |
Q3Vector3D_Scale(&inDrone->up, cosf(inRollAngle), &v1); |
Q3Vector3D_Scale(&inDrone->cross, sinf(inRollAngle), &v2); |
Q3Vector3D_Add(&v1, &v2, &inDrone->up); |
} |
} |
/* |
{ |
matrix = BuildRotationMatrix (angle, x, y, z) |
up = Multiply (up, matrix); |
normalize? |
} |
*/ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-14