1145 lines
22 KiB
Objective-C
1145 lines
22 KiB
Objective-C
/*
|
|
|
|
Entity.m
|
|
|
|
Oolite
|
|
Copyright (C) 2004-2013 Giles C Williams and contributors
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#import "Entity.h"
|
|
#import "EntityOOJavaScriptExtensions.h"
|
|
#import "PlayerEntity.h"
|
|
#import "OOPlanetEntity.h"
|
|
|
|
#import "OOMaths.h"
|
|
#import "Universe.h"
|
|
#import "GameController.h"
|
|
#import "ResourceManager.h"
|
|
#import "OOConstToString.h"
|
|
|
|
#import "CollisionRegion.h"
|
|
|
|
#import "NSScannerOOExtensions.h"
|
|
#import "OODebugFlags.h"
|
|
#import "NSObjectOOExtensions.h"
|
|
|
|
#ifndef NDEBUG
|
|
uint32_t gLiveEntityCount = 0;
|
|
size_t gTotalEntityMemory = 0;
|
|
#endif
|
|
|
|
|
|
#ifndef NDEBUG
|
|
static NSString * const kOOLogEntityAddToList = @"entity.linkedList.add";
|
|
static NSString * const kOOLogEntityAddToListError = @"entity.linkedList.add.error";
|
|
static NSString * const kOOLogEntityRemoveFromList = @"entity.linkedList.remove";
|
|
static NSString * const kOOLogEntityRemoveFromListError = @"entity.linkedList.remove.error";
|
|
static NSString * const kOOLogEntityUpdateError = @"entity.linkedList.update.error";
|
|
#endif
|
|
static NSString * const kOOLogEntityVerificationError = @"entity.linkedList.verify.error";
|
|
|
|
|
|
|
|
@interface Entity (OOPrivate)
|
|
|
|
- (BOOL) checkLinkedLists;
|
|
|
|
@end
|
|
|
|
|
|
@implementation Entity
|
|
|
|
- (id) init
|
|
{
|
|
self = [super init];
|
|
if (EXPECT_NOT(self == nil)) return nil;
|
|
|
|
_sessionID = [UNIVERSE sessionID];
|
|
|
|
orientation = kIdentityQuaternion;
|
|
rotMatrix = kIdentityMatrix;
|
|
position = kZeroHPVector;
|
|
|
|
no_draw_distance = 100000.0; // 10 km
|
|
|
|
collidingEntities = [[NSMutableArray alloc] init];
|
|
|
|
scanClass = CLASS_NOT_SET;
|
|
[self setStatus:STATUS_COCKPIT_DISPLAY];
|
|
|
|
spawnTime = [UNIVERSE getTime];
|
|
|
|
isSunlit = YES;
|
|
|
|
atmosphereFogging = [[OOColor colorWithRed: 0.0 green: 0.0 blue: 0.0 alpha: 0.0] retain];
|
|
|
|
#ifndef NDEBUG
|
|
gLiveEntityCount++;
|
|
gTotalEntityMemory += [self oo_objectSize];
|
|
#endif
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
- (void) dealloc
|
|
{
|
|
[UNIVERSE ensureEntityReallyRemoved:self];
|
|
DESTROY(collidingEntities);
|
|
DESTROY(collisionRegion);
|
|
[self deleteJSSelf];
|
|
[self setOwner:nil];
|
|
[atmosphereFogging release];
|
|
|
|
#ifndef NDEBUG
|
|
gLiveEntityCount--;
|
|
gTotalEntityMemory -= [self oo_objectSize];
|
|
#endif
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
|
|
- (NSString *)descriptionComponents
|
|
{
|
|
return [NSString stringWithFormat:@"position: %@ scanClass: %@ status: %@", HPVectorDescription([self position]), OOStringFromScanClass([self scanClass]), OOStringFromEntityStatus([self status])];
|
|
}
|
|
|
|
|
|
- (NSUInteger) sessionID
|
|
{
|
|
return _sessionID;
|
|
}
|
|
|
|
|
|
- (BOOL)isShip
|
|
{
|
|
return isShip;
|
|
}
|
|
|
|
|
|
- (BOOL)isDock
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (BOOL)isStation
|
|
{
|
|
return isStation;
|
|
}
|
|
|
|
|
|
- (BOOL)isSubEntity
|
|
{
|
|
return isSubEntity;
|
|
}
|
|
|
|
|
|
- (BOOL)isPlayer
|
|
{
|
|
return isPlayer;
|
|
}
|
|
|
|
|
|
- (BOOL)isPlanet
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (BOOL)isSun
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (BOOL) isSunlit
|
|
{
|
|
return isSunlit;
|
|
}
|
|
|
|
|
|
- (BOOL) isStellarObject
|
|
{
|
|
return [self isPlanet] || [self isSun];
|
|
}
|
|
|
|
|
|
- (BOOL)isSky
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL)isWormhole
|
|
{
|
|
return isWormhole;
|
|
}
|
|
|
|
|
|
- (BOOL) isEffect
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (BOOL) isVisualEffect
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (BOOL) isWaypoint
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
|
|
- (BOOL) validForAddToUniverse
|
|
{
|
|
NSUInteger mySessionID = [self sessionID];
|
|
NSUInteger currentSessionID = [UNIVERSE sessionID];
|
|
if (EXPECT_NOT(mySessionID != currentSessionID))
|
|
{
|
|
OOLogERR(@"entity.invalidSession", @"Entity %@ from session %lu cannot be added to universe in session %lu. This is an internal error, please report it.", [self shortDescription], mySessionID, currentSessionID);
|
|
return NO;
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
|
|
- (void) addToLinkedLists
|
|
{
|
|
#ifndef NDEBUG
|
|
if (gDebugFlags & DEBUG_LINKED_LISTS)
|
|
OOLog(kOOLogEntityAddToList, @"DEBUG adding entity %@ to linked lists", self);
|
|
#endif
|
|
//
|
|
// insert at the start
|
|
if (UNIVERSE)
|
|
{
|
|
x_previous = nil; x_next = UNIVERSE->x_list_start;
|
|
// move UP the list
|
|
while ((x_next)&&(x_next->position.x - x_next->collision_radius < position.x - collision_radius))
|
|
{
|
|
x_previous = x_next;
|
|
x_next = x_next->x_next;
|
|
}
|
|
if (x_next) x_next->x_previous = self;
|
|
if (x_previous) x_previous->x_next = self;
|
|
else UNIVERSE->x_list_start = self;
|
|
|
|
y_previous = nil; y_next = UNIVERSE->y_list_start;
|
|
// move UP the list
|
|
while ((y_next)&&(y_next->position.y - y_next->collision_radius < position.y - collision_radius))
|
|
{
|
|
y_previous = y_next;
|
|
y_next = y_next->y_next;
|
|
}
|
|
if (y_next) y_next->y_previous = self;
|
|
if (y_previous) y_previous->y_next = self;
|
|
else UNIVERSE->y_list_start = self;
|
|
|
|
z_previous = nil; z_next = UNIVERSE->z_list_start;
|
|
// move UP the list
|
|
while ((z_next)&&(z_next->position.z - z_next->collision_radius < position.z - collision_radius))
|
|
{
|
|
z_previous = z_next;
|
|
z_next = z_next->z_next;
|
|
}
|
|
if (z_next) z_next->z_previous = self;
|
|
if (z_previous) z_previous->z_next = self;
|
|
else UNIVERSE->z_list_start = self;
|
|
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
if (gDebugFlags & DEBUG_LINKED_LISTS)
|
|
{
|
|
if (![self checkLinkedLists])
|
|
{
|
|
OOLog(kOOLogEntityAddToListError, @"DEBUG LINKED LISTS - problem encountered while adding %@ to linked lists", self);
|
|
[UNIVERSE debugDumpEntities];
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
- (void) removeFromLinkedLists
|
|
{
|
|
#ifndef NDEBUG
|
|
if (gDebugFlags & DEBUG_LINKED_LISTS)
|
|
OOLog(kOOLogEntityRemoveFromList, @"DEBUG removing entity %@ from linked lists", self);
|
|
#endif
|
|
|
|
if ((x_next == nil)&&(x_previous == nil)) // removed already!
|
|
return;
|
|
|
|
// make sure the starting point is still correct
|
|
if (UNIVERSE)
|
|
{
|
|
if ((UNIVERSE->x_list_start == self)&&(x_next))
|
|
UNIVERSE->x_list_start = x_next;
|
|
if ((UNIVERSE->y_list_start == self)&&(y_next))
|
|
UNIVERSE->y_list_start = y_next;
|
|
if ((UNIVERSE->z_list_start == self)&&(z_next))
|
|
UNIVERSE->z_list_start = z_next;
|
|
}
|
|
//
|
|
if (x_previous) x_previous->x_next = x_next;
|
|
if (x_next) x_next->x_previous = x_previous;
|
|
//
|
|
if (y_previous) y_previous->y_next = y_next;
|
|
if (y_next) y_next->y_previous = y_previous;
|
|
//
|
|
if (z_previous) z_previous->z_next = z_next;
|
|
if (z_next) z_next->z_previous = z_previous;
|
|
//
|
|
x_previous = nil; x_next = nil;
|
|
y_previous = nil; y_next = nil;
|
|
z_previous = nil; z_next = nil;
|
|
|
|
#ifndef NDEBUG
|
|
if (gDebugFlags & DEBUG_LINKED_LISTS)
|
|
{
|
|
if (![self checkLinkedLists])
|
|
{
|
|
OOLog(kOOLogEntityRemoveFromListError, @"DEBUG LINKED LISTS - problem encountered while removing %@ from linked lists", self);
|
|
[UNIVERSE debugDumpEntities];
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
- (BOOL) checkLinkedLists
|
|
{
|
|
// DEBUG check for loops
|
|
if (UNIVERSE->n_entities > 0)
|
|
{
|
|
int n;
|
|
Entity *check, *last;
|
|
//
|
|
last = nil;
|
|
//
|
|
n = UNIVERSE->n_entities;
|
|
check = UNIVERSE->x_list_start;
|
|
while ((n--)&&(check))
|
|
{
|
|
last = check;
|
|
check = check->x_next;
|
|
}
|
|
if ((check)||(n > 0))
|
|
{
|
|
OOLog(kOOLogEntityVerificationError, @"Broken x_next %@ list (%d) ***", UNIVERSE->x_list_start, n);
|
|
return NO;
|
|
}
|
|
//
|
|
n = UNIVERSE->n_entities;
|
|
check = last;
|
|
while ((n--)&&(check)) check = check->x_previous;
|
|
if ((check)||(n > 0))
|
|
{
|
|
OOLog(kOOLogEntityVerificationError, @"Broken x_previous %@ list (%d) ***", UNIVERSE->x_list_start, n);
|
|
return NO;
|
|
}
|
|
//
|
|
n = UNIVERSE->n_entities;
|
|
check = UNIVERSE->y_list_start;
|
|
while ((n--)&&(check))
|
|
{
|
|
last = check;
|
|
check = check->y_next;
|
|
}
|
|
if ((check)||(n > 0))
|
|
{
|
|
OOLog(kOOLogEntityVerificationError, @"Broken y_next %@ list (%d) ***", UNIVERSE->y_list_start, n);
|
|
return NO;
|
|
}
|
|
//
|
|
n = UNIVERSE->n_entities;
|
|
check = last;
|
|
while ((n--)&&(check)) check = check->y_previous;
|
|
if ((check)||(n > 0))
|
|
{
|
|
OOLog(kOOLogEntityVerificationError, @"Broken y_previous %@ list (%d) ***", UNIVERSE->y_list_start, n);
|
|
return NO;
|
|
}
|
|
//
|
|
n = UNIVERSE->n_entities;
|
|
check = UNIVERSE->z_list_start;
|
|
while ((n--)&&(check))
|
|
{
|
|
last = check;
|
|
check = check->z_next;
|
|
}
|
|
if ((check)||(n > 0))
|
|
{
|
|
OOLog(kOOLogEntityVerificationError, @"Broken z_next %@ list (%d) ***", UNIVERSE->z_list_start, n);
|
|
return NO;
|
|
}
|
|
//
|
|
n = UNIVERSE->n_entities;
|
|
check = last;
|
|
while ((n--)&&(check)) check = check->z_previous;
|
|
if ((check)||(n > 0))
|
|
{
|
|
OOLog(kOOLogEntityVerificationError, @"Broken z_previous %@ list (%d) ***", UNIVERSE->z_list_start, n);
|
|
return NO;
|
|
}
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
|
|
- (void) updateLinkedLists
|
|
{
|
|
if (!UNIVERSE)
|
|
return; // not in the UNIVERSE - don't do this!
|
|
if ((x_next == nil)&&(x_previous == nil))
|
|
return; // not in the lists - don't do this!
|
|
|
|
#ifndef NDEBUG
|
|
if (gDebugFlags & DEBUG_LINKED_LISTS)
|
|
{
|
|
if (![self checkLinkedLists])
|
|
{
|
|
OOLog(kOOLogEntityVerificationError, @"DEBUG LINKED LISTS problem encountered before updating linked lists for %@", self);
|
|
[UNIVERSE debugDumpEntities];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// update position in linked list for position.x
|
|
// take self out of list..
|
|
if (x_previous) x_previous->x_next = x_next;
|
|
if (x_next) x_next->x_previous = x_previous;
|
|
// sink DOWN the list
|
|
while ((x_previous)&&(x_previous->position.x - x_previous->collision_radius > position.x - collision_radius))
|
|
{
|
|
x_next = x_previous;
|
|
x_previous = x_previous->x_previous;
|
|
}
|
|
// bubble UP the list
|
|
while ((x_next)&&(x_next->position.x - x_next->collision_radius < position.x - collision_radius))
|
|
{
|
|
x_previous = x_next;
|
|
x_next = x_next->x_next;
|
|
}
|
|
if (x_next) // insert self into the list before x_next..
|
|
x_next->x_previous = self;
|
|
if (x_previous) // insert self into the list after x_previous..
|
|
x_previous->x_next = self;
|
|
if ((x_previous == nil)&&(UNIVERSE)) // if we're the first then tell the UNIVERSE!
|
|
UNIVERSE->x_list_start = self;
|
|
|
|
// update position in linked list for position.y
|
|
// take self out of list..
|
|
if (y_previous) y_previous->y_next = y_next;
|
|
if (y_next) y_next->y_previous = y_previous;
|
|
// sink DOWN the list
|
|
while ((y_previous)&&(y_previous->position.y - y_previous->collision_radius > position.y - collision_radius))
|
|
{
|
|
y_next = y_previous;
|
|
y_previous = y_previous->y_previous;
|
|
}
|
|
// bubble UP the list
|
|
while ((y_next)&&(y_next->position.y - y_next->collision_radius < position.y - collision_radius))
|
|
{
|
|
y_previous = y_next;
|
|
y_next = y_next->y_next;
|
|
}
|
|
if (y_next) // insert self into the list before y_next..
|
|
y_next->y_previous = self;
|
|
if (y_previous) // insert self into the list after y_previous..
|
|
y_previous->y_next = self;
|
|
if ((y_previous == nil)&&(UNIVERSE)) // if we're the first then tell the UNIVERSE!
|
|
UNIVERSE->y_list_start = self;
|
|
|
|
// update position in linked list for position.z
|
|
// take self out of list..
|
|
if (z_previous) z_previous->z_next = z_next;
|
|
if (z_next) z_next->z_previous = z_previous;
|
|
// sink DOWN the list
|
|
while ((z_previous)&&(z_previous->position.z - z_previous->collision_radius > position.z - collision_radius))
|
|
{
|
|
z_next = z_previous;
|
|
z_previous = z_previous->z_previous;
|
|
}
|
|
// bubble UP the list
|
|
while ((z_next)&&(z_next->position.z - z_next->collision_radius < position.z - collision_radius))
|
|
{
|
|
z_previous = z_next;
|
|
z_next = z_next->z_next;
|
|
}
|
|
if (z_next) // insert self into the list before z_next..
|
|
z_next->z_previous = self;
|
|
if (z_previous) // insert self into the list after z_previous..
|
|
z_previous->z_next = self;
|
|
if ((z_previous == nil)&&(UNIVERSE)) // if we're the first then tell the UNIVERSE!
|
|
UNIVERSE->z_list_start = self;
|
|
|
|
// done
|
|
#ifndef NDEBUG
|
|
if (gDebugFlags & DEBUG_LINKED_LISTS)
|
|
{
|
|
if (![self checkLinkedLists])
|
|
{
|
|
OOLog(kOOLogEntityUpdateError, @"DEBUG LINKED LISTS problem encountered after updating linked lists for %@", self);
|
|
[UNIVERSE debugDumpEntities];
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
- (void) wasAddedToUniverse
|
|
{
|
|
// Do nothing
|
|
}
|
|
|
|
|
|
- (void) wasRemovedFromUniverse
|
|
{
|
|
// Do nothing
|
|
}
|
|
|
|
|
|
- (void) warnAboutHostiles
|
|
{
|
|
// do nothing for now, this can be expanded in sub classes
|
|
OOLog(@"general.error.subclassResponsibility.Entity-warnAboutHostiles", @"%@", @"***** Entity does nothing in warnAboutHostiles");
|
|
}
|
|
|
|
|
|
- (CollisionRegion*) collisionRegion
|
|
{
|
|
return collisionRegion;
|
|
}
|
|
|
|
|
|
- (void) setCollisionRegion: (CollisionRegion*) region
|
|
{
|
|
if (collisionRegion) [collisionRegion release];
|
|
collisionRegion = [region retain];
|
|
}
|
|
|
|
|
|
- (void) setUniversalID:(OOUniversalID)uid
|
|
{
|
|
universalID = uid;
|
|
}
|
|
|
|
|
|
- (OOUniversalID) universalID
|
|
{
|
|
return universalID;
|
|
}
|
|
|
|
|
|
- (BOOL) throwingSparks
|
|
{
|
|
return throw_sparks;
|
|
}
|
|
|
|
|
|
- (void) setThrowSparks:(BOOL) value
|
|
{
|
|
throw_sparks = value;
|
|
}
|
|
|
|
|
|
- (void) throwSparks
|
|
{
|
|
// do nothing for now
|
|
}
|
|
|
|
|
|
- (void) setOwner:(Entity *)ent
|
|
{
|
|
[_owner release];
|
|
_owner = [ent weakRetain];
|
|
}
|
|
|
|
|
|
- (id) owner
|
|
{
|
|
return [_owner weakRefUnderlyingObject];
|
|
}
|
|
|
|
|
|
- (ShipEntity *)parentEntity
|
|
{
|
|
id owner = [self owner];
|
|
if ([owner isShipWithSubEntityShip:self]) return owner;
|
|
return nil;
|
|
}
|
|
|
|
|
|
- (id<OOWeakReferenceSupport>) superShaderBindingTarget
|
|
{
|
|
return [self parentEntity];
|
|
}
|
|
|
|
|
|
- (ShipEntity *) rootShipEntity
|
|
{
|
|
ShipEntity *parent = [self parentEntity];
|
|
if (parent != nil) return [parent rootShipEntity];
|
|
if ([self isShip]) return (ShipEntity *)self;
|
|
return nil;
|
|
}
|
|
|
|
|
|
- (HPVector) position
|
|
{
|
|
return position;
|
|
}
|
|
|
|
- (Vector) cameraRelativePosition
|
|
{
|
|
return cameraRelativePosition;
|
|
}
|
|
|
|
- (GLfloat) cameraRangeFront
|
|
{
|
|
return magnitude(cameraRelativePosition) - [self frustumRadius];
|
|
}
|
|
|
|
- (GLfloat) cameraRangeBack
|
|
{
|
|
return magnitude(cameraRelativePosition) + [self frustumRadius];
|
|
}
|
|
|
|
|
|
|
|
// Exposed to uniform bindings.
|
|
// so needs to remain at OpenGL precision levels
|
|
- (Vector) relativePosition
|
|
{
|
|
return HPVectorToVector(HPvector_subtract([self position], [PLAYER position]));
|
|
}
|
|
|
|
- (Vector) vectorTo:(Entity *)entity
|
|
{
|
|
return HPVectorToVector(HPvector_subtract([entity position], [self position]));
|
|
}
|
|
|
|
|
|
- (void) setPosition:(HPVector) posn
|
|
{
|
|
position = posn;
|
|
[self updateCameraRelativePosition];
|
|
}
|
|
|
|
|
|
- (void) setPositionX:(OOHPScalar)x y:(OOHPScalar)y z:(OOHPScalar)z
|
|
{
|
|
position.x = x;
|
|
position.y = y;
|
|
position.z = z;
|
|
[self updateCameraRelativePosition];
|
|
}
|
|
|
|
|
|
- (void) updateCameraRelativePosition
|
|
{
|
|
cameraRelativePosition = HPVectorToVector(HPvector_subtract([self absolutePositionForSubentity],[PLAYER viewpointPosition]));
|
|
}
|
|
|
|
|
|
- (HPVector) absolutePositionForSubentity
|
|
{
|
|
return [self absolutePositionForSubentityOffset:kZeroHPVector];
|
|
}
|
|
|
|
|
|
- (HPVector) absolutePositionForSubentityOffset:(HPVector) offset
|
|
{
|
|
HPVector abspos = HPvector_add(position, OOHPVectorMultiplyMatrix(offset, rotMatrix));
|
|
Entity *last = nil;
|
|
Entity *father = [self parentEntity];
|
|
|
|
while (father != nil && father != last)
|
|
{
|
|
abspos = HPvector_add(OOHPVectorMultiplyMatrix(abspos, [father drawRotationMatrix]), [father position]);
|
|
last = father;
|
|
if (![last isSubEntity]) break;
|
|
father = [father owner];
|
|
}
|
|
return abspos;
|
|
}
|
|
|
|
|
|
- (double) zeroDistance
|
|
{
|
|
return zero_distance;
|
|
}
|
|
|
|
|
|
- (double) camZeroDistance
|
|
{
|
|
return cam_zero_distance;
|
|
}
|
|
|
|
|
|
- (NSComparisonResult) compareZeroDistance:(Entity *)otherEntity
|
|
{
|
|
if ((otherEntity)&&(zero_distance > otherEntity->zero_distance))
|
|
return NSOrderedAscending;
|
|
else
|
|
return NSOrderedDescending;
|
|
}
|
|
|
|
|
|
- (BoundingBox) boundingBox
|
|
{
|
|
return boundingBox;
|
|
}
|
|
|
|
|
|
- (GLfloat) mass
|
|
{
|
|
return mass;
|
|
}
|
|
|
|
|
|
- (void) setOrientation:(Quaternion) quat
|
|
{
|
|
orientation = quat;
|
|
[self orientationChanged];
|
|
}
|
|
|
|
|
|
- (Quaternion) orientation
|
|
{
|
|
return orientation;
|
|
}
|
|
|
|
|
|
- (Quaternion) normalOrientation
|
|
{
|
|
return [self orientation];
|
|
}
|
|
|
|
|
|
- (void) setNormalOrientation:(Quaternion) quat
|
|
{
|
|
[self setOrientation:quat];
|
|
}
|
|
|
|
|
|
- (void) orientationChanged
|
|
{
|
|
quaternion_normalize(&orientation);
|
|
rotMatrix = OOMatrixForQuaternionRotation(orientation);
|
|
}
|
|
|
|
|
|
- (void) setVelocity:(Vector) vel
|
|
{
|
|
velocity = vel;
|
|
}
|
|
|
|
|
|
- (Vector) velocity
|
|
{
|
|
return velocity;
|
|
}
|
|
|
|
|
|
- (double) speed
|
|
{
|
|
return magnitude([self velocity]);
|
|
}
|
|
|
|
|
|
- (GLfloat) distanceTravelled
|
|
{
|
|
return distanceTravelled;
|
|
}
|
|
|
|
|
|
- (void) setDistanceTravelled: (GLfloat) value
|
|
{
|
|
distanceTravelled = value;
|
|
}
|
|
|
|
|
|
- (void) setStatus:(OOEntityStatus) stat
|
|
{
|
|
_status = stat;
|
|
}
|
|
|
|
|
|
- (OOEntityStatus) status
|
|
{
|
|
return _status;
|
|
}
|
|
|
|
|
|
- (void) setScanClass:(OOScanClass)sClass
|
|
{
|
|
scanClass = sClass;
|
|
}
|
|
|
|
|
|
- (OOScanClass) scanClass
|
|
{
|
|
return scanClass;
|
|
}
|
|
|
|
|
|
- (void) setEnergy:(GLfloat) amount
|
|
{
|
|
energy = amount;
|
|
}
|
|
|
|
|
|
- (GLfloat) energy
|
|
{
|
|
return energy;
|
|
}
|
|
|
|
|
|
- (void) setMaxEnergy:(GLfloat)amount
|
|
{
|
|
maxEnergy = amount;
|
|
}
|
|
|
|
|
|
- (GLfloat) maxEnergy
|
|
{
|
|
return maxEnergy;
|
|
}
|
|
|
|
|
|
- (void) applyRoll:(GLfloat) roll andClimb:(GLfloat) climb
|
|
{
|
|
if ((roll == 0.0)&&(climb == 0.0)&&(!hasRotated))
|
|
return;
|
|
|
|
if (roll)
|
|
quaternion_rotate_about_z(&orientation, -roll);
|
|
if (climb)
|
|
quaternion_rotate_about_x(&orientation, -climb);
|
|
|
|
[self orientationChanged];
|
|
}
|
|
|
|
|
|
- (void) applyRoll:(GLfloat) roll climb:(GLfloat) climb andYaw:(GLfloat) yaw
|
|
{
|
|
if ((roll == 0.0)&&(climb == 0.0)&&(yaw == 0.0)&&(!hasRotated))
|
|
return;
|
|
|
|
if (roll)
|
|
quaternion_rotate_about_z(&orientation, -roll);
|
|
if (climb)
|
|
quaternion_rotate_about_x(&orientation, -climb);
|
|
if (yaw)
|
|
quaternion_rotate_about_y(&orientation, -yaw);
|
|
|
|
[self orientationChanged];
|
|
}
|
|
|
|
|
|
- (void) moveForward:(double)amount
|
|
{
|
|
HPVector forward = HPvector_multiply_scalar(HPvector_forward_from_quaternion(orientation), amount);
|
|
position = HPvector_add(position, forward);
|
|
distanceTravelled += amount;
|
|
}
|
|
|
|
|
|
- (OOMatrix) rotationMatrix
|
|
{
|
|
return rotMatrix;
|
|
}
|
|
|
|
|
|
- (OOMatrix) drawRotationMatrix
|
|
{
|
|
return rotMatrix;
|
|
}
|
|
|
|
|
|
- (OOMatrix) transformationMatrix
|
|
{
|
|
OOMatrix result = rotMatrix;
|
|
return OOMatrixHPTranslate(result, position);
|
|
}
|
|
|
|
|
|
- (OOMatrix) drawTransformationMatrix
|
|
{
|
|
OOMatrix result = rotMatrix;
|
|
return OOMatrixHPTranslate(result, position);
|
|
}
|
|
|
|
|
|
- (BOOL) canCollide
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
|
|
- (GLfloat) collisionRadius
|
|
{
|
|
return collision_radius;
|
|
}
|
|
|
|
|
|
- (GLfloat) frustumRadius
|
|
{
|
|
return collision_radius;
|
|
}
|
|
|
|
|
|
- (void) setCollisionRadius:(GLfloat) amount
|
|
{
|
|
collision_radius = amount;
|
|
}
|
|
|
|
|
|
- (NSMutableArray *) collisionArray
|
|
{
|
|
return collidingEntities;
|
|
}
|
|
|
|
|
|
- (void) update:(OOTimeDelta)delta_t
|
|
{
|
|
if (_status != STATUS_COCKPIT_DISPLAY)
|
|
{
|
|
if ([self isSubEntity])
|
|
{
|
|
zero_distance = [[self owner] zeroDistance];
|
|
cam_zero_distance = [[self owner] camZeroDistance];
|
|
[self updateCameraRelativePosition];
|
|
}
|
|
else
|
|
{
|
|
zero_distance = HPdistance2(PLAYER->position, position);
|
|
cam_zero_distance = HPdistance2([PLAYER viewpointPosition], position);
|
|
[self updateCameraRelativePosition];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
zero_distance = HPmagnitude2(position);
|
|
cam_zero_distance = zero_distance;
|
|
cameraRelativePosition = HPVectorToVector(position);
|
|
}
|
|
|
|
if ([self status] != STATUS_COCKPIT_DISPLAY)
|
|
{
|
|
[self applyVelocity:delta_t];
|
|
}
|
|
|
|
hasMoved = !HPvector_equal(position, lastPosition);
|
|
hasRotated = !quaternion_equal(orientation, lastOrientation);
|
|
lastPosition = position;
|
|
lastOrientation = orientation;
|
|
}
|
|
|
|
|
|
- (void) applyVelocity:(OOTimeDelta)delta_t
|
|
{
|
|
position = HPvector_add(position, HPvector_multiply_scalar(vectorToHPVector(velocity), delta_t));
|
|
}
|
|
|
|
|
|
- (BOOL) checkCloseCollisionWith:(Entity *)other
|
|
{
|
|
return other != nil;
|
|
}
|
|
|
|
|
|
- (double)findCollisionRadius
|
|
{
|
|
OOLogGenericSubclassResponsibility();
|
|
return 0;
|
|
}
|
|
|
|
|
|
- (void) drawImmediate:(bool)immediate translucent:(bool)translucent
|
|
{
|
|
OOLogGenericSubclassResponsibility();
|
|
}
|
|
|
|
|
|
- (void) takeEnergyDamage:(double) amount from:(Entity *) ent becauseOf:(Entity *) other weaponIdentifier:(NSString *)weaponIdentifier
|
|
{
|
|
|
|
}
|
|
|
|
|
|
- (void)dumpState
|
|
{
|
|
if (OOLogWillDisplayMessagesInClass(@"dumpState"))
|
|
{
|
|
OOLog(@"dumpState", @"State for %@:", self);
|
|
OOLogPushIndent();
|
|
OOLogIndent();
|
|
@try
|
|
{
|
|
[self dumpSelfState];
|
|
}
|
|
@catch (id exception) {}
|
|
OOLogPopIndent();
|
|
}
|
|
}
|
|
|
|
|
|
- (void)dumpSelfState
|
|
{
|
|
NSMutableArray *flags = nil;
|
|
NSString *flagsString = nil;
|
|
id owner = [self owner];
|
|
|
|
if (owner == self) owner = @"self";
|
|
else if (owner == nil) owner = @"none";
|
|
|
|
OOLog(@"dumpState.entity", @"Universal ID: %u", universalID);
|
|
OOLog(@"dumpState.entity", @"Scan class: %@", OOStringFromScanClass(scanClass));
|
|
OOLog(@"dumpState.entity", @"Status: %@", OOStringFromEntityStatus([self status]));
|
|
OOLog(@"dumpState.entity", @"Position: %@", HPVectorDescription(position));
|
|
OOLog(@"dumpState.entity", @"Orientation: %@", QuaternionDescription(orientation));
|
|
OOLog(@"dumpState.entity", @"Distance travelled: %g", distanceTravelled);
|
|
OOLog(@"dumpState.entity", @"Energy: %g of %g", energy, maxEnergy);
|
|
OOLog(@"dumpState.entity", @"Mass: %g", mass);
|
|
OOLog(@"dumpState.entity", @"Owner: %@", owner);
|
|
|
|
flags = [NSMutableArray array];
|
|
#define ADD_FLAG_IF_SET(x) if (x) { [flags addObject:@#x]; }
|
|
ADD_FLAG_IF_SET(isShip);
|
|
ADD_FLAG_IF_SET(isStation);
|
|
ADD_FLAG_IF_SET(isPlayer);
|
|
ADD_FLAG_IF_SET(isWormhole);
|
|
ADD_FLAG_IF_SET(isSubEntity);
|
|
ADD_FLAG_IF_SET(hasMoved);
|
|
ADD_FLAG_IF_SET(hasRotated);
|
|
ADD_FLAG_IF_SET(isSunlit);
|
|
ADD_FLAG_IF_SET(throw_sparks);
|
|
flagsString = [flags count] ? [flags componentsJoinedByString:@", "] : (NSString *)@"none";
|
|
OOLog(@"dumpState.entity", @"Flags: %@", flagsString);
|
|
OOLog(@"dumpState.entity", @"Collision Test Filter: %u", collisionTestFilter);
|
|
|
|
}
|
|
|
|
|
|
- (void)subEntityReallyDied:(ShipEntity *)sub
|
|
{
|
|
OOLog(@"entity.bug", @"%s called for non-ship entity %p by %p", __PRETTY_FUNCTION__, self, sub);
|
|
}
|
|
|
|
|
|
// For shader bindings.
|
|
- (GLfloat)universalTime
|
|
{
|
|
return [UNIVERSE getTime];
|
|
}
|
|
|
|
|
|
- (GLfloat)spawnTime
|
|
{
|
|
return spawnTime;
|
|
}
|
|
|
|
|
|
- (GLfloat)timeElapsedSinceSpawn
|
|
{
|
|
return [UNIVERSE getTime] - spawnTime;
|
|
}
|
|
|
|
|
|
- (void) setAtmosphereFogging: (OOColor *)fogging
|
|
{
|
|
[atmosphereFogging release];
|
|
atmosphereFogging = [fogging retain];
|
|
}
|
|
|
|
- (OOColor *) fogUniform
|
|
{
|
|
return [[atmosphereFogging retain] autorelease];
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
- (NSString *) descriptionForObjDumpBasic
|
|
{
|
|
NSString *result = [self descriptionComponents];
|
|
if (result != nil) result = [NSString stringWithFormat:@"%@ %@", NSStringFromClass([self class]), result];
|
|
else result = [self description];
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
- (NSString *) descriptionForObjDump
|
|
{
|
|
NSString *result = [self descriptionForObjDumpBasic];
|
|
|
|
result = [result stringByAppendingFormat:@" range: %g (visible: %@)", HPdistance([self position], [PLAYER position]), [self isVisible] ? @"yes" : @"no"];
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
- (NSSet *) allTextures
|
|
{
|
|
return nil;
|
|
}
|
|
#endif
|
|
|
|
|
|
- (BOOL) isVisible
|
|
{
|
|
return cam_zero_distance <= ABSOLUTE_NO_DRAW_DISTANCE2;
|
|
}
|
|
|
|
|
|
- (BOOL) isInSpace
|
|
{
|
|
switch ([self status])
|
|
{
|
|
case STATUS_IN_FLIGHT:
|
|
case STATUS_DOCKING:
|
|
case STATUS_LAUNCHING:
|
|
case STATUS_AUTOPILOT_ENGAGED:
|
|
case STATUS_WITCHSPACE_COUNTDOWN:
|
|
case STATUS_BEING_SCOOPED:
|
|
case STATUS_EFFECT:
|
|
case STATUS_ACTIVE:
|
|
return YES;
|
|
default:
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
|
|
- (BOOL) isImmuneToBreakPatternHide
|
|
{
|
|
return isImmuneToBreakPatternHide;
|
|
}
|
|
|
|
@end
|