53@interface StationEntity (OOPrivate)
55- (void) pullInShipIfPermitted:(
ShipEntity *)ship;
56- (void) addShipToStationCount:(
ShipEntity *)ship;
58- (void) addShipToLaunchQueue:(
ShipEntity *)ship withPriority:(BOOL)priority;
59- (unsigned) countOfShipsInLaunchQueueWithPrimaryRole:(NSString *)role;
61- (NSDictionary *) holdPositionInstructionForShip:(
ShipEntity *)ship;
67@interface StationEntity (mwDebug)
69- (NSArray *) dbgGetShipsOnApproach;
70- (NSArray *) dbgGetIdLocks;
71- (NSString *) dbgDumpIdLocks;
87 if (equivalentTechLevel == NSNotFound)
89 return [[UNIVERSE currentSystemData] oo_intForKey:KEY_TECHLEVEL];
93 return equivalentTechLevel;
100 equivalentTechLevel = value;
104- (Vector) virtualPortDimensions
106 return port_dimensions;
112 return player_reserved_dock;
116- (HPVector) beaconPosition
118 double buoy_distance = 10000.0;
120 HPVector result = HPvector_add([
self position], vectorToHPVector(vector_multiply_scalar(v_f, buoy_distance)));
126- (float) equipmentPriceFactor
128 return equipmentPriceFactor;
134 return marketCapacity;
138- (NSArray *) marketDefinition
140 return marketDefinition;
144- (NSString *) marketScriptName
146 return marketScriptName;
150- (BOOL) marketMonitored
156 return marketMonitored;
160- (BOOL) marketBroadcast
166 return marketBroadcast;
175 foreach (good, [market goods])
185 status += penalty * [manifest quantityForGood:good];
197 return [UNIVERSE commodityMarket];
201 [
self initialiseLocalMarket];
207- (void) setLocalMarket:(NSArray *) some_market
209 [[
self localMarket] loadStationAmounts:some_market];
213- (NSDictionary *) localMarketForScripting
215 return [[
self localMarket] dictionaryForScripting];
221 [[
self localMarket] setPrice:price forGood:commodity];
227 [[
self localMarket] setQuantity:quantity forGood:commodity];
231- (NSMutableArray *) localShipyard
233 return localShipyard;
237- (void) setLocalShipyard:(NSArray *) some_market
240 [localShipyard release];
241 localShipyard = [[NSMutableArray alloc] initWithArray:some_market];
245- (NSMutableDictionary *) localInterfaces
247 return localInterfaces;
253 if (definition ==
nil)
255 [localInterfaces removeObjectForKey:key];
259 [localInterfaces setObject:definition forKey:key];
267 localMarket = [[[UNIVERSE commodities] generateMarketForStation:self] retain];
272- (void) setPlanet:(OOPlanetEntity *)planet_entity
275 planet = [planet_entity universalID];
281- (OOPlanetEntity *) planet
283 return [UNIVERSE entityForUniversalID:planet];
287- (unsigned) countOfDockedContractors
289 return max_scavengers > scavengers_launched ? max_scavengers - scavengers_launched : 0;
293- (unsigned) countOfDockedPolice
295 return max_police > defenders_launched ? max_police - defenders_launched : 0;
299- (unsigned) countOfDockedDefenders
301 return max_defense_ships > defenders_launched ? max_defense_ships - defenders_launched : 0;
305- (NSEnumerator *)dockSubEntityEnumerator
307 return [[
self subEntities] objectEnumeratorFilteredWithSelector:@selector(isDock)];
311- (void) sanityCheckShipsOnApproach
314 NSEnumerator *subEnum =
nil;
317 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
319 soa += [sub pruneAndCountShipsOnApproach];
325 [shipAI message:@"DOCKING_COMPLETE"];
326 [
self doScriptEvent:OOJSID("stationDockingQueuesAreEmpty")];
334 NSEnumerator *subEnum =
nil;
338 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
340 if ([sub allowsLaunching] && [sub countOfShipsInLaunchQueue] == 0)
347 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
349 if ([sub allowsLaunching])
367- (void) abortAllDockings
369 NSEnumerator *subEnum =
nil;
371 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
376 [_shipsOnHold makeObjectsPerformSelector:@selector(sendAIMessage:) withObject:@"DOCKING_ABORTED"];
377 NSEnumerator *holdEnum =
nil;
379 for (holdEnum = [_shipsOnHold objectEnumerator]; (hold = [holdEnum nextObject]); )
381 [hold
doScriptEvent:OOJSID("stationWithdrewDockingClearance")];
390 [
self sendExpandedMessage:@"[station-docking-clearance-abort-cancelled]" toShip:player];
392 [player
doScriptEvent:OOJSID("stationWithdrewDockingClearance")];
395 [_shipsOnHold removeAllObjects];
397 [shipAI message:@"DOCKING_COMPLETE"];
398 [
self doScriptEvent:OOJSID("stationDockingQueuesAreEmpty")];
403- (void) autoDockShipsOnHold
405 NSEnumerator *onHoldEnum = [_shipsOnHold objectEnumerator];
407 while ((ship = [onHoldEnum nextObject]))
409 [
self pullInShipIfPermitted:ship];
412 [_shipsOnHold removeAllObjects];
416- (void) autoDockShipsOnApproach
418 NSEnumerator *subEnum =
nil;
420 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
425 [
self autoDockShipsOnHold];
427 [shipAI message:@"DOCKING_COMPLETE"];
428 [
self doScriptEvent:OOJSID("stationDockingQueuesAreEmpty")];
433- (Vector) portUpVectorForShip:(
ShipEntity*) ship
435 NSEnumerator *subEnum =
nil;
437 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
439 if ([sub shipIsInDockingQueue:ship])
450 NSMutableDictionary *acc = [NSMutableDictionary dictionaryWithCapacity:8];
451 [acc oo_setHPVector:coords forKey:@"destination"];
452 [acc oo_setFloat:speed forKey:@"speed"];
453 [acc oo_setFloat:range forKey:@"range"];
454 [acc setObject:[[station
weakRetain] autorelease] forKey:@"station"];
455 [acc oo_setBool:match_rotation forKey:@"match_rotation"];
456 [acc oo_setInteger:docking_stage forKey:@"docking_stage"];
459 [acc setObject:ai_message forKey:@"ai_message"];
463 [acc setObject:comms_message forKey:@"comms_message"];
465 return [NSDictionary dictionaryWithDictionary:acc];
472- (NSDictionary *) dockingInstructionsForShip:(
ShipEntity *) ship
474 if (ship ==
nil)
return nil;
476 [
self doScriptEvent:OOJSID("stationReceivedDockingRequest") withArgument:ship];
480 player_reserved_dock =
nil;
483 if ([ship isPlayer] && [ship legalStatus] > 50)
486 return OOMakeDockingInstructions(
self, [ship position], 0, 100,
@"DOCKING_REFUSED",
@"[station-docking-refused-to-fugitive]", NO, -1);
489 if (magnitude2(velocity) > 1.0 ||
490 fabs(flightPitch) > 0.01 ||
491 fabs(flightYaw) > 0.01)
494 return [
self holdPositionInstructionForShip:ship];
499 NSEnumerator *subEnum =
nil;
501 NSString *docking =
nil;
503 NSUInteger queue = 100;
505 BOOL alldockstoosmall = YES;
506 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
508 if ([sub shipIsInDockingQueue:ship])
512 alldockstoosmall = NO;
515 if (player_is_ahead) {
519 if (sub != player_reserved_dock || [ship isPlayer])
522 if ([docking isEqualToString:
@"DOCK_CLOSED"])
525 jsval rval = JSVAL_VOID;
528 JSBool tempreject = NO;
530 BOOL OK = [[
self script] callMethod:OOJSID("willOpenDockingPortFor") inContext:context withArguments:args count:2 result:&rval];
531 if (OK) OK = JS_ValueToBoolean(context, rval, &tempreject);
532 if (!OK) tempreject = NO;
535 docking =
@"TRY_AGAIN_LATER";
539 docking =
@"TOO_BIG_TO_DOCK";
545 if ([docking isEqualToString:
@"DOCKING_POSSIBLE"] && [sub countOfShipsInDockingQueue] < queue) {
549 alldockstoosmall = NO;
551 else if (![docking isEqualToString:
@"TOO_BIG_TO_DOCK"])
553 alldockstoosmall = NO;
558 alldockstoosmall = NO;
561 if (chosenDock ==
nil)
563 if (player_is_ahead || ([docking isEqualToString:
@"TOO_BIG_TO_DOCK"] && !alldockstoosmall) || docking ==
nil)
568 docking =
@"TRY_AGAIN_LATER";
576 if (fabs(flightRoll) > 0.01 && [chosenDock isOffCentre])
578 return [
self holdPositionInstructionForShip:ship];
582 [_shipsOnHold removeObject:ship];
584 [shipAI reactToMessage:@"DOCKING_REQUESTED" context:@"requestDockingCoordinates"];
585 [
self doScriptEvent:OOJSID("stationAcceptedDockingRequest") withArgument:ship];
591- (NSDictionary *)holdPositionInstructionForShip:(
ShipEntity *)ship
593 if (![_shipsOnHold containsObject:ship])
595 [
self sendExpandedMessage:@"[station-acknowledges-hold-position]" toShip:ship];
596 [_shipsOnHold addObject:ship];
603- (void) abortDockingForShip:(
ShipEntity *) ship
606 [ship
doScriptEvent:OOJSID("stationWithdrewDockingClearance")];
608 [_shipsOnHold removeObject:ship];
610 NSEnumerator *subEnum =
nil;
612 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
619 player_reserved_dock =
nil;
622 [
self sanityCheckShipsOnApproach];
628- (id)initWithKey:(NSString *)key definition:(NSDictionary *)dict
632 self = [
super initWithKey:key definition:dict];
637 hasBreakPattern = YES;
638 localInterfaces = [[NSMutableDictionary alloc] init];
662- (BOOL) setUpShipFromDictionary:(NSDictionary *) dict
670 port_radius = [dict oo_nonNegativeDoubleForKey:@"port_radius" defaultValue:500.0];
673 port_dimensions = make_vector(69, 69, 250);
674 NSString *portDimensionsStr = [dict oo_stringForKey:@"port_dimensions"];
675 if (portDimensionsStr !=
nil)
680 NSArray* tokens = [portDimensionsStr componentsSeparatedByString:@"x"];
681 if ([tokens
count] == 3)
683 port_dimensions = make_vector([[tokens objectAtIndex:0] floatValue],
684 [[tokens objectAtIndex:1] floatValue],
685 [[tokens objectAtIndex:2] floatValue]);
690 if (![super setUpShipFromDictionary:dict])
return NO;
692 equivalentTechLevel = [dict oo_unsignedIntegerForKey:@"equivalent_tech_level" defaultValue:NSNotFound];
693 max_scavengers = [dict oo_unsignedIntForKey:@"max_scavengers" defaultValue:3];
694 max_defense_ships = [dict oo_unsignedIntForKey:@"max_defense_ships" defaultValue:3];
695 max_police = [dict oo_unsignedIntForKey:@"max_police" defaultValue:STATION_MAX_POLICE];
696 equipmentPriceFactor = [dict oo_nonNegativeFloatForKey:@"equipment_price_factor" defaultValue:1.0];
697 equipmentPriceFactor = fmax(equipmentPriceFactor, 0.5f);
698 hasNPCTraffic = [dict oo_fuzzyBooleanForKey:@"has_npc_traffic" defaultValue:(maxFlightSpeed == 0)];
699 hasPatrolShips = [dict oo_fuzzyBooleanForKey:@"has_patrol_ships" defaultValue:NO];
700 suppress_arrival_reports = [dict oo_boolForKey:@"suppress_arrival_reports" defaultValue:NO];
701 [
self setAllegiance:[dict oo_stringForKey:@"allegiance"]];
703 marketCapacity = [dict oo_unsignedIntForKey:@"market_capacity" defaultValue:MAIN_SYSTEM_MARKET_LIMIT];
704 marketDefinition = [[dict oo_arrayForKey:@"market_definition" defaultValue:nil] retain];
705 marketScriptName = [[dict oo_stringForKey:@"market_script" defaultValue:nil] retain];
706 marketMonitored = [dict oo_boolForKey:@"market_monitored" defaultValue:NO];
707 marketBroadcast = [dict oo_boolForKey:@"market_broadcast" defaultValue:YES];
711 requiresDockingClearance = [dict oo_boolForKey:@"requires_docking_clearance" defaultValue:[UNIVERSE dockingClearanceProtocolActive]];
713 allowsFastDocking = [dict oo_boolForKey:@"allows_fast_docking" defaultValue:NO];
715 allowsAutoDocking = [dict oo_boolForKey:@"allows_auto_docking" defaultValue:YES];
717 allowsSaving = [UNIVERSE deterministicPopulation];
719 interstellarUndockingAllowed = [dict oo_boolForKey:@"interstellar_undocking" defaultValue:NO];
721 double unitime = [UNIVERSE getTime];
723 if ([
self hasNPCTraffic])
726 shuttle_launch_interval = 15.0 * 60.0;
727 last_shuttle_launch_time = unitime - (
ranrot_rand() & 63) * shuttle_launch_interval / 60.0;
730 trader_launch_interval = 3600.0 / docked_traders;
731 last_trader_launch_time = unitime + 60.0 - trader_launch_interval;
739 patrol_launch_interval = 300.0;
740 last_patrol_report_time = unitime - patrol_launch_interval;
742 if ([
self crew] ==
nil)
744 [
self setSingleCrewWithRole:@"police"];
747 if ([
self group] ==
nil)
749 [
self setGroup:[
self stationGroup]];
758- (BOOL) setUpSubEntities
760 if (![super setUpSubEntities])
765 NSEnumerator *subEnum =
nil;
769 for (subEnum = [
self shipSubEntityEnumerator]; (subEntity = [subEnum nextObject]); )
771 if ([subEntity isStation])
773 OOLog(
@"setup.ship.badType.subentities",
@"Subentity %@ (%@) of station %@ is itself a StationEntity. This is an internal error - please report it. ",subEntity,[subEntity shipDataKey],[
self displayName]);
780 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
786 OOLog(
@"ship.setup.docks",
@"No docks set up for %@, making virtual dock",
self);
789 NSMutableDictionary *virtualDockDict = [NSMutableDictionary dictionaryWithCapacity:10];
790 [virtualDockDict setObject:@"standard" forKey:@"type"];
791 [virtualDockDict setObject:@"oolite-dock-virtual" forKey:@"subentity_key"];
792 [virtualDockDict oo_setVector:make_vector(0,0,port_radius) forKey:@"position"];
793 [virtualDockDict oo_setQuaternion:kIdentityQuaternion forKey:@"orientation"];
794 [virtualDockDict oo_setBool:YES forKey:@"is_dock"];
795 [virtualDockDict setObject:@"the docking bay" forKey:@"dock_label"];
796 [virtualDockDict oo_setBool:YES forKey:@"allow_docking"];
797 [virtualDockDict oo_setBool:NO forKey:@"disallowed_docking_collides"];
798 [virtualDockDict oo_setBool:YES forKey:@"allow_launching"];
799 [virtualDockDict oo_setBool:YES forKey:@"_is_virtual_dock"];
801 if (![
self setUpOneStandardSubentity:virtualDockDict asTurret:NO])
811- (BOOL) shipIsInDockingCorridor:(
ShipEntity *)ship
813 if (![ship isShip])
return NO;
814 if ([ship isPlayer] && [ship status] == STATUS_DEAD)
return NO;
816 NSEnumerator *subEnum =
nil;
818 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
820 if ([sub shipIsInDockingCorridor:ship])
831- (void) pullInShipIfPermitted:(
ShipEntity *)ship
837- (BOOL) dockingCorridorIsEmpty
842 NSEnumerator *subEnum =
nil;
844 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
846 if ([sub dockingCorridorIsEmpty])
855- (void) clearDockingCorridor
860 NSEnumerator *subEnum =
nil;
862 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
873 BOOL isRockHermit = (scanClass == CLASS_ROCK);
874 BOOL isMainStation = (
self == [UNIVERSE station]);
876 double unitime = [UNIVERSE getTime];
878 if (!isMainStation && localMarket ==
nil)
880 [
self initialiseLocalMarket];
883 [
super update:delta_t];
888 if (isDockingStation && [player status] == STATUS_IN_FLIGHT)
894 [
self sendExpandedMessage:@"[station-docking-clearance-about-to-expire]" toShip:player];
897 else if (last_launch_time < unitime)
899 [
self sendExpandedMessage:@"[station-docking-clearance-expired]" toShip:player];
901 [player
doScriptEvent:OOJSID("playerDockingClearanceExpired")];
902 if ([
self currentlyInDockingQueues] == 0)
904 [[
self getAI] message:@"DOCKING_COMPLETE"];
905 [
self doScriptEvent:OOJSID("stationDockingQueuesAreEmpty")];
907 player_reserved_dock =
nil;
913 if (last_launch_time < unitime)
916 if ([
self currentlyInDockingQueues] == 0)
918 [[
self getAI] message:@"DOCKING_COMPLETE"];
919 [
self doScriptEvent:OOJSID("stationDockingQueuesAreEmpty")];
927 DockEntity *dock = [
self selectDockForDocking];
929 if ([
self hasMultipleDocks])
931 [
self sendExpandedMessage:[NSString stringWithFormat:
932 DESC(@"station-docking-clearance-granted-in-@-until-@"),
934 ClockToString([player
clockTime] + DOCKING_CLEARANCE_WINDOW, NO)]
939 [
self sendExpandedMessage:[NSString stringWithFormat:
940 DESC(@"station-docking-clearance-granted-until-@"),
941 ClockToString([player
clockTime] + DOCKING_CLEARANCE_WINDOW, NO)]
944 player_reserved_dock = dock;
946 [player
doScriptEvent:OOJSID("playerDockingClearanceGranted")];
952 if (approach_spacing > 0.0)
954 approach_spacing -= delta_t * 10.0;
955 if (approach_spacing < 0.0) approach_spacing = 0.0;
960 if (![
self hasNewAI])
963 if ((docked_shuttles > 0)&&(!isRockHermit))
965 if (unitime > last_shuttle_launch_time + shuttle_launch_interval)
967 if (([
self hasNPCTraffic])&&(aegis_status !=
AEGIS_NONE))
969 [
self launchShuttle];
971 last_shuttle_launch_time = unitime;
975 if ((docked_traders > 0)&&(!isRockHermit))
977 if (unitime > last_trader_launch_time + trader_launch_interval)
979 if ([
self hasNPCTraffic])
981 [
self launchIndependentShip:@"trader"];
984 last_trader_launch_time = unitime;
989 if (unitime > (last_patrol_report_time + patrol_launch_interval))
991 if (!((isMainStation && [
self hasNPCTraffic]) || hasPatrolShips) || [
self launchPatrol] !=
nil)
992 last_patrol_report_time = unitime;
1001 NSEnumerator *subEnum =
nil;
1003 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1008 [_shipsOnHold removeAllObjects];
1012- (BOOL) hasMultipleDocks
1014 NSEnumerator *subEnum =
nil;
1017 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1030- (BOOL) hasClearDock
1032 NSEnumerator *subEnum =
nil;
1034 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1036 if ([sub allowsDocking] && [sub countOfShipsInLaunchQueue] == 0 && [sub countOfShipsInDockingQueue] == 0)
1038 if ([[sub canAcceptShipForDocking:
PLAYER] isEqualToString:
@"DOCKING_POSSIBLE"])
1048- (BOOL) hasEligibleDock
1050 NSEnumerator *subEnum =
nil;
1052 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1055 if ([sub allowsDocking] && ([[sub canAcceptShipForDocking:
PLAYER] isEqualToString:
@"DOCKING_POSSIBLE"] || [[sub canAcceptShipForDocking:
PLAYER] isEqualToString:
@"TRY_AGAIN_LATER"]))
1065- (BOOL) hasLaunchDock
1067 NSEnumerator *subEnum =
nil;
1069 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1071 if ([sub allowsLaunching])
1082 NSEnumerator *subEnum =
nil;
1084 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1086 if ([sub allowsDocking] && [sub countOfShipsInLaunchQueue] == 0 && [sub countOfShipsInDockingQueue] == 0)
1095- (void) addShipToLaunchQueue:(
ShipEntity *)ship withPriority:(BOOL)priority
1097 NSEnumerator *subEnum =
nil;
1099 unsigned threshold = 0;
1104 while (threshold < 16)
1106 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1108 if (sub != player_reserved_dock)
1110 if ([sub countOfShipsInDockingQueue] == 0)
1112 if ([sub allowsLaunching] && [sub countOfShipsInLaunchQueue] <= threshold)
1114 if ([sub allowsLaunchingOf:ship])
1131 while (threshold < 16)
1133 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1140 if ([sub allowsLaunching] && [sub countOfShipsInDockingQueue] <= threshold)
1142 if ([sub allowsLaunchingOf:ship])
1153 OOLog(
@"station.launchShip.failed",
@"Cancelled launch for a %@ with role %@, as the %@ has too many ships in its launch queue(s) or no suitable launch docks.",
1154 [ship displayName], [ship primaryRole], [
self displayName]);
1158- (unsigned) countOfShipsInLaunchQueueWithPrimaryRole:(NSString *)role
1160 unsigned result = 0;
1161 NSEnumerator *subEnum =
nil;
1163 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1165 result += [sub countOfShipsInLaunchQueueWithPrimaryRole:role];
1172 return [
self fitsInDock:ship andLogNoFit:YES];
1176- (BOOL) fitsInDock:(
ShipEntity *)ship andLogNoFit:(BOOL)logNoFit
1178 if (![ship isShip])
return NO;
1180 NSEnumerator *subEnum =
nil;
1182 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1184 if ([sub allowsLaunchingOf:ship])
1190 if (logNoFit)
OOLog(
@"station.launchShip.failed",
@"Cancelled launch for a %@ with role %@, as it is too large for the docking port of the %@.",
1191 [ship displayName], [ship primaryRole],
self);
1198 if (ship ==
nil)
return;
1205 last_launch_time = [UNIVERSE getTime];
1207 [
self addShipToStationCount: ship];
1209 NSEnumerator *subEnum =
nil;
1211 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
1215 [
self sanityCheckShipsOnApproach];
1217 [
self doScriptEvent:OOJSID("otherShipDocked") withArgument:ship];
1220 if (isDockingStation && [player status] == STATUS_IN_FLIGHT &&
1223 if (![
self hasClearDock])
1226 if ([
self currentlyInDockingQueues])
1228 [
self sendExpandedMessage:[NSString stringWithFormat:
1229 DESC(@"station-docking-clearance-holding-d-ships-approaching"),
1230 [
self currentlyInDockingQueues]+1] toShip:player];
1232 else if([
self currentlyInLaunchingQueues])
1234 [
self sendExpandedMessage:[NSString stringWithFormat:
1235 DESC(@"station-docking-clearance-holding-d-ships-departing"),
1236 [
self currentlyInLaunchingQueues]+1] toShip:player];
1242 if ([ship isPlayer])
1244 player_reserved_dock =
nil;
1248- (void) addShipToStationCount:(
ShipEntity *) ship
1250 if ([ship isShuttle]) docked_shuttles++;
1251 else if ([ship isTrader] && ![ship isPlayer]) docked_traders++;
1252 else if (([ship isPolice] && ![ship isEscort]) || [ship hasPrimaryRole:
@"defense_ship"])
1254 if (0 < defenders_launched) defenders_launched--;
1256 else if ([ship hasPrimaryRole:
@"scavenger"] || [ship hasPrimaryRole:
@"miner"])
1258 if (0 < scavengers_launched) scavengers_launched--;
1263- (BOOL) interstellarUndockingAllowed
1265 return interstellarUndockingAllowed;
1269- (BOOL)hasNPCTraffic
1271 return hasNPCTraffic;
1275- (void)setHasNPCTraffic:(BOOL)flag
1277 hasNPCTraffic = flag != NO;
1290 return [
super collideWithShip:other];
1294- (BOOL) hasHostileTarget
1299- (void) takeEnergyDamage:(
double)amount from:(
Entity *)ent becauseOf:(
Entity *)other weaponIdentifier:(NSString *)weaponIdentifier
1305 if ([other isShip] && group !=
nil)
1308 isFriend = otherGroup == group || [otherGroup
leader] ==
self;
1312 if (
self == [
UNIVERSE station] && !isFriend)
1318 if ([
self hasNewAI] || isEnergyMine)
1320 unsigned b=isEnergyMine ? 96 : 64;
1325 [(
ShipEntity*)
other markAsOffender:b withReason:kOOLegalStatusReasonAttackedMainStation];
1326 [
self setPrimaryAggressor:other];
1327 [
self setFoundTarget:other];
1328 [
self launchPolice];
1333 [
self increaseAlertLevel];
1334 [
self respondToAttackFrom:ent becauseOf:other];
1339 if (!isFriend && (
self != [
UNIVERSE station] || amount < energy) )
1342 [
super takeEnergyDamage:amount from:ent becauseOf:other weaponIdentifier:weaponIdentifier];
1346- (void) adjustVelocity:(Vector) xVel
1348 if (
self != [
UNIVERSE station]) [
super adjustVelocity:xVel];
1351- (void)takeScrapeDamage:(
double)amount from:(
Entity *)ent
1354 if (
self != [
UNIVERSE station]) [
super takeScrapeDamage:amount from:ent];
1358- (void) takeHeatDamage:(
double)amount
1361 if (
self != [
UNIVERSE station]) [
super takeHeatDamage:amount];
1365- (NSString *) allegiance
1371- (void) setAllegiance:(NSString *)newAllegiance
1373 [allegiance release];
1374 allegiance = [newAllegiance copy];
1389 if (alertLevel != level)
1393 if (signallingScript)
1395 ShipScriptEventNoCx(
self,
"alertConditionChanged", INT_TO_JSVAL(level), INT_TO_JSVAL(oldLevel));
1400 [shipAI reactToMessage:@"GREEN_ALERT" context:nil];
1404 [shipAI reactToMessage:@"YELLOW_ALERT" context:nil];
1408 [shipAI reactToMessage:@"RED_ALERT" context:nil];
1416- (
ShipEntity *) launchIndependentShip:(NSString*) role
1418 if (![
self hasLaunchDock])
1420 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a ship with role %@, as the %@ has no launch docks.",
1421 role, [
self displayName]);
1425 BOOL trader = [role isEqualToString:@"trader"];
1426 BOOL sunskimmer = ([role isEqualToString:@"sunskim-trader"]);
1429 if((trader && (
randf() < 0.1)) || sunskimmer)
1431 ship = [UNIVERSE newShipWithRole:@"sunskim-trader"];
1438 ship = [UNIVERSE newShipWithRole:role];
1441 if (![
self fitsInDock:ship])
1451 [ship setSingleCrewWithRole:role];
1453 [ship setPrimaryRole:role];
1455 if(trader || ship->scanClass == CLASS_NOT_SET) [ship setScanClass: CLASS_NEUTRAL];
1459 [ship setBounty:0 withReason:kOOLegalStatusReasonSetup];
1460 [ship setCargoFlag:CARGO_FLAG_FULL_PLENTIFUL];
1463 [ship setFuel:(Ranrot()&31)];
1464 [UNIVERSE makeSunSkimmer:ship andSetAI:YES];
1470 if([ship fuel] == 0) [ship setFuel:70];
1475 [
self addShipToLaunchQueue:ship withPriority:NO];
1478 if ([ship group] ==
nil) [ship setGroup:escortGroup];
1483 unsigned escorts = [ship pendingEscortCount];
1486 [ship setOwner:self];
1487 [ship setUpEscorts];
1488 [ship setOwner:ship];
1491 [ship setPendingEscortCount:0];
1502- (void) increaseAlertLevel
1504 [
self setAlertLevel:[
self alertLevel] + 1 signallingScript:YES];
1509- (void) decreaseAlertLevel
1511 [
self setAlertLevel:[
self alertLevel] - 1 signallingScript:YES];
1516- (NSArray *) launchPolice
1518 if (![
self hasLaunchDock])
1520 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a police ship, as the %@ has no launch docks.",
1521 [
self displayName]);
1522 return [NSArray array];
1525 OOUniversalID police_target = [[
self primaryTarget] universalID];
1527 NSMutableArray *result =
nil;
1529 if (techlevel == NSNotFound) techlevel = 6;
1531 result = [NSMutableArray arrayWithCapacity:4];
1533 for (i = 0; (i < 4)&&(defenders_launched < max_police) ; i++)
1536 if (![
UNIVERSE entityForUniversalID:police_target])
1538 [
self noteLostTarget];
1539 return [NSArray array];
1544 if ((
Ranrot() & 3) + 9 < techlevel)
1546 police_ship = [UNIVERSE newShipWithRole:@"interceptor"];
1550 police_ship = [UNIVERSE newShipWithRole:@"police"];
1553 if (police_ship && [
self fitsInDock:police_ship])
1555 if (![police_ship crew])
1557 [police_ship setSingleCrewWithRole:@"police"];
1560 [police_ship setGroup:[
self stationGroup]];
1561 [police_ship setPrimaryRole:@"police"];
1562 [police_ship addTarget:[UNIVERSE entityForUniversalID:police_target]];
1563 if ([police_ship scanClass] == CLASS_NOT_SET)
1564 [police_ship setScanClass: CLASS_POLICE];
1565 [police_ship setBounty:0 withReason:kOOLegalStatusReasonSetup];
1566 if ([police_ship heatInsulation] < [
self heatInsulation])
1567 [police_ship setHeatInsulation:[
self heatInsulation]];
1568 [police_ship switchAITo:@"oolite-defenseShipAI.js"];
1569 [
self addShipToLaunchQueue:police_ship withPriority:YES];
1570 defenders_launched++;
1571 [result addObject:police_ship];
1573 [police_ship autorelease];
1575 [
self abortAllDockings];
1583 if (![
self hasLaunchDock])
1585 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a defense ship, as the %@ has no launch docks.",
1586 [
self displayName]);
1590 OOUniversalID defense_target = [[
self primaryTarget] universalID];
1592 NSString *defense_ship_key =
nil,
1593 *defense_ship_role =
nil,
1594 *default_defense_ship_role =
nil;
1595 NSString *defense_ship_ai =
@"oolite-defenseShipAI.js";
1599 techlevel = [
self equivalentTechLevel];
1600 if (techlevel == NSNotFound) techlevel = 6;
1601 if ((
Ranrot() & 7) + 6 <= techlevel)
1602 default_defense_ship_role =
@"interceptor";
1604 default_defense_ship_role =
@"police";
1606 if (scanClass == CLASS_ROCK)
1607 default_defense_ship_role =
@"hermit-ship";
1609 if (defenders_launched >= max_defense_ships)
1612 if (![
UNIVERSE entityForUniversalID:defense_target])
1614 [
self noteLostTarget];
1618 defense_ship_key = [shipinfoDictionary oo_stringForKey:@"defense_ship"];
1619 if (defense_ship_key !=
nil)
1621 defense_ship = [UNIVERSE newShipWithName:defense_ship_key];
1625 defense_ship_role = [shipinfoDictionary oo_stringForKey:@"defense_ship_role" defaultValue:default_defense_ship_role];
1626 defense_ship = [UNIVERSE newShipWithRole:defense_ship_role];
1629 if (!defense_ship && default_defense_ship_role != defense_ship_role)
1630 defense_ship = [
UNIVERSE newShipWithRole:default_defense_ship_role];
1632 if (!defense_ship || ![
self fitsInDock:defense_ship])
1634 [defense_ship release];
1638 if ([defense_ship isPolice] || [defense_ship hasPrimaryRole:
@"hermit-ship"])
1640 [defense_ship switchAITo:defense_ship_ai];
1643 [defense_ship setPrimaryRole:@"defense_ship"];
1645 defenders_launched++;
1647 if (![defense_ship crew])
1649 if ([defense_ship isPolice])
1651 [defense_ship setSingleCrewWithRole:@"police"];
1655 [defense_ship setSingleCrewWithRole:@"hunter"];
1659 [defense_ship setOwner: self];
1660 if ([
self group] ==
nil)
1662 [
self setGroup:[
self stationGroup]];
1664 [defense_ship setGroup:[
self stationGroup]];
1666 [defense_ship addTarget:[UNIVERSE entityForUniversalID:defense_target]];
1668 if ((scanClass != CLASS_ROCK)&&(scanClass != CLASS_STATION))
1670 [defense_ship setScanClass: scanClass];
1672 else if ([defense_ship scanClass] == CLASS_NOT_SET)
1674 [defense_ship setScanClass: CLASS_NEUTRAL];
1677 if ([defense_ship heatInsulation] < [
self heatInsulation])
1679 [defense_ship setHeatInsulation:[
self heatInsulation]];
1682 [
self addShipToLaunchQueue:defense_ship withPriority:YES];
1683 [defense_ship autorelease];
1684 [
self abortAllDockings];
1686 return defense_ship;
1693 if (![
self hasLaunchDock])
1695 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a scavenger ship, as the %@ has no launch docks.",
1696 [
self displayName]);
1702 unsigned scavs = [UNIVERSE countShipsWithPrimaryRole:@"scavenger" inRange:SCANNER_MAX_RANGE ofEntity:self] + [
self countOfShipsInLaunchQueueWithPrimaryRole:
@"scavenger"];
1704 if (scavs >= max_scavengers)
return nil;
1705 if (scavengers_launched >= max_scavengers)
return nil;
1707 scavenger_ship = [UNIVERSE newShipWithRole:@"scavenger"];
1709 if (![
self fitsInDock:scavenger_ship])
1711 [scavenger_ship release];
1717 if (![scavenger_ship crew])
1719 [scavenger_ship setSingleCrewWithRole:@"miner"];
1722 scavengers_launched++;
1723 [scavenger_ship setScanClass: CLASS_NEUTRAL];
1724 if ([scavenger_ship heatInsulation] < [
self heatInsulation])
1725 [scavenger_ship setHeatInsulation:[
self heatInsulation]];
1726 [scavenger_ship setGroup:[
self stationGroup]];
1727 [scavenger_ship switchAITo:@"oolite-scavengerAI.js"];
1728 [
self addShipToLaunchQueue:scavenger_ship withPriority:NO];
1729 [scavenger_ship autorelease];
1731 return scavenger_ship;
1738 if (![
self hasLaunchDock])
1740 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a miner ship, as the %@ has no launch docks.",
1741 [
self displayName]);
1747 int n_miners = [UNIVERSE countShipsWithPrimaryRole:@"miner" inRange:SCANNER_MAX_RANGE ofEntity:self] + [
self countOfShipsInLaunchQueueWithPrimaryRole:
@"miner"];
1753 if (scavengers_launched >= max_scavengers)
return nil;
1755 miner_ship = [UNIVERSE newShipWithRole:@"miner"];
1757 if (![
self fitsInDock:miner_ship])
1759 [miner_ship release];
1765 if (![miner_ship crew])
1767 [miner_ship setSingleCrewWithRole:@"miner"];
1770 scavengers_launched++;
1771 [miner_ship setScanClass:CLASS_NEUTRAL];
1772 if ([miner_ship heatInsulation] < [
self heatInsulation])
1773 [miner_ship setHeatInsulation:[
self heatInsulation]];
1774 [miner_ship setGroup:[
self stationGroup]];
1775 [miner_ship switchAITo:@"oolite-scavengerAI.js"];
1776 [
self addShipToLaunchQueue:miner_ship withPriority:NO];
1777 [miner_ship autorelease];
1787 if ([
self hasLaunchDock])
1789 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a pirate ship, as the %@ has no launch docks.",
1790 [
self displayName]);
1794 OOUniversalID defense_target = [[
self primaryTarget] universalID];
1797 if (defenders_launched >= max_defense_ships)
return nil;
1799 if (![
UNIVERSE entityForUniversalID:defense_target])
1801 [
self noteLostTarget];
1806 pirate_ship = [UNIVERSE newShipWithRole:@"pirate"];
1809 if (![
self fitsInDock:pirate_ship])
1811 [pirate_ship release];
1817 if (![pirate_ship crew])
1819 [pirate_ship setSingleCrewWithRole:@"pirate"];
1822 defenders_launched++;
1825 [pirate_ship setOwner:self];
1826 [pirate_ship setGroup:[
self stationGroup]];
1827 [pirate_ship setPrimaryRole:@"defense_ship"];
1828 [pirate_ship addTarget:[UNIVERSE entityForUniversalID:defense_target]];
1829 [pirate_ship setScanClass: CLASS_NEUTRAL];
1830 if ([pirate_ship heatInsulation] < [
self heatInsulation])
1831 [pirate_ship setHeatInsulation:[
self heatInsulation]];
1833 [pirate_ship setBounty: 10 + floor(randf() * 20) withReason:kOOLegalStatusReasonSetup];
1835 [
self addShipToLaunchQueue:pirate_ship withPriority:NO];
1836 [pirate_ship autorelease];
1837 [
self abortAllDockings];
1846 if (![
self hasLaunchDock])
1848 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a shuttle ship, as the %@ has no launch docks.",
1849 [
self displayName]);
1854 shuttle_ship = [UNIVERSE newShipWithRole:@"shuttle"];
1856 if (![
self fitsInDock:shuttle_ship])
1858 [shuttle_ship release];
1864 if (![shuttle_ship crew])
1866 [shuttle_ship setSingleCrewWithRole:@"trader"];
1870 [shuttle_ship setScanClass: CLASS_NEUTRAL];
1871 [shuttle_ship setCargoFlag:CARGO_FLAG_FULL_SCARCE];
1872 [shuttle_ship switchAITo:@"oolite-shuttleAI.js"];
1873 [
self addShipToLaunchQueue:shuttle_ship withPriority:NO];
1875 [shuttle_ship autorelease];
1877 return shuttle_ship;
1884 if (![
self hasLaunchDock])
1886 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for an escort ship, as the %@ has no launch docks.",
1887 [
self displayName]);
1892 escort_ship = [UNIVERSE newShipWithRole:@"escort"];
1894 if (escort_ship && [
self fitsInDock:escort_ship])
1896 if (![escort_ship crew])
1898 [escort_ship setSingleCrewWithRole:@"hunter"];
1901 [escort_ship setScanClass: CLASS_NEUTRAL];
1902 [escort_ship setCargoFlag: CARGO_FLAG_FULL_PLENTIFUL];
1903 [escort_ship switchAITo:@"oolite-escortAI.js"];
1904 [
self addShipToLaunchQueue:escort_ship withPriority:NO];
1907 [escort_ship release];
1915 if (![
self hasLaunchDock])
1917 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a patrol ship, as the %@ has no launch docks.",
1918 [
self displayName]);
1921 if (defenders_launched < max_police)
1926 techlevel = [
self equivalentTechLevel];
1927 if (techlevel == NSNotFound)
1930 if ((
Ranrot() & 7) + 6 <= techlevel)
1931 patrol_ship = [UNIVERSE newShipWithRole:@"interceptor"];
1933 patrol_ship = [UNIVERSE newShipWithRole:@"police"];
1935 if (![
self fitsInDock:patrol_ship])
1937 [patrol_ship release];
1943 if (![patrol_ship crew])
1945 [patrol_ship setSingleCrewWithRole:@"police"];
1948 defenders_launched++;
1949 [patrol_ship switchLightsOff];
1950 if ([patrol_ship scanClass] == CLASS_NOT_SET)
1951 [patrol_ship setScanClass: CLASS_POLICE];
1952 if ([patrol_ship heatInsulation] < [
self heatInsulation])
1953 [patrol_ship setHeatInsulation:[
self heatInsulation]];
1954 [patrol_ship setPrimaryRole:@"police-station-patrol"];
1955 [patrol_ship setBounty:0 withReason:kOOLegalStatusReasonSetup];
1956 [patrol_ship setGroup:[
self stationGroup]];
1957 [patrol_ship switchAITo:@"oolite-policeAI.js"];
1958 [
self addShipToLaunchQueue:patrol_ship withPriority:NO];
1959 [
self acceptPatrolReportFrom:patrol_ship];
1960 [patrol_ship autorelease];
1969- (void) launchShipWithRole:(NSString*) role
1971 if (![
self hasLaunchDock])
1973 OOLog(
@"station.launchShip.impossible",
@"Cancelled launch for a ship with role %@, as the %@ has no launch docks.",
1974 role, [
self displayName]);
1977 ShipEntity *ship = [UNIVERSE newShipWithRole: role];
1978 if (ship && [
self fitsInDock:ship])
1982 [ship setSingleCrewWithRole:role];
1984 if (ship->scanClass == CLASS_NOT_SET) [ship setScanClass: CLASS_NEUTRAL];
1985 [ship setPrimaryRole:role];
1986 [ship setGroup:[
self stationGroup]];
1987 [
self addShipToLaunchQueue:ship withPriority:NO];
1994- (void) becomeExplosion
1996 if (
self == [
UNIVERSE station])
return;
2000 if ((player)&&([player status] == STATUS_DOCKED || [player status] == STATUS_DOCKING)&&([player dockedStation] ==
self))
2004 [UNIVERSE setViewDirection:VIEW_FORWARD];
2005 [[UNIVERSE gameController] setMouseInteractionModeForFlight];
2009 if (scanClass == CLASS_ROCK)
2012 [
self setPrimaryRole:@"asteroid"];
2017 [
super becomeExplosion];
2022- (void) becomeEnergyBlast
2024 if (
self == [
UNIVERSE station])
return;
2025 [
super becomeEnergyBlast];
2029- (void) becomeLargeExplosion:(
double) factor
2031 if (
self == [
UNIVERSE station])
return;
2032 [
super becomeLargeExplosion:factor];
2036- (void) acceptPatrolReportFrom:(
ShipEntity*) patrol_ship
2038 last_patrol_report_time = [UNIVERSE getTime];
2044- (NSString *) acceptDockingClearanceRequestFrom:(
ShipEntity *)other
2046 NSString *result =
nil;
2047 double timeNow = [UNIVERSE getTime];
2050 [
self doScriptEvent:OOJSID("stationReceivedDockingRequest") withArgument:other];
2053 [UNIVERSE clearPreviousMessage];
2055 [
self sanityCheckShipsOnApproach];
2059 if (![
self requiresDockingClearance])
2065 if (!(([other isPlayer] && [other hasHostileTarget]) || (
self == [
UNIVERSE station] && [other bounty] > 50)))
2067 [
self sendExpandedMessage:@"[station-docking-clearance-not-required]" toShip:other];
2069 if ([other isPlayer])
2073 [shipAI reactToMessage:@"DOCKING_REQUESTED" context:nil];
2074 [
self doScriptEvent:OOJSID("stationAcceptedDockingRequest") withArgument:other];
2077 result =
@"DOCKING_CLEARANCE_NOT_REQUIRED";
2082 if( result ==
nil && [other isPlayer] &&
self == [player getTargetDockStation])
2084 switch( [player getDockingClearanceStatus] )
2087 if (!no_docking_while_launching)
2090 [
self sendExpandedMessage:[NSString stringWithFormat:
2091 DESC(@"station-docking-clearance-extended-until-@"),
2092 ClockToString([player
clockTime] + DOCKING_CLEARANCE_WINDOW, NO)]
2095 result =
@"DOCKING_CLEARANCE_EXTENDED";
2101 last_launch_time = timeNow;
2102 [
self sendExpandedMessage:@"[station-docking-clearance-cancelled]" toShip:other];
2104 result =
@"DOCKING_CLEARANCE_CANCELLED";
2105 player_reserved_dock =
nil;
2106 if ([
self currentlyInDockingQueues] == 0)
2108 [shipAI message:@"DOCKING_COMPLETE"];
2109 [
self doScriptEvent:OOJSID("stationDockingQueuesAreEmpty")];
2120 if (result ==
nil && [other isPlayer] &&
self != [player getTargetDockStation])
2122 player_reserved_dock =
nil;
2129 if (result ==
nil &&
self == [
UNIVERSE station] && [other bounty] > 50)
2131 [
self sendExpandedMessage:@"[station-docking-clearance-H-clearance-refused]" toShip:other];
2132 if ([other isPlayer])
2134 result =
@"DOCKING_CLEARANCE_DENIED_SHIP_FUGITIVE";
2137 if (result ==
nil && [other hasHostileTarget])
2139 [
self sendExpandedMessage:@"[station-docking-clearance-denied]" toShip:other];
2140 if ([other isPlayer])
2142 result =
@"DOCKING_CLEARANCE_DENIED_SHIP_HOSTILE";
2145 if (![
self hasEligibleDock])
2147 if ([other isPlayer])
2151 [
self sendExpandedMessage:@"[station-docking-clearance-denied-no-docks]" toShip:other];
2153 result =
@"DOCKING_CLEARANCE_DENIED_NO_DOCKS";
2155 else if (![
self hasClearDock])
2160 if (result ==
nil && (([
self currentlyInDockingQueues] && last_launch_time < timeNow) || (![other isPlayer] && [player getDockingClearanceStatus] ==
DOCKING_CLEARANCE_STATUS_REQUESTED)))
2162 [
self sendExpandedMessage:[NSString stringWithFormat:
2163 DESC(@"station-docking-clearance-acknowledged-d-ships-approaching"),
2164 [
self currentlyInDockingQueues]+1] toShip:other];
2166 result =
@"DOCKING_CLEARANCE_DENIED_TRAFFIC_INBOUND";
2169 if (result ==
nil && [
self currentlyInLaunchingQueues])
2171 [
self sendExpandedMessage:[NSString stringWithFormat:
2172 DESC(@"station-docking-clearance-acknowledged-d-ships-departing"),
2173 [
self currentlyInLaunchingQueues]+1] toShip:other];
2175 result =
@"DOCKING_CLEARANCE_DENIED_TRAFFIC_OUTBOUND";
2181 if ([other isPlayer])
2185 result =
@"DOCKING_CLEARANCE_DENIED_NO_DOCKS";
2187 NSEnumerator *subEnum =
nil;
2189 BOOL openLater = NO;
2190 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
2193 if ([docking isEqualToString:
@"DOCK_CLOSED"])
2196 jsval rval = JSVAL_VOID;
2199 JSBool tempreject = NO;
2201 BOOL OK = [[
self script] callMethod:OOJSID("willOpenDockingPortFor") inContext:context withArguments:args count:2 result:&rval];
2202 if (OK) OK = JS_ValueToBoolean(context, rval, &tempreject);
2203 if (!OK) tempreject = NO;
2210 if (openLater)
break;
2215 [
self sendExpandedMessage:@"[station-docking-clearance-denied-no-docks-yet]" toShip:other];
2219 [
self sendExpandedMessage:@"[station-docking-clearance-denied-no-docks]" toShip:other];
2229 if ([other isPlayer])
2232 player_reserved_dock = [
self selectDockForDocking];
2235 if ([
self hasMultipleDocks] && [other isPlayer])
2237 [
self sendExpandedMessage:[NSString stringWithFormat:
2238 DESC(@"station-docking-clearance-granted-in-@-until-@"),
2239 [player_reserved_dock displayName],
2240 ClockToString([player
clockTime] + DOCKING_CLEARANCE_WINDOW, NO)]
2245 [
self sendExpandedMessage:[NSString stringWithFormat:
2246 DESC(@"station-docking-clearance-granted-until-@"),
2247 ClockToString([player
clockTime] + DOCKING_CLEARANCE_WINDOW, NO)]
2251 result =
@"DOCKING_CLEARANCE_GRANTED";
2252 [shipAI reactToMessage:@"DOCKING_REQUESTED" context:nil];
2253 [
self doScriptEvent:OOJSID("stationAcceptedDockingRequest") withArgument:other];
2259- (unsigned) currentlyInDockingQueues
2261 NSEnumerator *subEnum =
nil;
2264 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
2266 soa += [sub countOfShipsInDockingQueue];
2268 soa += [_shipsOnHold
count];
2273- (unsigned) currentlyInLaunchingQueues
2275 NSEnumerator *subEnum =
nil;
2278 for (subEnum = [
self dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
2280 soa += [sub countOfShipsInLaunchQueue];
2286- (BOOL) requiresDockingClearance
2288 return requiresDockingClearance;
2292- (void) setRequiresDockingClearance:(BOOL)newValue
2294 requiresDockingClearance = !!newValue;
2298- (BOOL) allowsFastDocking
2300 return allowsFastDocking;
2304- (void) setAllowsFastDocking:(BOOL)newValue
2306 allowsFastDocking = !!newValue;
2310- (BOOL) allowsAutoDocking
2312 return allowsAutoDocking;
2316- (void) setAllowsAutoDocking:(BOOL)newValue
2318 allowsAutoDocking = !!newValue;
2322- (BOOL) allowsSaving
2325 return allowsSaving && ([
self maxFlightSpeed] == 0);
2329- (BOOL) isRotatingStation
2331 if ([shipinfoDictionary oo_boolForKey:
@"rotating" defaultValue:NO])
return YES;
2332 return [[shipinfoDictionary objectForKey:@"roles"] rangeOfString:@"rotating-station"].location != NSNotFound;
2336- (NSString *) marketOverrideName
2343 return [shipinfoDictionary oo_stringForKey:@"market"];
2351 id determinant = [shipinfoDictionary objectForKey:@"has_shipyard"];
2354 determinant = [shipinfoDictionary objectForKey:
@"hasShipyard"];
2359 if ([determinant isKindOfClass:[NSArray
class]])
2361 return [PLAYER scriptTestConditions:OOSanitizeLegacyScriptConditions(determinant, nil)];
2375- (void) generateShipyard
2377 [
self generateShipyard:[
self equivalentTechLevel]];
2385 if ([
self localShipyard] ==
nil)
2387 [
self setLocalShipyard:[UNIVERSE shipsForSaleForSystem:[UNIVERSE currentSystemID] withTL:stationTechLevel atTime:[PLAYER clockTime]]];
2390 NSMutableArray *shipyard = [
self localShipyard];
2393 for (i = 0; i < [shipyard count]; i++)
2395 NSString *shipID = [[shipyard oo_dictionaryAtIndex:i] oo_stringForKey:SHIPYARD_KEY_ID];
2396 if ([[
PLAYER shipyardRecord] objectForKey:shipID])
2398 [shipyard removeObjectAtIndex:i--];
2404- (BOOL) suppressArrivalReports
2406 return suppress_arrival_reports;
2410- (void) setSuppressArrivalReports:(BOOL)newValue
2412 suppress_arrival_reports = !!newValue;
2416- (BOOL) hasBreakPattern
2418 return hasBreakPattern;
2422- (void) setHasBreakPattern:(BOOL)newValue
2424 hasBreakPattern = !!newValue;
2428- (NSString *) descriptionComponents
2430 return [NSString stringWithFormat:@"\"%@\" %@", name, [
super descriptionComponents]];
2434- (void)dumpSelfState
2436 NSMutableArray *flags =
nil;
2437 NSString *flagsString =
nil;
2438 NSString *alertString =
@"*** ERROR: UNKNOWN ALERT LEVEL ***";
2440 [
super dumpSelfState];
2445 alertString =
@"green";
2449 alertString =
@"yellow";
2453 alertString =
@"red";
2457 OOLog(
@"dumpState.stationEntity",
@"Alert level: %@", alertString);
2458 OOLog(
@"dumpState.stationEntity",
@"Max police: %u", max_police);
2459 OOLog(
@"dumpState.stationEntity",
@"Max defense ships: %u", max_defense_ships);
2460 OOLog(
@"dumpState.stationEntity",
@"Defenders launched: %u", defenders_launched);
2461 OOLog(
@"dumpState.stationEntity",
@"Max scavengers: %u", max_scavengers);
2462 OOLog(
@"dumpState.stationEntity",
@"Scavengers launched: %u", scavengers_launched);
2463 OOLog(
@"dumpState.stationEntity",
@"Docked shuttles: %u", docked_shuttles);
2464 OOLog(
@"dumpState.stationEntity",
@"Docked traders: %u", docked_traders);
2465 OOLog(
@"dumpState.stationEntity",
@"Equivalent tech level: %li", equivalentTechLevel);
2466 OOLog(
@"dumpState.stationEntity",
@"Equipment price factor: %g", equipmentPriceFactor);
2468 flags = [NSMutableArray array];
2469 #define ADD_FLAG_IF_SET(x) if (x) { [flags addObject:@#x]; }
2471 if ([
self isRotatingStation]) { [flags addObject:@"rotatingStation"]; }
2472 if (![
self dockingCorridorIsEmpty]) { [flags addObject:@"dockingCorridorIsBusy"]; }
2473 flagsString = [flags count] ? [flags componentsJoinedByString:@", "] : (NSString *)
@"none";
2474 OOLog(
@"dumpState.stationEntity",
@"Flags: %@", flagsString);
2479 if([_shipsOnHold
count] > 0)
2481 OOLog(
@"dumpState.stationEntity",
@"%li Ships on hold (unsorted):", [_shipsOnHold
count]);
2484 NSEnumerator *onHoldEnum = [_shipsOnHold objectEnumerator];
2487 while ((ship = [onHoldEnum nextObject]))
2489 OOLog(
@"dumpState.stationEntity",
@"Nr %i: %@ at distance %g with role: %@", i++, [ship displayName], HPdistance([
self position], [ship position]), [ship primaryRole]);
#define ADD_FLAG_IF_SET(x)
void OOStandardsDeprecated(NSString *message)
BOOL OOEnforceStandards(void)
#define OOJS_PROFILE_EXIT
#define OOJS_PROFILE_ENTER
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
OOINLINE JSContext * OOJSAcquireContext(void)
OOINLINE void OOJSRelinquishContext(JSContext *context)
#define OOLog(class, format,...)
Vector vector_forward_from_quaternion(Quaternion quat)
NSString * OOCommodityType
uint64_t OOCreditsQuantity
@ DOCKING_CLEARANCE_STATUS_TIMING_OUT
@ DOCKING_CLEARANCE_STATUS_NOT_REQUIRED
@ DOCKING_CLEARANCE_STATUS_GRANTED
@ DOCKING_CLEARANCE_STATUS_NONE
@ DOCKING_CLEARANCE_STATUS_REQUESTED
#define ShipScriptEventNoCx(ship, event,...)
NSDictionary * OOMakeDockingInstructions(StationEntity *station, HPVector coords, float speed, float range, NSString *ai_message, NSString *comms_message, BOOL match_rotation, int docking_stage)
@ STATION_ALERT_LEVEL_RED
@ STATION_ALERT_LEVEL_YELLOW
@ STATION_ALERT_LEVEL_GREEN
#define DOCKING_CLEARANCE_WINDOW
void launchShip:(ShipEntity *ship)
Vector portUpVectorForShipsBoundingBox:(BoundingBox bb)
NSDictionary * dockingInstructionsForShip:(ShipEntity *ship)
NSUInteger countOfShipsInDockingQueue()
NSString * canAcceptShipForDocking:(ShipEntity *ship)
void autoDockShipsOnApproach()
void abortDockingForShip:(ShipEntity *ship)
void noteDockingForShip:(ShipEntity *ship)
void clearDockingCorridor()
void addShipToLaunchQueue:withPriority:(ShipEntity *ship,[withPriority] BOOL priority)
NSUInteger exportLegalityForGood:(OOCommodityType good)
NSUInteger importLegalityForGood:(OOCommodityType good)
void setLeader:(ShipEntity *leader)
OODockingClearanceStatus getDockingClearanceStatus()
StationEntity * getTargetDockStation()
void setDockingClearanceStatus:(OODockingClearanceStatus newValue)
void leaveDock:(StationEntity *station)
BOOL isExplicitlyUnpiloted()
void doScriptEvent:(jsid message)
void sendAIMessage:(NSString *message)
void enterDock:(StationEntity *station)