Implemented role set vs. primary role distinction in ShipEntity. Appears to work.

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@1166 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2007-09-07 17:16:36 +00:00
parent 693c27e2c2
commit dfc8f99526
20 changed files with 648 additions and 434 deletions

View File

@ -158,6 +158,12 @@ typedef struct
struct JSObject *jsSelf;
}
- (BOOL)isShip;
- (BOOL)isStation;
- (BOOL)isSubEntity;
- (BOOL)isPlayer;
- (BOOL)isPlanet;
- (BOOL) validForAddToUniverse;
- (void) addToLinkedLists;
- (void) removeFromLinkedLists;
@ -180,7 +186,7 @@ typedef struct
- (void) throwSparks;
- (void) setOwner:(Entity *)ent;
- (Entity *)owner;
- (id)owner;
- (void) setPosition:(Vector)posn;
- (void) setPositionX:(GLfloat)x y:(GLfloat)y z:(GLfloat)z;

View File

@ -99,6 +99,36 @@ static NSString * const kOOLogEntityUpdateError = @"entity.linkedList.update.
}
- (BOOL)isShip
{
return isShip;
}
- (BOOL)isStation
{
return isStation;
}
- (BOOL)isSubEntity
{
return isSubentity;
}
- (BOOL)isPlayer
{
return isPlayer;
}
- (BOOL)isPlanet
{
return isPlanet;
}
- (BOOL) validForAddToUniverse
{
return YES;
@ -476,7 +506,7 @@ static NSString * const kOOLogEntityUpdateError = @"entity.linkedList.update.
}
- (Entity *) owner
- (id) owner
{
return [UNIVERSE entityForUniversalID:owner];
}

View File

@ -1042,7 +1042,7 @@ static GLfloat texture_uv_array[10400 * 2];
if (other->isShip)
{
ShipEntity *ship = (ShipEntity *)other;
if ([[ship roles] isEqual:@"shuttle"])
if ([ship isShuttle])
{
[ship landOnPlanet];
if ([ship reportAIMessages])

View File

@ -294,11 +294,13 @@ static PlayerEntity *sSharedPlayer = nil;
{
if (missile_entity[i])
{
[missile_roles addObject:[missile_entity[i] roles]];
[missile_roles addObject:[missile_entity[i] primaryRole]];
}
else
{
[missile_roles addObject:@"NONE"];
}
}
[result setObject:missile_roles forKey:@"missile_roles"];
// [self safeAllMissiles]; // affects missile_status!!
@ -1054,7 +1056,9 @@ static PlayerEntity *sSharedPlayer = nil;
[name autorelease];
name = [[shipDict stringForKey:@"name" defaultValue:name] copy];
[self setRoles:@"player"];
[roleSet release];
roleSet = nil;
[self setPrimaryRole:@"player"];
OOColor *color = [OOColor brightColorWithDescription:[shipDict objectForKey:@"laser_color"]];
if (color == nil) color = [OOColor redColor];
@ -1653,7 +1657,7 @@ double scoopSoundPlayTime = 0.0;
}
}
if ((missile_status == MISSILE_STATUS_ARMED)&&(ident_engaged||[[missile_entity[activeMissile] roles] hasSuffix:@"MISSILE"])&&((status == STATUS_IN_FLIGHT)||(status == STATUS_WITCHSPACE_COUNTDOWN)))
if ((missile_status == MISSILE_STATUS_ARMED)&&(ident_engaged||[missile_entity[activeMissile] isMissile])&&((status == STATUS_IN_FLIGHT)||(status == STATUS_WITCHSPACE_COUNTDOWN)))
{
int first_target_id = [UNIVERSE getFirstEntityTargettedByPlayer:self];
if (first_target_id != NO_TARGET)
@ -2568,11 +2572,10 @@ double scoopSoundPlayTime = 0.0;
if (missile_entity[next_missile])
{
// if this is a missile then select it
// if ([[missile_entity[next_missile] roles] isEqual:@"EQ_MISSILE"])
if (missile_entity[next_missile]) // if it exists
{
[self setActiveMissile:next_missile];
if (([[missile_entity[next_missile] roles] hasSuffix:@"MISSILE"])&&([missile_entity[next_missile] primaryTarget] != nil))
if (([missile_entity[next_missile] isMissile])&&([missile_entity[next_missile] primaryTarget] != nil))
{
// copy the missile's target
[self addTarget:[missile_entity[next_missile] primaryTarget]];
@ -2727,7 +2730,7 @@ double scoopSoundPlayTime = 0.0;
double mcr = missile->collision_radius;
if ([[missile roles] hasSuffix:@"MINE"]&&((missile_status == MISSILE_STATUS_ARMED)||(missile_status == MISSILE_STATUS_TARGET_LOCKED)))
if ([missile isMine]&&((missile_status == MISSILE_STATUS_ARMED)||(missile_status == MISSILE_STATUS_TARGET_LOCKED)))
{
BOOL launchedOK = [self launchMine:missile];
if (launchedOK)
@ -3387,7 +3390,7 @@ double scoopSoundPlayTime = 0.0;
int killClass = other->scanClass; // **tgape** change (+line)
int kill_award = 1;
if ([[other roles] isEqual:@"police"]) // oops, we shot a copper!
if ([other isPolice]) // oops, we shot a copper!
legalStatus |= 64;
if (![UNIVERSE strict]) // only mess with the scores if we're not in 'strict' mode
@ -3395,7 +3398,7 @@ double scoopSoundPlayTime = 0.0;
BOOL killIsCargo = ((killClass == CLASS_CARGO) && ([other commodityAmount] > 0));
if ((killIsCargo) || (killClass == CLASS_BUOY) || (killClass == CLASS_ROCK))
{
if (![[other roles] isEqual:@"tharglet"]) // okay, we'll count tharglets as proper kills
if (![other hasRole:@"tharglet"]) // okay, we'll count tharglets as proper kills
{
score /= 10; // reduce bounty awarded
kill_award = 0; // don't award a kill
@ -5266,7 +5269,7 @@ static int last_outfitting_index;
missile_entity[i] = nil;
if (weapon)
{
NSString* weapon_key = [weapon roles];
NSString* weapon_key = [weapon primaryRole];
int weapon_value = [UNIVERSE getPriceForWeaponSystemWithKey:weapon_key];
tradeIn += weapon_value;
[weapon release];

View File

@ -423,7 +423,7 @@ static NSTimeInterval time_last_frame;
// launch here
if (!fire_missile_pressed)
{
BOOL missile_noise = [[missile_entity[activeMissile] roles] hasSuffix:@"MISSILE"];
BOOL missile_noise = [missile_entity[activeMissile] isMissile];
if ([self fireMissile])
{
if (missile_noise) [missileSound play];
@ -515,7 +515,7 @@ static NSTimeInterval time_last_frame;
missile_status = MISSILE_STATUS_ARMED;
if ((ident_engaged) && ([self primaryTarget]))
{
if ([[missile_entity[activeMissile] roles] hasSuffix:@"MISSILE"])
if ([missile_entity[activeMissile] isMissile])
{
missile_status = MISSILE_STATUS_TARGET_LOCKED;
[missile_entity[activeMissile] addTarget:[self primaryTarget]];
@ -527,7 +527,7 @@ static NSTimeInterval time_last_frame;
else
{
primaryTarget = NO_TARGET;
if ([[missile_entity[activeMissile] roles] hasSuffix:@"MISSILE"])
if ([missile_entity[activeMissile] isMissile])
{
if (missile_entity[activeMissile])
[missile_entity[activeMissile] removeTarget:nil];
@ -536,7 +536,7 @@ static NSTimeInterval time_last_frame;
[self beep];
}
}
if ([[missile_entity[activeMissile] roles] hasSuffix:@"MINE"])
if ([missile_entity[activeMissile] isMine])
{
[UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[mine-armed]") forCount:4.5];
if (![UNIVERSE playCustomSound:@"[mine-armed]"])

View File

@ -1185,7 +1185,7 @@ static int scriptRandomSeed = -1; // ensure proper random function
[tokens removeObjectAtIndex:0];
messageString = [tokens componentsJoinedByString:@" "];
[UNIVERSE sendShipsWithRole:roleString messageToAI:messageString];
[UNIVERSE sendShipsWithPrimaryRole:roleString messageToAI:messageString];
}
@ -1224,7 +1224,7 @@ static int scriptRandomSeed = -1; // ensure proper random function
OOLog(kOOLogNoteAddShips, @"DEBUG ..... Going to add %d ships with role '%@'", number, roleString);
while (number--)
[UNIVERSE witchspaceShipWithRole:roleString];
[UNIVERSE witchspaceShipWithPrimaryRole:roleString];
}
@ -1873,7 +1873,7 @@ static int scriptRandomSeed = -1; // ensure proper random function
[se1AI setStateMachine:@"exitingTraderAI.plist"];
[se1AI setState:@"EXIT_SYSTEM"];
[se1AI reactToMessage:[NSString stringWithFormat:@"pauseAI: %d", 3 + (ranrot_rand() & 15)]];
[se1 setRoles:@"none"]; // prevents new ship from appearing at witchpoint when this one leaves!
[se1 setPrimaryRole:@"none"]; // prevents new ship from appearing at witchpoint when this one leaves!
}
}
}

View File

@ -28,7 +28,7 @@ MA 02110-1301, USA.
#import "OOEntityWithDrawable.h"
@class OOBrain, OOColor, StationEntity, ParticleEntity, PlanetEntity,
WormholeEntity, AI, Octree, OOMesh, OOScript;
WormholeEntity, AI, Octree, OOMesh, OOScript, OORoleSet;
#define MAX_TARGETS 24
@ -192,7 +192,8 @@ MA 02110-1301, USA.
AI *shipAI; // ship's AI system
NSString *name; // descriptive name
NSString *roles; // names fo roles a ship can take, eg. trader, hunter, police, pirate, scavenger &c.
OORoleSet *roleSet; // Roles a ship can take, eg. trader, hunter, police, pirate, scavenger &c.
NSString *primaryRole; // "Main" role of the ship.
// AI stuff
Vector jink; // x and y set factors for offsetting a pursuing ship's position
@ -385,8 +386,23 @@ MA 02110-1301, USA.
- (NSString *) name;
- (NSString *) identFromShip:(ShipEntity*) otherShip; // name displayed to other ships
- (NSString *) roles;
- (void) setRoles:(NSString *) value;
- (BOOL) hasRole:(NSString *)role;
- (OORoleSet *)roleSet;
- (NSString *)primaryRole;
- (void)setPrimaryRole:(NSString *)role;
- (BOOL)hasPrimaryRole:(NSString *)role;
- (BOOL)isPolice; // Scan class is CLASS_POLICE
- (BOOL)isThargoid; // Scan class is CLASS_THARGOID
- (BOOL)isTrader; // Primary role is "trader" || isPlayer
- (BOOL)isPirate; // Primary role is "pirate"
- (BOOL)isMissile; // Primary role has suffix "MISSILE"
- (BOOL)isMine; // Primary role has suffix "MINE"
- (BOOL)isWeapon; // isMissile || isWeapon
- (BOOL)isEscort; // Primary role is "escort" or "wingman"
- (BOOL)isShuttle; // Primary role is "shuttle"
- (BOOL) hasHostileTarget;
@ -515,7 +531,7 @@ BOOL class_masslocks(int some_class);
- (void) setPrimaryAggressor:(Entity *) targetEntity;
- (void) addTarget:(Entity *) targetEntity;
- (void) removeTarget:(Entity *) targetEntity;
- (Entity *) primaryTarget;
- (id) primaryTarget;
- (int) primaryTargetID;
- (OOBehaviour) behaviour;
@ -586,7 +602,7 @@ BOOL class_masslocks(int some_class);
- (void) setDestination:(Vector) dest;
inline BOOL pairOK(NSString* my_role, NSString* their_role);
- (BOOL) canAcceptEscort:(ShipEntity *)potentialEscort;
- (BOOL) acceptAsEscort:(ShipEntity *) other_ship;
- (Vector) coordinatesForEscortPosition:(int) f_pos;
- (void) deployEscorts;

View File

@ -35,6 +35,7 @@ MA 02110-1301, USA.
#import "OOCollectionExtractors.h"
#import "OOConstToString.h"
#import "NSScannerOOExtensions.h"
#import "OORoleSet.h"
#import "OOCharacter.h"
#import "OOBrain.h"
@ -267,8 +268,10 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change
[name autorelease];
name = [[shipDict stringForKey:@"name" defaultValue:name] copy];
[roles release];
roles = [[shipDict stringForKey:@"roles"] copy];
[roleSet release];
roleSet = [[OORoleSet alloc] initWithRoleString:[shipDict stringForKey:@"roles"]];
[primaryRole release];
primaryRole = nil;
[self setOwner:self];
@ -454,14 +457,15 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change
if (isSubentity)
{
[(ShipEntity *)[self owner] subEntityReallyDied:self];
[[self owner] subEntityReallyDied:self];
}
[shipinfoDictionary release];
[shipAI release];
[cargo release];
[name release];
[roles release];
[roleSet release];
[primaryRole release];
[sub_entities release];
[laser_color release];
[script release];
@ -744,12 +748,8 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change
NSString *escortRole = @"escort";
NSString *escortShipKey = nil;
// FIXME: should look for substring, or in more sensible role manager
if ([roles isEqual:@"trader"])
escortRole = @"escort";
if ([roles isEqual:@"police"])
escortRole = @"wingman";
// if ([self isTrader]) escortRole = @"escort";
if ([self isPolice]) escortRole = @"wingman";
if ([shipinfoDictionary objectForKey:@"escort-role"])
{
@ -796,7 +796,7 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change
[escorter setStatus:STATUS_IN_FLIGHT];
[escorter setRoles:escortRole];
[escorter setPrimaryRole:escortRole];
[escorter setScanClass:scanClass]; // you are the same as I
@ -2867,17 +2867,123 @@ static GLfloat mascem_color2[4] = { 0.4, 0.1, 0.4, 1.0}; // purple
}
- (NSString *) roles
- (BOOL) hasRole:(NSString *)role
{
return roles;
return [roleSet hasRole:role] || [role isEqual:primaryRole];
}
- (void) setRoles:(NSString *) value
- (OORoleSet *)roleSet
{
if (roleSet == nil) roleSet = [[OORoleSet alloc] initWithRoleString:primaryRole];
return [roleSet roleSetWithAddedRoleIfNotSet:primaryRole probability:1.0];
}
/*
- (void) setRoles:(OORoleSet *)inRoles
{
if (inRoles != nil && ![inRoles isEqual:roles])
{
if (roles)
[roles release];
roles = value ? [value copy] : @"";
roles = [inRoles copy];
}
}
- (void) setRoleString:(NSString *)string
{
[self setRoles:[OORoleSet roleSetWithString:string]];
}*/
- (NSString *)primaryRole
{
if (primaryRole == nil)
{
primaryRole = [roleSet anyRole];
if (primaryRole == nil) primaryRole = @"trader";
[primaryRole retain];
OOLog(@"ship.noPrimaryRole", @"%@ had no primary role, randomly selected \"%@\".", primaryRole);
}
return primaryRole;
}
- (void)setPrimaryRole:(NSString *)role
{
if (![role isEqual:primaryRole])
{
[primaryRole release];
primaryRole = [role copy];
}
}
- (BOOL)hasPrimaryRole:(NSString *)role
{
return [[self primaryRole] isEqual:role];
}
- (BOOL)isPolice
{
#if 0
return [self hasPrimaryRole:@"police"] || [self hasPrimaryRole:@"interceptor"] || [self hasPrimaryRole:@"wingman"];
#else
return [self scanClass] == CLASS_POLICE;
#endif
}
- (BOOL)isThargoid
{
#if 0
return [self hasPrimaryRole:@"thargoid"];
#else
return [self scanClass] == CLASS_THARGOID;
#endif
}
- (BOOL)isTrader
{
return isPlayer || [self hasPrimaryRole:@"trader"];
}
- (BOOL)isPirate
{
return [self hasPrimaryRole:@"pirate"];
}
- (BOOL)isMissile
{
return [[self primaryRole] hasSuffix:@"MISSILE"];
}
- (BOOL)isMine
{
return [[self primaryRole] hasSuffix:@"MINE"];
}
- (BOOL)isWeapon
{
return [self isMissile] || [self isMine];
}
- (BOOL)isEscort
{
return [self hasPrimaryRole:@"escort"] || [self hasPrimaryRole:@"wingman"];
}
- (BOOL)isShuttle
{
return [self hasPrimaryRole:@"shuttle"];
}
@ -3501,8 +3607,7 @@ static GLfloat mascem_color2[4] = { 0.4, 0.1, 0.4, 1.0}; // purple
[self doScriptEvent:@"didDie"];
}
if ([roles isEqual:@"thargoid"])
[self broadcastThargoidDestroyed];
if ([self isThargoid]) [self broadcastThargoidDestroyed];
if (!suppressExplosion)
{
@ -3627,7 +3732,7 @@ static GLfloat mascem_color2[4] = { 0.4, 0.1, 0.4, 1.0}; // purple
// Throw out rocks and alloys to be scooped up
//
if ([roles isEqual:@"asteroid"])
if ([self hasPrimaryRole:@"asteroid"])
{
if ((being_mined)||(randf() < 0.20))
{
@ -3663,7 +3768,7 @@ static GLfloat mascem_color2[4] = { 0.4, 0.1, 0.4, 1.0}; // purple
return; // don't do anything more
}
if ([roles isEqual:@"boulder"])
if ([self hasPrimaryRole:@"boulder"])
{
if ((being_mined)||(ranrot_rand() % 100 < 20))
{
@ -4069,8 +4174,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
- (void) collectBountyFor:(ShipEntity *)other
{
if ([roles isEqual:@"pirate"])
bounty += [other bounty];
if ([self isPirate]) bounty += [other bounty];
}
@ -4258,7 +4362,7 @@ BOOL class_masslocks(int some_class)
}
- (Entity *) primaryTarget
- (id) primaryTarget
{
return [UNIVERSE entityForUniversalID:primaryTarget];
}
@ -6229,25 +6333,29 @@ BOOL class_masslocks(int some_class)
}
}
BOOL iAmTheLaw = (scanClass == CLASS_POLICE);
BOOL uAreTheLaw = ((other)&&(other->scanClass == CLASS_POLICE));
energy -= amount;
being_mined = NO;
//
ShipEntity *hunter = nil;
if ((other)&&(other->isShip))
{
ShipEntity* hunter = (ShipEntity *)other;
if ([hunter isCloaked]) other = nil; // lose it!
hunter = (ShipEntity *)other;
if ([hunter isCloaked])
{
// lose it!
other = nil;
hunter = nil;
}
//
}
// if the other entity is a ship note it as an aggressor
if ((other)&&(other->isShip))
if (hunter != nil)
{
ShipEntity* hunter = (ShipEntity *)other;
//
BOOL iAmTheLaw = [self isPolice];
BOOL uAreTheLaw = [hunter isPolice];
last_escort_target = NO_TARGET; // we're being attacked, escorts can scramble!
//
primaryAggressor = [hunter universalID];
found_target = primaryAggressor;
@ -6264,7 +6372,7 @@ BOOL class_masslocks(int some_class)
// tell our group we've been attacked
if (groupID != NO_TARGET)
{
if ([roles isEqual:@"escort"]||[roles isEqual:@"trader"])
if ([self isTrader]|| [self isEscort])
{
ShipEntity *group_leader = [UNIVERSE entityForUniversalID:groupID];
if ((group_leader)&&(group_leader->isShip))
@ -6276,7 +6384,7 @@ BOOL class_masslocks(int some_class)
else
groupID = NO_TARGET;
}
if ([roles isEqual:@"pirate"])
if ([self isPirate])
{
NSArray *fellow_pirates = [self shipsInGroup:groupID];
for (i = 0; i < [fellow_pirates count]; i++)
@ -6323,13 +6431,12 @@ BOOL class_masslocks(int some_class)
// die if I'm out of energy
if (energy <= 0.0)
{
if ((other)&&(other->isShip))
if (hunter != nil)
{
ShipEntity* hunter = (ShipEntity *)other;
[hunter collectBountyFor:self];
if ([hunter primaryTarget] == (Entity *)self)
if ([hunter primaryTarget] == self)
{
[hunter removeTarget:(Entity *)self];
[hunter removeTarget:self];
[[hunter getAI] message:@"TARGET_DESTROYED"];
}
}
@ -6465,7 +6572,7 @@ BOOL class_masslocks(int some_class)
/* Add a new ship to maintain quantities of standard ships, unless
there's a nova in the works (or the AI asked us not to).
*/
[UNIVERSE witchspaceShipWithRole:roles];
[UNIVERSE witchspaceShipWithPrimaryRole:[self primaryRole]];
}
[w_hole suckInShip: self]; // removes ship from universe
@ -6486,7 +6593,7 @@ BOOL class_masslocks(int some_class)
[shipAI message:@"ENTERED_WITCHSPACE"];
if (![[UNIVERSE sun] willGoNova]) // if the sun's not going nova
[UNIVERSE witchspaceShipWithRole:roles]; // then add a new ship like this one leaving!
[UNIVERSE witchspaceShipWithPrimaryRole:[self primaryRole]]; // then add a new ship like this one leaving!
[UNIVERSE removeEntity:self];
}
@ -6575,14 +6682,19 @@ int w_space_seed = 1234567;
frustration = 0.0; // new destination => no frustration!
}
inline BOOL pairOK(NSString* my_role, NSString* their_role)
- (BOOL) canAcceptEscort:(ShipEntity *)potentialEscort
{
BOOL pairing_okay = NO;
if (![self isEscort])
{
return [potentialEscort hasRole:@"escort"];
}
if (([self hasRole:@"police"] || [self hasRole:@"interceptor"]))
{
return [potentialEscort hasRole:@"wingman"];
}
pairing_okay |= (![my_role isEqual:@"escort"] && ![my_role isEqual:@"wingman"] && [their_role isEqual:@"escort"]);
pairing_okay |= (([my_role isEqual:@"police"]||[my_role isEqual:@"interceptor"]) && [their_role isEqual:@"wingman"]);
return pairing_okay;
return NO;
}
@ -6595,7 +6707,7 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role)
if ([shipAI ai_stack_depth] > 1)
return NO;
if (pairOK(roles, [other_ship roles]))
if ([self canAcceptEscort:other_ship])
{
unsigned i;
// check it's not already been accepted
@ -6864,7 +6976,7 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role)
{
ShipEntity* ship = (ShipEntity *)my_entities[i];
d2 = distance2(position, ship->position);
if ((d2 < found_d2)&&([[ship roles] isEqual:@"tharglet"]))
if ((d2 < found_d2)&&([ship hasPrimaryRole:@"tharglet"]))
[[ship getAI] message:@"THARGOID_DESTROYED"];
}
for (i = 0; i < ship_count; i++)
@ -7045,7 +7157,7 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role)
- (void) setNumberOfMinedRocks:(int) value
{
if (![roles isEqual:@"asteroid"])
if (![self hasPrimaryRole:@"asteroid"])
return;
likely_cargo = value;
}
@ -7170,7 +7282,7 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role)
{
// Create a bouy and beacon where the hulk is.
// Get the main GalCop station to launch a pilot boat to deliver a pilot to the hulk.
NSLog(@"claimAsSalvage called on %@ %@", [self name], [self roles]);
NSLog(@"claimAsSalvage called on %@ %@", [self name], [self roleSet]);
/*
// Won't work in interstellar space because there is no GalCop station
if ([[self planet_number] intValue] < 0)
@ -7211,7 +7323,7 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role)
n_scanned_ships = 0;
scan = z_previous;
NSLog(@"searching for pilot boat");
OOLog(@"ship.pilotage", @"searching for pilot boat");
while (scan &&(scan->isShip == NO))
scan = scan->z_previous; // skip non-ships
@ -7221,14 +7333,14 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role)
if (scan->isShip)
{
scanShip = (ShipEntity *)scan;
NSArray *scanRoles = ScanTokensFromString([scanShip roles]);
if ([scanRoles containsObject:@"pilot"] == YES)
if ([self hasRole:@"pilot"] == YES)
{
if ([scanShip primaryTargetID] == NO_TARGET)
{
NSLog(@"found pilot boat with no target, will use this one");
OOLog(@"ship.pilotage", @"found pilot boat with no target, will use this one");
pilot = scanShip;
[pilot setPrimaryRole:@"pilot"];
break;
}
}
@ -7240,7 +7352,7 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role)
if (pilot != nil)
{
NSLog(@"becoming pilot target and setting AI");
OOLog(@"ship.pilotage", @"becoming pilot target and setting AI");
[pilot setReportAIMessages:YES];
[pilot addTarget:self];
[pilot setStateMachine:@"pilotAI.plist"];
@ -7263,7 +7375,7 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role)
[super dumpSelfState];
OOLog(@"dumpState.shipEntity", @"Name: %@", name);
OOLog(@"dumpState.shipEntity", @"Roles: %@", roles);
OOLog(@"dumpState.shipEntity", @"Roles: %@", roleSet);
OOLog(@"dumpState.shipEntity", @"Script: %@", script);
if (sub_entities != nil) OOLog(@"dumpState.shipEntity", @"Subentity count: %u", [sub_entities count]);
OOLog(@"dumpState.shipEntity", @"Behaviour: %@", BehaviourToString(behaviour));

View File

@ -172,10 +172,10 @@ MA 02110-1301, USA.
for (i = 0; i < n_scanned_ships ; i++)
{
ShipEntity *ship = scanned_ships[i];
if ((([[ship roles] isEqual:@"trader"])||(ship->isPlayer))&&(ship->status != STATUS_DEAD)&&(ship->status != STATUS_DOCKED))
if ([ship isTrader] && (ship->status != STATUS_DEAD) && (ship->status != STATUS_DOCKED))
{
GLfloat d2 = distance2_scanned_ships[i];
if (([roles isEqual:@"pirate"])&&(d2 < desired_range * desired_range)&&(ship->isPlayer)&&(PIRATES_PREFER_PLAYER))
if (PIRATES_PREFER_PLAYER && ship->isPlayer && [self isPirate] && (d2 < desired_range * desired_range))
d2 = 0.0;
if (d2 < found_d2)
{
@ -203,7 +203,7 @@ MA 02110-1301, USA.
for (i = 0; i < n_scanned_ships ; i++)
{
ShipEntity *ship = scanned_ships[i];
if ((([[ship roles] isEqual:@"trader"])||(ship->isPlayer))&&(ship->status != STATUS_DEAD)&&(ship->status != STATUS_DOCKED))
if ([ship isTrader] && (ship->status != STATUS_DEAD) && (ship->status != STATUS_DOCKED))
ids_found[n_found++] = ship->universalID;
}
if (n_found == 0)
@ -244,10 +244,8 @@ MA 02110-1301, USA.
}
}
BOOL isPolice = (scanClass == CLASS_POLICE);
//
[self checkScanner];
//
double found_d2 = scannerRange * scannerRange;
found_target = NO_TARGET;
unsigned i;
@ -256,7 +254,7 @@ MA 02110-1301, USA.
ShipEntity *other = (ShipEntity *)scanned_ships[i];
if ((other->scanClass == CLASS_CARGO)&&([other cargoType] != CARGO_NOT_CARGO))
{
if ((!isPolice) || ([other commodityType] == 3)) // police only rescue lifepods and slaves
if ((![self isPolice]) || ([other commodityType] == 3)) // police only rescue lifepods and slaves
{
GLfloat d2 = distance2_scanned_ships[i];
if (d2 < found_d2)
@ -457,12 +455,12 @@ MA 02110-1301, USA.
if (has_ecm)
{
// use the ECM and battle on
ShipEntity* hunter = (ShipEntity*)[missile owner];
ShipEntity *hunter = [missile owner];
[self setPrimaryAggressor:hunter]; // lets get them now for that!
found_target = primaryAggressor;
if ([roles isEqual:@"police"]||[roles isEqual:@"interceptor"]||[roles isEqual:@"wingman"])
if ([self isPolice])
{
NSArray *fellow_police = [self shipsInGroup:groupID];
unsigned i;
@ -475,17 +473,13 @@ MA 02110-1301, USA.
}
// if I'm a copper and you're not, then mark the other as an offender!
BOOL iAmTheLaw = ([roles isEqual:@"police"]||[roles isEqual:@"wingman"]||[roles isEqual:@"interceptor"]);
BOOL uAreTheLaw = ([[hunter roles] isEqual:@"police"]||[[hunter roles] isEqual:@"wingman"]||[[hunter roles] isEqual:@"interceptor"]);
if ((iAmTheLaw)&&(!uAreTheLaw))
[hunter markAsOffender:64];
if ([self isPolice] && ![hunter isPolice]) [hunter markAsOffender:64];
[self fireECM];
return;
}
// RUN AWAY !!
//
jink.x = 0.0;
jink.y = 0.0;
jink.z = 1000.0;
@ -921,9 +915,9 @@ WormholeEntity* whole;
}
if (ship->isStation)
[ship acceptDistressMessageFrom:self];
if ([[ship roles] isEqual:@"police"])
if ([ship hasPrimaryRole:@"police"]) // Not isPolice because we don't want wingmen shooting off... but what about interceptors?
[ship acceptDistressMessageFrom:self];
if ([[ship roles] isEqual:@"hunter"])
if ([ship hasPrimaryRole:@"hunter"])
[ship acceptDistressMessageFrom:self];
}
}
@ -946,7 +940,7 @@ WormholeEntity* whole;
break;
default:
if ((scanClass == CLASS_POLICE)||[roles isEqual:@"police"]||[roles isEqual:@"interceptor"]||[roles isEqual:@"wingman"])
if ([self isPolice])
[[UNIVERSE entityForUniversalID:found_target] markAsOffender:8]; // you have been warned!!
[shipAI reactToMessage:@"ACCEPT_DISTRESS_CALL"];
break;
@ -985,13 +979,13 @@ WormholeEntity* whole;
/*-- Locates all the thargoid warships in range and chooses the nearest --*/
[self checkScanner];
unsigned i;
//
GLfloat found_d2 = scannerRange * scannerRange;
found_target = NO_TARGET;
for (i = 0; i < n_scanned_ships; i++)
{
ShipEntity *ship = scanned_ships[i];
if ([[ship roles] isEqual:@"thargoid"])
if ([ship isThargoid])
{
GLfloat d2 = distance2_scanned_ships[i];
if (d2< found_d2)
@ -1001,10 +995,8 @@ WormholeEntity* whole;
}
}
}
if (found_target != NO_TARGET)
[shipAI message:@"TARGET_FOUND"];
else
[shipAI message:@"NOTHING_FOUND"];
if (found_target != NO_TARGET) [shipAI message:@"TARGET_FOUND"];
else [shipAI message:@"NOTHING_FOUND"];
}
@ -1020,17 +1012,15 @@ WormholeEntity* whole;
{
ShipEntity *thing = scanned_ships[i];
GLfloat d2 = distance2_scanned_ships[i];
if ((thing->scanClass != CLASS_CARGO)&&(thing->status != STATUS_DOCKED)&&(![[thing roles] hasPrefix:@"tharg"])&&(d2 < found_d2))
if ((thing->scanClass != CLASS_CARGO) && (thing->status != STATUS_DOCKED) && ![thing isThargoid] && (d2 < found_d2))
{
found_target = [thing universalID];
if (thing->isPlayer) d2 = 0.0; // prefer the player
found_d2 = d2;
}
}
if (found_target != NO_TARGET)
[shipAI message:@"TARGET_FOUND"];
else
[shipAI message:@"NOTHING_FOUND"];
if (found_target != NO_TARGET) [shipAI message:@"TARGET_FOUND"];
else [shipAI message:@"NOTHING_FOUND"];
}
@ -1085,7 +1075,7 @@ WormholeEntity* whole;
{
ShipEntity *thing = scanned_ships[i];
GLfloat d2 = distance2_scanned_ships[i];
if (((thing->scanClass == CLASS_THARGOID)||(([thing primaryTarget] == self)&&([thing hasHostileTarget])))&&(d2 < found_d2))
if ((d2 < found_d2) && ([thing isThargoid] || (([thing primaryTarget] == self) && [thing hasHostileTarget])))
{
found_target = [thing universalID];
found_d2 = d2;
@ -1262,22 +1252,23 @@ WormholeEntity* whole;
if ((ship != self) && (!ship->isPlayer) && (ship->scanClass == scanClass)) // look for alike
{
GLfloat d2 = distance2_scanned_ships[i];
if ((d2 < found_d2)&&(pairOK([ship roles], roles)))
if ((d2 < found_d2) && [ship canAcceptEscort:self])
{
found_d2 = d2;
found_target = ship->universalID;
}
}
}
if (found_target != NO_TARGET)
[shipAI message:@"TARGET_FOUND"];
if (found_target != NO_TARGET) [shipAI message:@"TARGET_FOUND"];
else
{
[shipAI message:@"NOTHING_FOUND"];
if ([roles isEqual:@"wingman"])
if ([self hasPrimaryRole:@"wingman"])
{
// become free-lance police :)
[shipAI setStateMachine:@"route1patrolAI.plist"]; // use this to avoid referencing a released AI
[self setPrimaryRole:@"police"];
}
}
@ -1404,13 +1395,12 @@ WormholeEntity* whole;
- (void) checkForMotherStation
{
Entity* my_owner = [self owner];
if ((!my_owner) || (!(my_owner->isStation)))
StationEntity *motherStation = [self owner];
if ((!motherStation) || (!(motherStation->isStation)))
{
[shipAI message:@"NOTHING_FOUND"];
return;
}
StationEntity* motherStation = (StationEntity*)[self owner];
Vector v0 = motherStation->position;
Vector rpos = make_vector(position.x - v0.x, position.y - v0.y, position.z - v0.z);
double found_d2 = scannerRange * scannerRange;
@ -1425,28 +1415,27 @@ WormholeEntity* whole;
- (void) sendTargetCommsMessage:(NSString*) message
{
ShipEntity* ship = (ShipEntity*)[self primaryTarget];
if ((!ship)||(ship->status == STATUS_DEAD)||(ship->status == STATUS_DOCKED))
ShipEntity *ship = [self primaryTarget];
if ((ship == nil) || (ship->status == STATUS_DEAD) || (ship->status == STATUS_DOCKED))
{
primaryTarget = NO_TARGET;
[shipAI reactToMessage:@"TARGET_LOST"];
return;
}
[self sendExpandedMessage:message toShip:(ShipEntity*)[self primaryTarget]];
[self sendExpandedMessage:message toShip:[self primaryTarget]];
}
- (void) markTargetForFines
{
ShipEntity* ship = (ShipEntity*)[self primaryTarget];
if ((!ship)||(ship->status == STATUS_DEAD)||(ship->status == STATUS_DOCKED))
ShipEntity *ship = [self primaryTarget];
if ((ship == nil) || (ship->status == STATUS_DEAD) || (ship->status == STATUS_DOCKED))
{
primaryTarget = NO_TARGET;
[shipAI reactToMessage:@"TARGET_LOST"];
return;
}
if ([(ShipEntity*)[self primaryTarget] markForFines])
[shipAI message:@"TARGET_MARKED"];
if ([ship markForFines]) [shipAI message:@"TARGET_MARKED"];
}
@ -1454,8 +1443,8 @@ WormholeEntity* whole;
{
if ((isStation)||(scanClass == CLASS_POLICE))
{
ShipEntity* ship = (ShipEntity*)[self primaryTarget];
if ((!ship)||(ship->status == STATUS_DEAD)||(ship->status == STATUS_DOCKED))
ShipEntity *ship = [self primaryTarget];
if ((ship == nil) || (ship->status == STATUS_DEAD) || (ship->status == STATUS_DOCKED))
{
primaryTarget = NO_TARGET;
[shipAI reactToMessage:@"TARGET_LOST"];
@ -1480,7 +1469,7 @@ WormholeEntity* whole;
for (i = 0; i < n_scanned_ships; i++)
{
ShipEntity *thing = scanned_ships[i];
if ([[thing roles] rangeOfString:@"boulder"].location != NSNotFound)
if ([thing hasRole:@"boulder"])
{
GLfloat d2 = distance2_scanned_ships[i];
if (d2 < found_d2)
@ -1495,7 +1484,7 @@ WormholeEntity* whole;
for (i = 0; i < n_scanned_ships; i++)
{
ShipEntity *thing = scanned_ships[i];
if ([[thing roles] rangeOfString:@"asteroid"].location != NSNotFound)
if ([thing hasRole:@"boulder"])
{
GLfloat d2 = distance2_scanned_ships[i];
if (d2 < found_d2)
@ -1507,10 +1496,8 @@ WormholeEntity* whole;
}
}
if (found_target != NO_TARGET)
[shipAI message:@"TARGET_FOUND"];
else
[shipAI message:@"NOTHING_FOUND"];
if (found_target != NO_TARGET) [shipAI message:@"TARGET_FOUND"];
else [shipAI message:@"NOTHING_FOUND"];
}
@ -1529,10 +1516,8 @@ WormholeEntity* whole;
Vector d0 = (the_target) ? the_target->position : kZeroVector;
v0.x += (randf() - 0.5)*collision_radius; v0.y += (randf() - 0.5)*collision_radius; v0.z += (randf() - 0.5)*collision_radius;
v0.x -= d0.x; v0.y -= d0.y; v0.z -= d0.z;
if (v0.x||v0.y||v0.z)
v0 = unit_vector(&v0);
else
v0.z = -1.0;
v0 = vector_normal_or_fallback(v0, make_vector(0, 0, -1));
v0.x *= bo_distance; v0.y *= bo_distance; v0.z *= bo_distance;
v0.x += d0.x; v0.y += d0.y; v0.z += d0.z;
coordinates = v0;
@ -1542,9 +1527,7 @@ WormholeEntity* whole;
- (void) requestNewTarget
{
ShipEntity* mother = nil;
if ([self owner])
mother = (ShipEntity*)[self owner];
ShipEntity *mother = [self owner];
if ((mother == nil)&&([UNIVERSE entityForUniversalID:groupID]))
mother = [UNIVERSE entityForUniversalID:groupID];
if (!mother)
@ -1565,7 +1548,7 @@ WormholeEntity* whole;
ShipEntity *thing = scanned_ships[i];
GLfloat d2 = distance2_scanned_ships[i];
GLfloat e1 = [thing energy];
if (((thing->scanClass == CLASS_THARGOID)||(([thing primaryTarget] == mother)&&([thing hasHostileTarget])))&&(d2 < found_d2))
if ((d2 < found_d2) && ([thing isThargoid] || (([thing primaryTarget] == mother) && [thing hasHostileTarget])))
{
if (e1 > max_e)
{
@ -1576,10 +1559,8 @@ WormholeEntity* whole;
}
}
if (found_target != NO_TARGET)
[shipAI message:@"TARGET_FOUND"];
else
[shipAI message:@"NOTHING_FOUND"];
if (found_target != NO_TARGET) [shipAI message:@"TARGET_FOUND"];
else [shipAI message:@"NOTHING_FOUND"];
}
@ -1610,7 +1591,7 @@ WormholeEntity* whole;
{
ShipEntity *thing = scanned_ships[i];
GLfloat d2 = distance2_scanned_ships[i];
if ((thing->scanClass != CLASS_CARGO)&&(thing->status != STATUS_DOCKED)&&([[thing roles] isEqual:scanRole])&&(d2 < found_d2))
if ((d2 < found_d2) && (thing->scanClass != CLASS_CARGO) && (thing->status != STATUS_DOCKED) && ([thing hasPrimaryRole:scanRole]))
{
found_target = thing->universalID;
found_d2 = d2;
@ -1873,7 +1854,7 @@ WormholeEntity* whole;
{
// two point - one at z - cr one at z + cr
ShipEntity *ship = [UNIVERSE entityForUniversalID:primaryTarget];
if (!ship)
if (ship == nil)
{
[shipAI message:@"NOTHING_FOUND"];
return;

View File

@ -145,7 +145,7 @@ typedef enum
- (void) addShipToLaunchQueue:(ShipEntity *) ship;
- (unsigned) countShipsInLaunchQueueWithRole:(NSString *) a_role;
- (unsigned) countShipsInLaunchQueueWithPrimaryRole:(NSString *)role;
- (void) launchShip:(ShipEntity *) ship;

View File

@ -525,8 +525,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
int corridor_count = 9;
int corridor_final_approach = 3;
int ship_id = [ship universalID];
NSString* shipID = [NSString stringWithFormat:@"%d", ship_id];
NSNumber *shipID = [NSNumber numberWithUnsignedShort:[ship universalID]];
Vector launchVector = vector_forward_from_quaternion(quaternion_multiply(port_orientation, orientation));
Vector temp = (fabsf(launchVector.x) < 0.8)? make_vector(1,0,0) : make_vector(0,1,0);
@ -534,9 +533,8 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
Vector rightVector = cross_product(launchVector, temp);
Vector upVector = cross_product(launchVector, rightVector);
// will select a direction for offset based on the shipID
//
int offset_id = ship_id & 0xf; // 16 point compass
// will select a direction for offset based on the entity personality (was ship ID)
int offset_id = [ship entityPersonalityInt] & 0xf; // 16 point compass
double c = cos(offset_id * M_PI * ONE_EIGHTH);
double s = sin(offset_id * M_PI * ONE_EIGHTH);
@ -1109,15 +1107,14 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
}
- (unsigned) countShipsInLaunchQueueWithRole:(NSString *) a_role
- (unsigned) countShipsInLaunchQueueWithPrimaryRole:(NSString *)role
{
if ([launchQueue count] == 0)
return 0;
unsigned i;
unsigned result = 0;
unsigned i, count, result = 0;
count = [launchQueue count];
for (i = 0; i < [launchQueue count]; i++)
{
if ([[(ShipEntity *)[launchQueue objectAtIndex:i] roles] isEqual:a_role])
if ([[launchQueue objectAtIndex:i] hasPrimaryRole:role])
result++;
}
return result;
@ -1167,26 +1164,25 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
// set last launch time to avoid clashes with outgoing ships
last_launch_time = [UNIVERSE getTime];
if ([[ship roles] isEqual:@"shuttle"])
docked_shuttles++;
if ([[ship roles] isEqual:@"trader"])
docked_traders++;
if ([[ship roles] isEqual:@"police"])
police_launched--;
if ([[ship roles] isEqual:@"hermit-ship"])
police_launched--;
if ([[ship roles] isEqual:@"defense_ship"])
police_launched--;
if ([[ship roles] isEqual:@"scavenger"]||[[ship roles] isEqual:@"miner"]) // treat miners and scavengers alike!
scavengers_launched--;
if ([ship isShuttle]) docked_shuttles++;
else if ([ship isTrader] && ![ship isPlayer]) docked_traders++;
else if (([ship isPolice] && ![ship isEscort]) || [ship hasPrimaryRole:@"hermit-ship"] || [ship hasPrimaryRole:@"defense_ship"])
{
if (0 < police_launched) police_launched--;
}
else if ([ship hasPrimaryRole:@"scavenger"] || [ship hasPrimaryRole:@"miner"]) // treat miners and scavengers alike!
{
if (0 < scavengers_launched) scavengers_launched--;
}
OOUniversalID ship_id = [ship universalID];
NSNumber *shipID = [NSNumber numberWithUnsignedShort:ship_id];
int ship_id = [ship universalID];
NSString* shipID = [NSString stringWithFormat:@"%d", ship_id];
[shipsOnApproach removeObjectForKey:shipID];
if ([shipsOnApproach count] == 0)
[shipAI message:@"DOCKING_COMPLETE"];
int i; // clear any previously owned docking stages
unsigned i; // clear any previously owned docking stages
for (i = 0; i < MAX_DOCKING_STAGES; i++)
if ((id_lock[i] == ship_id)||([UNIVERSE entityForUniversalID:id_lock[i]] == nil))
id_lock[i] = NO_TARGET;
@ -1346,7 +1342,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
[OOCharacter randomCharacterWithRole: @"police"
andOriginalSystem: [UNIVERSE systemSeed]]]];
[police_ship setRoles:@"police"];
[police_ship setPrimaryRole:@"police"];
[police_ship addTarget:[UNIVERSE entityForUniversalID:police_target]];
[police_ship setScanClass: CLASS_POLICE];
[police_ship setBounty:0];
@ -1399,7 +1395,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
if (!defense_ship)
return;
[defense_ship setRoles:@"defense_ship"];
[defense_ship setPrimaryRole:@"defense_ship"];
police_launched++;
@ -1429,7 +1425,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
{
ShipEntity *scavenger_ship;
unsigned scavs = [UNIVERSE countShipsWithRole:@"scavenger" inRange:SCANNER_MAX_RANGE ofEntity:self] + [self countShipsInLaunchQueueWithRole:@"scavenger"];
unsigned scavs = [UNIVERSE countShipsWithRole:@"scavenger" inRange:SCANNER_MAX_RANGE ofEntity:self] + [self countShipsInLaunchQueueWithPrimaryRole:@"scavenger"];
if (scavs >= max_scavengers) return;
if (scavengers_launched >= max_scavengers) return;
@ -1457,7 +1453,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
{
ShipEntity *miner_ship;
int n_miners = [UNIVERSE countShipsWithRole:@"miner" inRange:SCANNER_MAX_RANGE ofEntity:self] + [self countShipsInLaunchQueueWithRole:@"miner"];
int n_miners = [UNIVERSE countShipsWithRole:@"miner" inRange:SCANNER_MAX_RANGE ofEntity:self] + [self countShipsInLaunchQueueWithPrimaryRole:@"miner"];
if (n_miners >= 1) // just the one
return;
@ -1565,7 +1561,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
[OOCharacter randomCharacterWithRole: @"trader"
andOriginalSystem: [UNIVERSE systemSeed]]]];
[trader_ship setRoles:@"trader"];
[trader_ship setPrimaryRole:@"trader"];
[trader_ship setScanClass: CLASS_NEUTRAL];
[trader_ship setCargoFlag:CARGO_FLAG_FULL_PLENTIFUL];
@ -1641,7 +1637,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
[patrol_ship switchLightsOff];
[patrol_ship setScanClass: CLASS_POLICE];
[patrol_ship setRoles:@"police"];
[patrol_ship setPrimaryRole:@"police"];
[patrol_ship setBounty:0];
[patrol_ship setGroupID:universalID]; // who's your Daddy
[[patrol_ship getAI] setStateMachine:@"planetPatrolAI.plist"];
@ -1664,7 +1660,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
[ship setCrew:[NSArray arrayWithObject:
[OOCharacter randomCharacterWithRole: role
andOriginalSystem: [UNIVERSE systemSeed]]]];
[ship setRoles: role];
[ship setPrimaryRole:role];
[ship setGroupID:universalID]; // who's your Daddy
[self addShipToLaunchQueue:ship];
[ship release];
@ -1687,8 +1683,8 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
if (scanClass == CLASS_ROCK) // ie we're a rock hermit or similar
{
// set the roles so that we break up into rocks!
roles = @"asteroid";
// set the role so that we break up into rocks!
[self setPrimaryRole:@"asteroid"];
being_mined = YES;
}
@ -1780,7 +1776,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
if (gDebugFlags & DEBUG_ENTITIES)
{
NSString* result = [[NSString alloc] initWithFormat:@"<StationEntity %@ %d (%@)%@%@ // %@>",
name, universalID, roles, (UNIVERSE == nil)? @" (not in UNIVERSE)":@"", ([self isRotatingStation])? @" (rotating)":@"", collisionRegion];
name, universalID, roleSet, (UNIVERSE == nil)? @" (not in UNIVERSE)":@"", ([self isRotatingStation])? @" (rotating)":@"", collisionRegion];
return [result autorelease];
}
#endif

View File

@ -1294,7 +1294,8 @@ static BOOL hostiles;
{
if ([player missileForStation:i])
{
NSString *miss_roles = [[player missileForStation:i] roles];
// TODO: copy icon data into missile object instead of looking it up each time. Possibly make weapon stores a ShipEntity subclass?
NSString *miss_roles = [[player missileForStation:i] primaryRole];
NSArray *miss_icon = [[UNIVERSE descriptions] arrayForKey:miss_roles];
if (i == [player activeMissile])
{

View File

@ -58,6 +58,7 @@ SOFTWARE.
NSString *_roleString;
NSDictionary *_rolesAndProbabilities;
NSSet *_roles;
float _totalProb;
}
+ (id)roleSetWithString:(NSString *)roleString;
@ -75,8 +76,12 @@ SOFTWARE.
- (NSArray *)sortedRoles;
- (NSDictionary *)rolesAndProbabilities;
// Returns a random role, taking probabilities into account.
- (NSString *)anyRole;
// Creating modified copies of role sets:
- (id)roleSetWithAddedRole:(NSString *)role probability:(float)probability;
- (id)roleSetWithAddedRoleIfNotSet:(NSString *)role probability:(float)probability; // Unlike the above, does not change probability if role exists.
- (id)roleSetWithRemovedRole:(NSString *)role;
@end

View File

@ -49,6 +49,8 @@ SOFTWARE.
#import "OORoleSet.h"
#import "OOStringParsing.h"
#import "OOCollectionExtractors.h"
#import "OOLogging.h"
@interface OORoleSet (OOPrivate)
@ -109,6 +111,22 @@ SOFTWARE.
}
- (BOOL)isEqual:(id)other
{
if ([other isKindOfClass:[OORoleSet class]])
{
return [_rolesAndProbabilities isEqual:[other rolesAndProbabilities]];
}
else return NO;
}
- (unsigned)hash
{
return [_rolesAndProbabilities hash];
}
- (id)copyWithZone:(NSZone *)zone
{
// Note: since object is immutable, a copy is no different from the original.
@ -159,11 +177,7 @@ SOFTWARE.
- (float)probabilityForRole:(NSString *)role
{
NSNumber *value = nil;
if (role != nil) value = [_rolesAndProbabilities objectForKey:role];
if (value != nil) return [value floatValue];
else return 0.0f;
return [_rolesAndProbabilities floatForKey:role defaultValue:0.0f];
}
@ -189,11 +203,52 @@ SOFTWARE.
}
- (NSString *)anyRole
{
NSEnumerator *roleEnum = nil;
NSString *role;
float prob, selected;
selected = randf() * _totalProb;
prob = 0.0f;
for (roleEnum = [_rolesAndProbabilities objectEnumerator]; (role = [roleEnum nextObject]); )
{
prob += [_rolesAndProbabilities floatForKey:role];
if (selected <= prob) break;
}
if (role == nil)
{
role = [[self roles] anyObject];
OOLog(@"roleSet.anyRole.failed", @"Could not get a weighted-random role from role set %@, returning unweighted selection %@. TotalProb: %g, selected: %g, prob at end: %@", self, role, _totalProb, selected, prob);
}
return role;
}
- (id)roleSetWithAddedRoleIfNotSet:(NSString *)role probability:(float)probability
{
NSMutableDictionary *dict = nil;
if (role == nil || probability < 0 || ([self hasRole:role] && [self probabilityForRole:role] == probability))
{
return [[self copy] autorelease];
}
dict = [[_rolesAndProbabilities mutableCopy] autorelease];
[dict setObject:[NSNumber numberWithFloat:probability] forKey:role];
return [[[[self class] alloc] initWithRolesAndProbabilities:dict] autorelease];
}
- (id)roleSetWithAddedRole:(NSString *)role probability:(float)probability
{
NSMutableDictionary *dict = nil;
if (role == nil || probability < 0 || [self hasRole:role]) return [[self copy] autorelease];
if (role == nil || probability < 0 || [self hasRole:role])
{
return [[self copy] autorelease];
}
dict = [[_rolesAndProbabilities mutableCopy] autorelease];
[dict setObject:[NSNumber numberWithFloat:probability] forKey:role];
@ -219,6 +274,10 @@ SOFTWARE.
- (id)initWithRolesAndProbabilities:(NSDictionary *)dict
{
NSEnumerator *roleEnum = nil;
NSString *role;
float prob;
if (dict == nil)
{
[self release];
@ -229,6 +288,20 @@ SOFTWARE.
// Note: _roles and _roleString are derived on the fly as needed.
_rolesAndProbabilities = [dict copy];
for (roleEnum = [dict keyEnumerator]; (role = [roleEnum nextObject]); )
{
prob = [dict floatForKey:role defaultValue:-1];
if (prob < 0)
{
OOLog(@"roleSet.badValue", @"Attempt to create a role set with negative or non-numerical probability for role %@.", role);
[self release];
return nil;
}
_totalProb += prob;
}
return self;
}

View File

@ -35,12 +35,6 @@ MA 02110-1301, USA.
- (NSString *)jsClassName;
- (BOOL)isShip;
- (BOOL)isStation;
- (BOOL)isSubEntity;
- (BOOL)isPlayer;
- (BOOL)isPlanet;
// Internal:
- (void)getJSClass:(JSClass **)outClass andPrototype:(JSObject **)outPrototype;
- (void)deleteJSSelf;

View File

@ -48,36 +48,6 @@ MA 02110-1301, USA.
}
- (BOOL)isShip
{
return isShip;
}
- (BOOL)isStation
{
return isStation;
}
- (BOOL)isSubEntity
{
return isSubentity;
}
- (BOOL)isPlayer
{
return isPlayer;
}
- (BOOL)isPlanet
{
return isPlanet;
}
- (jsval)javaScriptValueInContext:(JSContext *)context
{
JSClass *class = NULL;

View File

@ -30,6 +30,7 @@ MA 02110-1301, USA.
#import "AI.h"
#import "OOStringParsing.h"
#import "EntityOOJavaScriptExtensions.h"
#import "OORoleSet.h"
static JSObject *sShipPrototype;
@ -45,8 +46,6 @@ static JSBool ShipReactToAIMessage(JSContext *context, JSObject *this, uintN arg
static JSBool ShipDeployEscorts(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult);
static JSBool ShipDockEscorts(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult);
static NSArray *ArrayOfRoles(NSString *rolesString);
static JSExtendedClass sShipClass =
{
@ -76,6 +75,8 @@ enum
// Property IDs
kShip_shipDescription, // name, string, read-only
kShip_roles, // roles, array, read-only
kShip_roleProbabilities, // roles and probabilities, dictionary, read-only
kShip_primaryRole, // Primary role, string, read-only
kShip_AI, // AI state machine name, string, read/write
kShip_AIState, // AI state machine state, string, read/write
kShip_fuel, // fuel, float, read/write
@ -102,7 +103,11 @@ enum
kShip_maxCargo, // maximum cargo, integer, read-only
kShip_speed, // current flight speed, double, read-only (should probably be read/write, but may interfere with AI behaviour)
kShip_maxSpeed, // maximum flight speed, double, read-only
kShip_script // script, Script, read-only
kShip_script, // script, Script, read-only
kShip_isPirate, // is pirate, boolean, read-only
kShip_isPolice, // is police, boolean, read-only
kShip_isThargoid, // is thargoid, boolean, read-only
kShip_isTrader // is trader, boolean, read-only
};
@ -111,6 +116,8 @@ static JSPropertySpec sShipProperties[] =
// JS name ID flags
{ "shipDescription", kShip_shipDescription, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "roles", kShip_roles, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "roleProbabilities", kShip_roleProbabilities, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "primaryRole", kShip_primaryRole, JSPROP_PERMANENT | JSPROP_ENUMERATE },
{ "AI", kShip_AI, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "AIState", kShip_AIState, JSPROP_PERMANENT | JSPROP_ENUMERATE },
{ "fuel", kShip_fuel, JSPROP_PERMANENT | JSPROP_ENUMERATE },
@ -138,6 +145,10 @@ static JSPropertySpec sShipProperties[] =
{ "speed", kShip_speed, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "maxSpeed", kShip_maxSpeed, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "script", kShip_script, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "isPirate", kShip_isPirate, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "isPolice", kShip_isPolice, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "isThargoid", kShip_isThargoid, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "isTrader", kShip_isTrader, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ 0 }
};
@ -207,7 +218,15 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js
break;
case kShip_roles:
result = ArrayOfRoles([entity roles]);
result = [[entity roleSet] sortedRoles];
break;
case kShip_roleProbabilities:
result = [[entity roleSet] rolesAndProbabilities];
break;
case kShip_primaryRole:
result = [entity primaryRole];
break;
case kShip_AI:
@ -324,6 +343,22 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js
if (result == nil) result = [NSNull null];
break;
case kShip_isPirate:
*outValue = BOOLToJSVal([entity isPirate]);
break;
case kShip_isPolice:
*outValue = BOOLToJSVal([entity isPolice]);
break;
case kShip_isThargoid:
*outValue = BOOLToJSVal([entity isThargoid]);
break;
case kShip_isTrader:
*outValue = BOOLToJSVal([entity isTrader]);
break;
default:
OOReportJavaScriptBadPropertySelector(context, @"Ship", JSVAL_TO_INT(name));
return NO;
@ -349,10 +384,22 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js
switch (JSVAL_TO_INT(name))
{
case kShip_primaryRole:
if (entity->isPlayer)
{
OOReportJavaScriptError(context, @"Ship.AIState [setter]: cannot set %@ for player.", "primary role");
}
else
{
strVal = [NSString stringWithJavaScriptValue:*value inContext:context];
if (strVal != nil) [entity setPrimaryRole:strVal];
}
break;
case kShip_AIState:
if (entity->isPlayer)
{
OOReportJavaScriptError(context, @"Ship.AIState [setter]: cannot set AI state for player.");
OOReportJavaScriptError(context, @"Ship.AIState [setter]: cannot set %@ for player.", "AI state");
}
else
{
@ -550,36 +597,3 @@ static JSBool ShipDockEscorts(JSContext *context, JSObject *this, uintN argc, js
[thisEnt dockEscorts];
return YES;
}
static NSArray *ArrayOfRoles(NSString *rolesString)
{
NSArray *rawRoles = nil;
NSMutableArray *filteredRoles = nil;
NSAutoreleasePool *pool = nil;
unsigned i, count;
NSString *role = nil;
NSRange parenRange;
pool = [[NSAutoreleasePool alloc] init];
rawRoles = ScanTokensFromString(rolesString);
count = [rawRoles count];
filteredRoles = [NSMutableArray arrayWithCapacity:count];
for (i = 0; i != count; ++i)
{
role = [rawRoles objectAtIndex:i];
// Strip probability from string
parenRange = [role rangeOfString:@"("];
if (parenRange.location != NSNotFound)
{
role = [role substringToIndex:parenRange.location];
}
[filteredRoles addObject:role];
}
[filteredRoles retain];
[pool release];
return filteredRoles;
}

View File

@ -443,6 +443,7 @@ static JSBool SystemAddShips(JSContext *context, JSObject *this, uintN argc, jsv
}
// Note: need a way to specify the use of witchspace-in effects (as in legacy_addShips).
OOReportJavaScriptError(context, @"System.addShips(): not implemented.");
return YES;
@ -461,7 +462,7 @@ static JSBool SystemLegacyAddShips(JSContext *context, JSObject *this, uintN arg
return YES;
}
while (count--) [UNIVERSE witchspaceShipWithRole:role];
while (count--) [UNIVERSE witchspaceShipWithPrimaryRole:role];
return YES;
}

View File

@ -32,6 +32,11 @@ MA 02110-1301, USA.
#import "OOWeakReference.h"
#import "OOTypes.h"
@class GameController, CollisionRegion, MyOpenGLView, GuiDisplayGen,
Entity, ShipEntity, StationEntity, PlanetEntity, PlayerEntity,
OORoleSet;
#define CROSSHAIR_SIZE 32.0
enum
@ -108,9 +113,6 @@ enum
#define BILLBOARD_DEPTH 50000.0
@class GameController, CollisionRegion, MyOpenGLView, GuiDisplayGen;
@class Entity, ShipEntity, StationEntity, PlanetEntity, PlayerEntity;
@interface Universe: NSObject <OOWeakReferenceSupport>
{
@ -277,7 +279,7 @@ enum
- (BOOL) addShips:(int) howMany withRole:(NSString *) desc nearPosition:(Vector) pos withCoordinateSystem:(NSString *) system withinRadius:(GLfloat) radius;
- (BOOL) addShips:(int) howMany withRole:(NSString *) desc intoBoundingBox:(BoundingBox) bbox;
- (BOOL) spawnShip:(NSString *) shipdesc;
- (void) witchspaceShipWithRole:(NSString *) desc;
- (void) witchspaceShipWithPrimaryRole:(NSString *)role;
- (void) spawnShipWithRole:(NSString *) desc near:(Entity *) entity;
- (void) set_up_break_pattern:(Vector) pos quaternion:(Quaternion) q;
@ -353,10 +355,12 @@ enum
- (int) getFirstEntityHitByLaserFromEntity:(Entity *) e1 inView:(int) viewdir offset:(Vector) offset rangeFound:(GLfloat*)range_ptr;
- (int) getFirstEntityTargettedByPlayer:(PlayerEntity*) player;
- (NSArray *) getEntitiesWithinRange:(double) range1 ofEntity:(Entity *) e1;
- (unsigned) countShipsWithRole:(NSString *) desc inRange:(double) range1 ofEntity:(Entity *)e1;
- (unsigned) countShipsWithRole:(NSString *) desc;
- (void) sendShipsWithRole:(NSString *) desc messageToAI:(NSString *) ms;
- (NSArray *) getEntitiesWithinRange:(double)range ofEntity:(Entity *)entity;
- (unsigned) countShipsWithRole:(NSString *)role inRange:(double)range ofEntity:(Entity *)entity;
- (unsigned) countShipsWithRole:(NSString *)role;
- (unsigned) countShipsWithPrimaryRole:(NSString *)role inRange:(double)range ofEntity:(Entity *)entity;
- (unsigned) countShipsWithPrimaryRole:(NSString *)role;
- (void) sendShipsWithPrimaryRole:(NSString *)role messageToAI:(NSString *)message;
- (OOTimeAbsolute) getTime;
- (OOTimeDelta) getTimeDelta;

View File

@ -85,11 +85,21 @@ static NSComparisonResult compareName(NSDictionary *dict1, NSDictionary *dict2,
static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2, void * context);
typedef BOOL (*ShipFilterPredicate)(ShipEntity *ship, id parameter);
static BOOL HasRolePredicate(ShipEntity *ship, id parameter);
static BOOL HasPrimaryRolePredicate(ShipEntity *ship, id parameter);
@interface Universe (OOPrivate)
- (BOOL)doRemoveEntity:(Entity *)entity;
- (NSDictionary *)getDictionaryForShip:(NSString *)desc recursionLimit:(uint32_t)recursionLimit;
- (unsigned) countShipsWithPredicate:(ShipFilterPredicate)predicate
parameter:(id)parameter
inRange:(double)range1
ofEntity:(Entity *)e1;
@end
@ -1398,7 +1408,7 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
[OOCharacter randomCharacterWithRole:@"police"
andOriginalSystem: (randf() > 0.05)? systems[Ranrot() & 255]:system_seed]]];
[hunter_ship setRoles:@"police"];
[hunter_ship setPrimaryRole:@"police"];
if (hunter_ship->scanClass == CLASS_NOT_SET)
[hunter_ship setScanClass: CLASS_POLICE];
while (((Ranrot() & 7) + 2 < government)&&([hunter_ship escortCount] < 6))
@ -1523,7 +1533,7 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
[OOCharacter randomCharacterWithRole:@"trader"
andOriginalSystem: (randf() > 0.85)? systems[Ranrot() & 255]:system_seed]]];
[trader_ship setRoles:@"trader"]; // set this to allow escorts to pair with the ship
[trader_ship setPrimaryRole:@"trader"]; // set this to allow escorts to pair with the ship
if ((trader_ship)&&(trader_ship->scanClass == CLASS_NOT_SET))
[trader_ship setScanClass: CLASS_NEUTRAL];
[trader_ship setPosition:launchPos];
@ -1635,7 +1645,7 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
[OOCharacter randomCharacterWithRole:@"police"
andOriginalSystem: (randf() > 0.05)? systems[Ranrot() & 255]:system_seed]]];
[hunter_ship setRoles:@"police"];
[hunter_ship setPrimaryRole:@"police"];
if (hunter_ship->scanClass == CLASS_NOT_SET)
[hunter_ship setScanClass: CLASS_POLICE];
while (((Ranrot() & 7) + 2 < government)&&([hunter_ship escortCount] < 6))
@ -2335,16 +2345,17 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
}
- (void) witchspaceShipWithRole:(NSString *)desc
- (void) witchspaceShipWithPrimaryRole:(NSString *)role
{
// adds a ship exiting witchspace (corollary of when ships leave the system)
ShipEntity *ship;
ship = [self newShipWithRole:desc]; // retain count = 1
ShipEntity *ship = nil;
ship = [self newShipWithRole:role]; // retain count = 1
if (ship)
{
if ((ship->scanClass == CLASS_NO_DRAW)||(ship->scanClass == CLASS_NOT_SET))
[ship setScanClass: CLASS_NEUTRAL];
if ([desc isEqual:@"trader"])
if ([role isEqual:@"trader"])
{
[ship setCargoFlag: CARGO_FLAG_FULL_SCARCE];
if (randf() > 0.10)
@ -2352,14 +2363,14 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
else
[[ship getAI] setStateMachine:@"route2sunskimAI.plist"]; // route3 really, but the AI's the same
}
if ([desc isEqual:@"pirate"])
if ([role isEqual:@"pirate"])
{
[ship setCargoFlag: CARGO_FLAG_PIRATE];
[ship setBounty: (Ranrot() & 7) + (Ranrot() & 7) + ((randf() < 0.05)? 63 : 23)]; // they already have a price on their heads
}
if (![ship crew])
[ship setCrew:[NSArray arrayWithObject:
[OOCharacter randomCharacterWithRole: desc
[OOCharacter randomCharacterWithRole:role
andOriginalSystem: systems[Ranrot() & 255]]]];
[ship leaveWitchspace]; // gets added to the universe here!
@ -2784,45 +2795,6 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
foundf += chance;
}
}
/*for (shipEnum = [shipdata keyEnumerator]; (shipKey = [shipEnum nextObject]); )
{
shipDict = [shipdata dictionaryForKey:shipKey];
shipRoles = ScanTokensFromString([shipDict stringForKey:@"roles"]);
if ([shipDict arrayForKey:@"conditions"])
{
PlayerEntity* player = [PlayerEntity sharedPlayer];
if ((player) && (player->isPlayer) && (![player checkCouplet:shipDict onEntity:player]))
shipRoles = [NSArray array]; // empty array - ship does not meet conditions listed
}
for (j = 0; j < [shipRoles count]; j++)
{
NSString *putative_roles = [shipRoles stringAtIndex:j];
GLfloat chance = 1.0;
if (putative_roles)
{
if ([putative_roles hasPrefix:search] && ([putative_roles rangeOfString:@"("].location != NSNotFound))
{
NSScanner* scanner = [NSScanner scannerWithString:putative_roles]; // scanner
[scanner scanUpToString:@"(" intoString:&putative_roles]; // look for '('
[scanner scanString:@"(" intoString:NULL]; // skip over it
if (![scanner scanFloat:&chance]) chance = 1.0; // try to scan a float
// ignore from '(' onwards (lazy)
}
if ([putative_roles isEqual:search] && (chance > 0.0))
{
[foundShips addObject:shipKey];
[foundChance addObject:[NSNumber numberWithFloat:chance]];
found++;
foundf += chance;
}
}
}
}*/
i = 0;
@ -2845,7 +2817,7 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
shipKey = [foundShips stringAtIndex:i];
ship = [self newShipWithName:shipKey]; // may return nil if not found!
[ship setRoles:search]; // set its roles to this one particular chosen role
[ship setPrimaryRole:search];
shipDict = [shipdata dictionaryForKey:shipKey];
if ([shipDict fuzzyBooleanForKey:@"auto_ai" defaultValue:YES])
@ -2876,7 +2848,7 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
[pool release]; // tidy everything up
// check a trader has fuel
if ([ship fuel] == 0 &&([[ship roles] rangeOfString:@"trader"].location != NSNotFound))
if ([ship fuel] == 0 && [[ship primaryRole] isEqual:@"trader"])
{
[ship setFuel: PLAYER_MAX_FUEL];
}
@ -2916,6 +2888,10 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
else [localException raise];
NS_ENDHANDLER
// Set primary role to same as ship name, if ship name is also a role.
// Otherwise, if caller doesn't set a role, one will be selected randomly.
if ([ship hasRole:desc]) [ship setPrimaryRole:desc];
return ship; // retain count = 1
}
@ -4602,65 +4578,37 @@ static BOOL MaintainLinkedLists(Universe* uni)
}
- (unsigned) countShipsWithRole:(NSString *) desc inRange:(double) range1 ofEntity:(Entity *)e1
- (unsigned) countShipsWithRole:(NSString *)role inRange:(double)range ofEntity:(Entity *)entity
{
if (!e1) return 0;
unsigned i, found;
unsigned ent_count = n_entities;
unsigned ship_count = 0;
Entity *my_entities[ent_count];
for (i = 0; i < ent_count; i++)
if (sortedEntities[i]->isShip)
my_entities[ship_count++] = [sortedEntities[i] retain]; // retained
found = 0;
Vector p1 = e1->position;
for (i = 0; i < ship_count; i++)
{
Entity *e2 = my_entities[i];
if ((e2 != e1)&&([[(ShipEntity *)e2 roles] isEqual:desc]))
{
Vector p2 = e2->position;
p2.x -= p1.x; p2.y -= p1.y; p2.z -= p1.z;
double cr = range1 + e2->collision_radius;
double d2 = p2.x*p2.x + p2.y*p2.y + p2.z*p2.z - cr*cr;
if (d2 < 0)
found++;
}
}
for (i = 0; i < ship_count; i++)
[my_entities[i] release]; // released
return found;
return [self countShipsWithPredicate:HasRolePredicate
parameter:role
inRange:range
ofEntity:entity];
}
- (unsigned) countShipsWithRole:(NSString *) desc
- (unsigned) countShipsWithRole:(NSString *)role
{
unsigned i, found;
unsigned ent_count = n_entities;
unsigned ship_count = 0;
Entity *my_entities[ent_count];
for (i = 0; i < ent_count; i++)
if (sortedEntities[i]->isShip)
my_entities[ship_count++] = [sortedEntities[i] retain]; // retained
found = 0;
for (i = 0; i < ship_count; i++)
{
Entity *e2 = my_entities[i];
if (([[(ShipEntity *)e2 roles] isEqual:desc]))
found++;
}
for (i = 0; i < ship_count; i++)
[my_entities[i] release]; // released
return found;
return [self countShipsWithRole:role inRange:-1 ofEntity:nil];
}
- (void) sendShipsWithRole:(NSString *) desc messageToAI:(NSString *) ms
- (unsigned) countShipsWithPrimaryRole:(NSString *)role inRange:(double)range ofEntity:(Entity *)entity
{
return [self countShipsWithPredicate:HasPrimaryRolePredicate
parameter:role
inRange:range
ofEntity:entity];
}
- (unsigned) countShipsWithPrimaryRole:(NSString *)role
{
return [self countShipsWithPrimaryRole:role inRange:-1 ofEntity:nil];
}
- (void) sendShipsWithPrimaryRole:(NSString *)role messageToAI:(NSString *)ms
{
int i, found;
int ent_count = n_entities;
@ -4674,7 +4622,7 @@ static BOOL MaintainLinkedLists(Universe* uni)
for (i = 0; i < ship_count; i++)
{
Entity *e2 = my_entities[i];
if ([[(ShipEntity *)e2 roles] isEqual:desc])
if ([[(ShipEntity *)e2 primaryRole] isEqual:role])
[[(ShipEntity *)e2 getAI] reactToMessage:ms];
}
for (i = 0; i < ship_count; i++)
@ -6260,8 +6208,8 @@ static BOOL MaintainLinkedLists(Universe* uni)
- (BOOL) generateEconomicDataWithEconomy:(OOEconomyID) economy andRandomFactor:(int) random_factor
{
StationEntity *some_station = [self station];
NSString *station_roles = [some_station roles];
if ([commoditylists arrayForKey:station_roles] == nil) station_roles = @"default";
NSString *stationRole = [some_station primaryRole];
if ([commoditylists arrayForKey:stationRole] == nil) stationRole = @"default";
[commoditydata release];
commoditydata = [[self commodityDataForEconomy:economy andStation:some_station andRandomFactor:random_factor] retain];
@ -6276,8 +6224,8 @@ static BOOL MaintainLinkedLists(Universe* uni)
unsigned i;
station_roles = [[self currentSystemData] stringForKey:@"market"];
if (station_roles == nil) station_roles = [some_station roles];
if ([commoditylists arrayForKey:station_roles] == nil) station_roles = @"default";
NSString *stationRole = [some_station primaryRole];
if ([commoditylists arrayForKey:stationRole] == nil) stationRole = @"default";
ourEconomy = [NSMutableArray arrayWithArray:[commoditylists arrayForKey:station_roles]];
@ -7699,4 +7647,64 @@ static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2,
return shipdict;
}
- (unsigned) countShipsWithPredicate:(ShipFilterPredicate)predicate
parameter:(id)parameter
inRange:(double)range1
ofEntity:(Entity *)e1
{
if (e1 == nil || predicate == NULL) return 0;
unsigned i, found;
unsigned ent_count = n_entities;
unsigned ship_count = 0;
ShipEntity *my_entities[ent_count];
Vector p1;
for (i = 0; i < ent_count; i++)
if (sortedEntities[i]->isShip)
my_entities[ship_count++] = [sortedEntities[i] retain]; // retained
found = 0;
if (e1 != nil) p1 = e1->position;
else p1 = kZeroVector;
for (i = 0; i < ship_count; i++)
{
ShipEntity *e2 = my_entities[i];
if (e2 != e1 && predicate(e2, parameter))
{
double d2;
if (range1 < 0) d2 = -1; // Negative range means infinity
else
{
Vector p2 = e2->position;
p2.x -= p1.x; p2.y -= p1.y; p2.z -= p1.z;
double cr = range1 + e2->collision_radius;
d2 = p2.x*p2.x + p2.y*p2.y + p2.z*p2.z - cr*cr;
}
if (d2 < 0)
{
found++;
}
}
}
for (i = 0; i < ship_count; i++)
[my_entities[i] release]; // released
return found;
}
@end
static BOOL HasRolePredicate(ShipEntity *ship, id parameter)
{
return [ship hasRole:parameter];
}
static BOOL HasPrimaryRolePredicate(ShipEntity *ship, id parameter)
{
return [ship hasPrimaryRole:parameter];
}