Oolite
Loading...
Searching...
No Matches
ShipEntity(PureAI) Category Reference

Instance Methods

(void) - setStateTo:
 
(void) - pauseAI:
 
(void) - randomPauseAI:
 
(void) - dropMessages:
 
(void) - debugDumpPendingMessages
 
(void) - setDestinationToCurrentLocation
 
(void) - setDesiredRangeTo:
 
(void) - setDesiredRangeForWaypoint
 
(void) - setSpeedTo:
 
(void) - setSpeedFactorTo:
 
(void) - setSpeedToCruiseSpeed
 
(void) - setThrustFactorTo:
 
(void) - setTargetToPrimaryAggressor
 
(void) - scanForNearestMerchantman
 
(void) - scanForRandomMerchantman
 
(void) - scanForLoot
 
(void) - scanForRandomLoot
 
(void) - setTargetToFoundTarget
 
(void) - checkForFullHold
 
(void) - getWitchspaceEntryCoordinates
 
(void) - setDestinationFromCoordinates
 
(void) - setCoordinatesFromPosition
 
(void) - fightOrFleeMissile
 
(void) - setCourseToPlanet
 
(void) - setTakeOffFromPlanet
 
(void) - landOnPlanet
 
(void) - checkTargetLegalStatus
 
(void) - checkOwnLegalStatus
 
(void) - exitAIWithMessage:
 
(void) - setDestinationToTarget
 
(void) - setDestinationWithinTarget
 
(void) - checkCourseToDestination
 
(void) - checkAegis
 
(void) - checkEnergy
 
(void) - checkHeatInsulation
 
(void) - scanForOffenders
 
(void) - setCourseToWitchpoint
 
(void) - setDestinationToWitchpoint
 
(void) - setDestinationToStationBeacon
 
(void) - performHyperSpaceExit
 
(void) - performHyperSpaceExitWithoutReplacing
 
(void) - wormholeGroup
 
(void) - commsMessage:
 
(void) - commsMessageByUnpiloted:
 
(void) - ejectCargo
 
(void) - scanForThargoid
 
(void) - scanForNonThargoid
 
(void) - thargonCheckMother
 
(void) - becomeUncontrolledThargon
 
(void) - checkDistanceTravelled
 
(void) - fightOrFleeHostiles
 
(void) - suggestEscort
 
(void) - escortCheckMother
 
(void) - checkGroupOddsVersusTarget
 
(void) - scanForFormationLeader
 
(void) - messageMother:
 
(void) - setPlanetPatrolCoordinates
 
(void) - setSunSkimStartCoordinates
 
(void) - setSunSkimEndCoordinates
 
(void) - setSunSkimExitCoordinates
 
(void) - patrolReportIn
 
(void) - checkForMotherStation
 
(void) - sendTargetCommsMessage:
 
(void) - markTargetForFines
 
(void) - markTargetForOffence:
 
(void) - storeTarget
 
(void) - recallStoredTarget
 
(void) - scanForRocks
 
(void) - setDestinationToDockingAbort
 
(void) - requestNewTarget
 
(void) - rollD:
 
(void) - scanForNearestShipWithPrimaryRole:
 
(void) - scanForNearestShipHavingRole:
 
(void) - scanForNearestShipWithAnyPrimaryRole:
 
(void) - scanForNearestShipHavingAnyRole:
 
(void) - scanForNearestShipWithScanClass:
 
(void) - scanForNearestShipWithoutPrimaryRole:
 
(void) - scanForNearestShipNotHavingRole:
 
(void) - scanForNearestShipWithoutAnyPrimaryRole:
 
(void) - scanForNearestShipNotHavingAnyRole:
 
(void) - scanForNearestShipWithoutScanClass:
 
(void) - setCoordinates:
 
(void) - checkForNormalSpace
 
(void) - setTargetToRandomStation
 
(void) - setTargetToLastStation
 
(void) - addFuel:
 
(void) - scriptActionOnTarget:
 
(void) - sendScriptMessage:
 
(void) - ai_throwSparks
 
(void) - explodeSelf
 
(void) - ai_debugMessage:
 
(void) - targetFirstBeaconWithCode:
 
(void) - targetNextBeaconWithCode:
 
(void) - setRacepointsFromTarget
 
(void) - performFlyRacepoints
 
(void) - addPrimaryAggressorAsDefenseTarget
 
(void) - addFoundTargetAsDefenseTarget
 
(void) - findNewDefenseTarget
 
(void) - setDestinationToJinkPosition [implementation]
 
(void) - disengageAutopilot [implementation]
 
(void) - messageSelf: [implementation]
 
(void) - scanForNearestShipMatchingPredicate: [implementation]
 
(void) - safeScriptActionOnTarget: [implementation]
 

Detailed Description

Definition at line 72 of file ShipEntityAI.m.

Method Documentation

◆ addFoundTargetAsDefenseTarget

- (void) addFoundTargetAsDefenseTarget

Definition at line 1 of file ShipEntityAI.m.

1152{
1153 Entity* fTarget = [self foundTarget];
1154 if (fTarget != nil)
1155 {
1156 if ([fTarget isShip] && ![(ShipEntity *)fTarget isFriendlyTo:self])
1157 {
1158 [self addDefenseTarget:fTarget];
1159 }
1160 }
1161}
return self
return nil

◆ addFuel:

- (void) addFuel: (NSString *)  fuel_number

Definition at line 1 of file ShipEntityAI.m.

2553 :(NSString*) fuel_number
2554{
2555 [self setFuel:[self fuel] + [fuel_number intValue] * 10];
2556}

◆ addPrimaryAggressorAsDefenseTarget

- (void) addPrimaryAggressorAsDefenseTarget

Definition at line 1 of file ShipEntityAI.m.

976{
977 Entity *primeAggressor = [self primaryAggressor];
978 if (!primeAggressor)
979 return;
980 if ([self isDefenseTarget:primeAggressor])
981 return;
982
983 if ([primeAggressor isShip] && ![(ShipEntity*)primeAggressor isFriendlyTo:self])
984 {
985 [self addDefenseTarget:primeAggressor];
986 }
987}

◆ ai_debugMessage:

- (void) ai_debugMessage: (NSString *)  message

Definition at line 1 of file ShipEntityAI.m.

2643 :(NSString *)message
2644{
2645 NSString *desc = [NSString stringWithFormat:@"%@ %d", [self name], [self universalID]];
2646 if ([self isPlayer]) desc = @"player autopilot";
2647 OOLog(@"ai.takeAction.debugMessage", @"DEBUG: AI MESSAGE from %@: %@", desc, message);
2648}
#define OOLog(class, format,...)
Definition OOLogging.h:88

◆ ai_throwSparks

- (void) ai_throwSparks

Definition at line 1 of file ShipEntityAI.m.

2632{
2633 [self setThrowSparks:YES];
2634}

◆ becomeUncontrolledThargon

- (void) becomeUncontrolledThargon

Definition at line 1 of file ShipEntityAI.m.

1744{
1745 int ent_count = UNIVERSE->n_entities;
1746 Entity** uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
1747 int i;
1748 for (i = 0; i < ent_count; i++) if (uni_entities[i]->isShip)
1749 {
1750 ShipEntity *other = (ShipEntity*)uni_entities[i];
1751 if ([other primaryTarget] == self)
1752 {
1753 [other removeTarget:self];
1754 }
1755 if ([other isDefenseTarget:self])
1756 {
1757 [other removeDefenseTarget:self];
1758 }
1759 }
1760 // now we're just a bunch of alien artefacts!
1761 scanClass = CLASS_CARGO;
1762 reportAIMessages = NO;
1763 [self setAITo:@"dumbAI.plist"];
1764 DESTROY(_primaryTarget);
1765 [self setSpeed: 0.0];
1766 [self setGroup:nil];
1767}
#define DESTROY(x)
Definition OOCocoa.h:75
#define UNIVERSE
Definition Universe.h:842
void removeTarget:(Entity *targetEntity)
void removeDefenseTarget:(Entity *target)

◆ checkAegis

- (void) checkAegis

Definition at line 1 of file ShipEntityAI.m.

1461{
1462 switch (aegis_status)
1463 {
1465 [shipAI message:@"AEGIS_CLOSE_TO_MAIN_PLANET"];
1466 // It's been a few years since 1.71 - it should be safe enough to comment out the line below for 1.77/1.78 -- Kaks 20120917
1467 //[shipAI message:@"AEGIS_CLOSE_TO_PLANET"]; // fires only for main planets, kept for compatibility with pre-1.72 AI plists.
1468 return;
1470 {
1471 Entity<OOStellarBody> *nearest = [self findNearestStellarBody];
1472
1473 if([nearest isSun])
1474 {
1475 [shipAI message:@"CLOSE_TO_SUN"];
1476 }
1477 else
1478 {
1479 [shipAI message:@"CLOSE_TO_PLANET"];
1480 if ([nearest planetType] == STELLAR_TYPE_MOON)
1481 {
1482 [shipAI message:@"CLOSE_TO_MOON"];
1483 }
1484 else
1485 {
1486 [shipAI message:@"CLOSE_TO_SECONDARY_PLANET"];
1487 }
1488 }
1489 return;
1490 }
1492 [shipAI message:@"AEGIS_IN_DOCKING_RANGE"];
1493 return;
1494 case AEGIS_NONE:
1495 [shipAI message:@"AEGIS_NONE"];
1496 return;
1497 }
1498
1499 NSLog(@"Aegis status for %@ has taken on invalid value %i. This is an internal error, please report it.", self, aegis_status);
1500 aegis_status = AEGIS_NONE;
1501 [shipAI message:@"AEGIS_NONE"];
1502}
#define NSLog(format,...)
Definition OOLogging.h:137
@ STELLAR_TYPE_MOON
@ AEGIS_IN_DOCKING_RANGE
Definition OOTypes.h:64
@ AEGIS_CLOSE_TO_MAIN_PLANET
Definition OOTypes.h:63
@ AEGIS_CLOSE_TO_ANY_PLANET
Definition OOTypes.h:62
@ AEGIS_NONE
Definition OOTypes.h:61

◆ checkCourseToDestination

- (void) checkCourseToDestination

Definition at line 1 of file ShipEntityAI.m.

1442{
1443 Entity *hazard = [UNIVERSE hazardOnRouteFromEntity: self toDistance: desired_range fromPoint: _destination];
1444
1445 if (hazard == nil || ([hazard isShip] && HPdistance(position, [hazard position]) > scannerRange) || ([hazard isPlanet] && aegis_status == AEGIS_NONE))
1446 [shipAI message:@"COURSE_OK"]; // Avoid going into a waypoint.plist for far away objects, it cripples the main AI a bit in its funtionality.
1447 else
1448 {
1449 if ([hazard isShip] && (weapon_damage * 24.0 > [hazard energy]))
1450 {
1451 [shipAI reactToMessage:@"HAZARD_CAN_BE_DESTROYED" context:@"checkCourseToDestination"];
1452 }
1453
1454 _destination = [UNIVERSE getSafeVectorFromEntity:self toDistance:desired_range fromPoint:_destination];
1455 [shipAI message:@"WAYPOINT_SET"];
1456 }
1457}

◆ checkDistanceTravelled

- (void) checkDistanceTravelled

Definition at line 1 of file ShipEntityAI.m.

1771{
1772 if (distanceTravelled > desired_range)
1773 [shipAI message:@"GONE_BEYOND_RANGE"];
1774}

◆ checkEnergy

- (void) checkEnergy

Definition at line 1 of file ShipEntityAI.m.

1506{
1507 if (energy == maxEnergy)
1508 {
1509 [shipAI message:@"ENERGY_FULL"];
1510 return;
1511 }
1512 if (energy >= maxEnergy * 0.75)
1513 {
1514 [shipAI message:@"ENERGY_HIGH"];
1515 return;
1516 }
1517 if (energy <= maxEnergy * 0.25)
1518 {
1519 [shipAI message:@"ENERGY_LOW"];
1520 return;
1521 }
1522 [shipAI message:@"ENERGY_MEDIUM"];
1523}

◆ checkForFullHold

- (void) checkForFullHold

Definition at line 1 of file ShipEntityAI.m.

1164{
1165 if (!max_cargo)
1166 {
1167 [shipAI message:@"NO_CARGO_BAY"];
1168 }
1169 else if ([cargo count] >= [self maxAvailableCargoSpace])
1170 {
1171 [shipAI message:@"HOLD_FULL"];
1172 }
1173 else
1174 {
1175 [shipAI message:@"HOLD_NOT_FULL"];
1176 }
1177}
unsigned count

◆ checkForMotherStation

- (void) checkForMotherStation

Definition at line 1 of file ShipEntityAI.m.

2060{
2061 ShipEntity *motherStation = [[self group] leader];
2062 if ((!motherStation) || (!(motherStation->isStation)))
2063 {
2064 [shipAI message:@"NOTHING_FOUND"];
2065 return;
2066 }
2067 double found_d2 = scannerRange * scannerRange;
2068 HPVector v0 = motherStation->position;
2069 if (HPdistance2(v0,position) > found_d2)
2070 {
2071 [shipAI message:@"NOTHING_FOUND"];
2072 return;
2073 }
2074 [shipAI message:@"STATION_FOUND"];
2075}
unsigned isStation
Definition Entity.h:92
HPVector position
Definition Entity.h:112

◆ checkForNormalSpace

- (void) checkForNormalSpace

Definition at line 1 of file ShipEntityAI.m.

2475{
2476 if ([UNIVERSE sun] && [UNIVERSE planet])
2477 [shipAI message:@"NORMAL_SPACE"];
2478 else
2479 [shipAI message:@"INTERSTELLAR_SPACE"];
2480}

◆ checkGroupOddsVersusTarget

- (void) checkGroupOddsVersusTarget

Definition at line 1 of file ShipEntityAI.m.

1853{
1854 NSUInteger ownGroupCount = [[self group] count] + (ranrot_rand() & 3); // add a random fudge factor
1855 NSUInteger targetGroupCount = [[[self primaryTarget] group] count] + (ranrot_rand() & 3); // add a random fudge factor
1856
1857 if (ownGroupCount == targetGroupCount)
1858 {
1859 [shipAI message:@"ODDS_LEVEL"];
1860 }
1861 else if (ownGroupCount > targetGroupCount)
1862 {
1863 [shipAI message:@"ODDS_GOOD"];
1864 }
1865 else
1866 {
1867 [shipAI message:@"ODDS_BAD"];
1868 }
1869}
#define ranrot_rand()

◆ checkHeatInsulation

- (void) checkHeatInsulation

Definition at line 1 of file ShipEntityAI.m.

1526{
1527 float minInsulation = 1000 / [self maxFlightSpeed] + 1;
1528
1529 if ([self heatInsulation] < minInsulation)
1530 {
1531 [shipAI message:@"INSULATION_POOR"];
1532 return;
1533 }
1534 [shipAI message:@"INSULATION_OK"];
1535}

◆ checkOwnLegalStatus

- (void) checkOwnLegalStatus

Definition at line 1 of file ShipEntityAI.m.

1386{
1387 if (scanClass == CLASS_THARGOID)
1388 {
1389 [shipAI message:@"SELF_THARGOID"];
1390 return;
1391 }
1392 int ls = [self legalStatus];
1393 if (ls > 50)
1394 {
1395 [shipAI message:@"SELF_FUGITIVE"];
1396 return;
1397 }
1398 if (ls > 20)
1399 {
1400 [shipAI message:@"SELF_OFFENDER"];
1401 return;
1402 }
1403 if (ls > 0)
1404 {
1405 [shipAI message:@"SELF_MINOR_OFFENDER"];
1406 return;
1407 }
1408 [shipAI message:@"SELF_CLEAN"];
1409}

◆ checkTargetLegalStatus

- (void) checkTargetLegalStatus

Definition at line 1 of file ShipEntityAI.m.

1355{
1356 ShipEntity *other_ship = [self primaryTarget];
1357 if (!other_ship)
1358 {
1359 [shipAI message:@"NO_TARGET"];
1360 return;
1361 }
1362 else
1363 {
1364 int ls = [other_ship legalStatus];
1365 if (ls > 50)
1366 {
1367 [shipAI message:@"TARGET_FUGITIVE"];
1368 return;
1369 }
1370 if (ls > 20)
1371 {
1372 [shipAI message:@"TARGET_OFFENDER"];
1373 return;
1374 }
1375 if (ls > 0)
1376 {
1377 [shipAI message:@"TARGET_MINOR_OFFENDER"];
1378 return;
1379 }
1380 [shipAI message:@"TARGET_CLEAN"];
1381 }
1382}
int legalStatus()

◆ commsMessage:

- (void) commsMessage: (NSString *)  valueString

Definition at line 1 of file ShipEntityAI.m.

1658 :(NSString *)valueString
1659{
1660 [self commsMessage:valueString withUnpilotedOverride:NO];
1661}

◆ commsMessageByUnpiloted:

- (void) commsMessageByUnpiloted: (NSString *)  valueString

Definition at line 1 of file ShipEntityAI.m.

1664 :(NSString *)valueString
1665{
1666 [self commsMessage:valueString withUnpilotedOverride:YES];
1667}

◆ debugDumpPendingMessages

- (void) debugDumpPendingMessages

Definition at line 1 of file ShipEntityAI.m.

887{
888 [shipAI debugDumpPendingMessages];
889}

◆ disengageAutopilot

- (void) disengageAutopilot
implementation

Definition at line 1 of file ShipEntityAI.m.

1636{
1637 OOLogERR(@"ai.invalid.notPlayer", @"Error in %@:%@, AI method endAutoPilot is only applicable to the player.", [shipAI name], [shipAI state]);
1638}
#define OOLogERR(class, format,...)
Definition OOLogging.h:112

◆ dropMessages:

- (void) dropMessages: (NSString *)  messageString

Definition at line 1 of file ShipEntityAI.m.

872 :(NSString *)messageString
873{
874 NSArray *messages = nil;
875 NSString *message = nil;
876 NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceCharacterSet];
877
878 messages = [messageString componentsSeparatedByString:@","];
879 foreach (message, messages)
880 {
881 [shipAI dropMessage:[message stringByTrimmingCharactersInSet:whiteSpace]];
882 }
883}

◆ ejectCargo

- (void) ejectCargo

Definition at line 1 of file ShipEntityAI.m.

1671{
1672 OOCargoQuantity i, cargo_to_go = 0.1 * [self maxAvailableCargoSpace];
1673 while (cargo_to_go > 15)
1674 {
1675 cargo_to_go = ranrot_rand() % cargo_to_go;
1676 }
1677 [self dumpCargo];
1678 for (i = 1; i < cargo_to_go; i++)
1679 {
1680 [self performSelector:@selector(dumpCargo) withObject:nil afterDelay:0.75 * i]; // drop 3 canisters per 2 seconds
1681 }
1682}
uint32_t OOCargoQuantity
Definition OOTypes.h:176

◆ escortCheckMother

- (void) escortCheckMother

Definition at line 1 of file ShipEntityAI.m.

1834{
1835 ShipEntity *mother = [self owner];
1836
1837 if ([mother acceptAsEscort:self])
1838 {
1839 [self setOwner:mother];
1840 [self setGroup:[mother escortGroup]];
1841 [shipAI message:@"ESCORTING"];
1842 }
1843 else
1844 {
1845 [self setOwner:self];
1846 if ([self group] == [mother escortGroup]) [self setGroup:nil];
1847 [shipAI message:@"NOT_ESCORTING"];
1848 }
1849}
OOShipGroup * escortGroup()

◆ exitAIWithMessage:

- (void) exitAIWithMessage: (NSString *)  message

Definition at line 1 of file ShipEntityAI.m.

1412 :(NSString *)message
1413{
1414 if ([message length] == 0) message = @"RESTARTED";
1415 [shipAI exitStateMachineWithMessage:message];
1416}

◆ explodeSelf

- (void) explodeSelf

Definition at line 1 of file ShipEntityAI.m.

2638{
2639 [self getDestroyedBy:nil damageType:kOODamageTypeEnergy];
2640}

◆ fightOrFleeHostiles

- (void) fightOrFleeHostiles

Definition at line 1 of file ShipEntityAI.m.

1778{
1779 [self addDefenseTarget:[self foundTarget]];
1780
1781 if ([self hasEscorts])
1782 {
1783 Entity *leTarget = [self lastEscortTarget];
1784 if (leTarget != nil)
1785 {
1786 [self setFoundTarget:leTarget];
1787 [shipAI message:@"FLEEING"];
1788 return;
1789 }
1790
1791 [self setPrimaryAggressor:[self foundTarget]];
1792 [self addTarget:[self foundTarget]];
1793 [self deployEscorts];
1794 [shipAI message:@"DEPLOYING_ESCORTS"];
1795 [shipAI message:@"FLEEING"];
1796 return;
1797 }
1798
1799 // consider launching a missile
1800 if (missiles > 2) // keep a reserve
1801 {
1802 if (randf() < 0.50)
1803 {
1804 [self setPrimaryAggressor:[self foundTarget]];
1805 [self addTarget:[self foundTarget]];
1806 [self fireMissile];
1807 [shipAI message:@"FLEEING"];
1808 return;
1809 }
1810 }
1811
1812 // consider fighting
1813 if (energy > maxEnergy * 0.80)
1814 {
1815 [self setPrimaryAggressor:[self foundTarget]];
1816 //[self performAttack];
1817 [shipAI message:@"FIGHTING"];
1818 return;
1819 }
1820
1821 [shipAI message:@"FLEEING"];
1822}
float randf(void)

◆ fightOrFleeMissile

- (void) fightOrFleeMissile

Definition at line 1 of file ShipEntityAI.m.

1228{
1229 // find an incoming missile...
1230 //
1231 ShipEntity *missile = nil;
1232 unsigned i;
1233 ShipEntity *escort = nil;
1234 ShipEntity *target = nil;
1235
1236 [self checkScannerIgnoringUnpowered];
1237 for (i = 0; (i < n_scanned_ships)&&(missile == nil); i++)
1238 {
1239 ShipEntity *thing = scanned_ships[i];
1240 if (thing->scanClass == CLASS_MISSILE)
1241 {
1242 target = [thing primaryTarget];
1243
1244 if (target == self)
1245 {
1246 missile = thing;
1247 }
1248 else
1249 {
1250 foreach (escort, [self escortEnumerator])
1251 {
1252 if (target == escort)
1253 {
1254 missile = thing;
1255 }
1256 }
1257 }
1258 }
1259 }
1260
1261 if (missile == nil) return;
1262
1263 [self addTarget:missile];
1264 [self addDefenseTarget:missile];
1265
1266 // Notify own ship script that we are being attacked.
1267 ShipEntity *hunter = [missile owner];
1268 [self doScriptEvent:OOJSID("shipBeingAttacked") withArgument:hunter];
1269 [hunter doScriptEvent:OOJSID("shipAttackedOther") withArgument:self];
1270
1271 if ([self isPolice])
1272 {
1273 // Notify other police in group of attacker.
1274 // Note: prior to 1.73 this was done only if we had ECM.
1275 ShipEntity *police = nil;
1276
1277 foreach (police, [[self group] mutationSafeEnumerator])
1278 {
1279 [police setFoundTarget:hunter];
1280 [police setPrimaryAggressor:hunter];
1281 }
1282 }
1283
1284 // if I'm a copper and you're not, then mark the other as an offender!
1285 if ([self isPolice] && ![hunter isPolice]) [hunter markAsOffender:64 withReason:kOOLegalStatusReasonAttackedPolice];
1286
1287 if ([self hasECM])
1288 {
1289 // use the ECM and battle on
1290
1291 [self setPrimaryAggressor:hunter]; // lets get them now for that!
1292 [self setFoundTarget:hunter];
1293
1294 [self fireECM];
1295 return;
1296 }
1297
1298 // RUN AWAY !!
1299 desired_range = 10000;
1300 [self performFlee];
1301 [shipAI message:@"FLEEING"];
1302}
id owner()
Definition Entity.m:584
void setPrimaryAggressor:(Entity *targetEntity)
OOScanClass scanClass()
void markAsOffender:withReason:(int offence_value,[withReason] OOLegalStatusReason reason)
void doScriptEvent:withArgument:(jsid message,[withArgument] id argument)
void setFoundTarget:(Entity *targetEntity)

◆ findNewDefenseTarget

- (void) findNewDefenseTarget

Definition at line 1 of file ShipEntityAI.m.

1539{
1540 [self checkScanner];
1541 unsigned i;
1542 for (i = 0; i < n_scanned_ships ; i++)
1543 {
1544 ShipEntity *ship = scanned_ships[i];
1545 if (![ship isCloaked] && (([ship primaryTarget] == self && [ship hasHostileTarget]) || [ship isMine] || ([ship isThargoid] != [self isThargoid])))
1546 {
1547 if (![self isDefenseTarget:ship])
1548 {
1549 [self addDefenseTarget:ship];
1550 return;
1551 }
1552 }
1553 }
1554}

◆ getWitchspaceEntryCoordinates

- (void) getWitchspaceEntryCoordinates

Definition at line 1 of file ShipEntityAI.m.

1184{
1185 /*- calculates coordinates from the nearest station it can find, or just fly 10s forward -*/
1186 if (!UNIVERSE)
1187 {
1188 Vector vr = vector_multiply_scalar(v_forward, maxFlightSpeed * 10.0); // 10 second flying away
1189 coordinates = HPvector_add(position, vectorToHPVector(vr));
1190 return;
1191 }
1192 //
1193 // find the nearest station...
1194 //
1195 // we don't use "checkScanner" because we must rely on finding a present station.
1196 //
1197 StationEntity *station = nil;
1198 station = [UNIVERSE nearestShipMatchingPredicate:IsStationPredicate
1199 parameter:nil
1200 relativeToEntity:self];
1201
1202 if (station && HPdistance2([station position], position) < SCANNER_MAX_RANGE2) // there is a station in range.
1203 {
1204 Vector vr = vector_multiply_scalar([station rightVector], 10000); // 10km from station
1205 coordinates = HPvector_add([station position], vectorToHPVector(vr));
1206 }
1207 else
1208 {
1209 Vector vr = vector_multiply_scalar(v_forward, maxFlightSpeed * 10.0); // 10 second flying away
1210 coordinates = HPvector_add(position, vectorToHPVector(vr));
1211 }
1212}
#define SCANNER_MAX_RANGE2
Definition Entity.h:52

◆ landOnPlanet

- (void) landOnPlanet

Definition at line 1 of file ShipEntityAI.m.

1348{
1349 // Selects the nearest planet it can find.
1350 [self landOnPlanet:[self findNearestPlanet]];
1351}

◆ markTargetForFines

- (void) markTargetForFines

Definition at line 1 of file ShipEntityAI.m.

2091{
2092 ShipEntity *ship = [self primaryTarget];
2093 if ((ship == nil) || ([ship status] == STATUS_DEAD) || ([ship status] == STATUS_DOCKED))
2094 {
2095 [self noteLostTarget];
2096 return;
2097 }
2098 if ([ship markForFines]) [shipAI message:@"TARGET_MARKED"];
2099}

◆ markTargetForOffence:

- (void) markTargetForOffence: (NSString *)  valueString

Definition at line 1 of file ShipEntityAI.m.

2102 :(NSString *)valueString
2103{
2104 if ((isStation)||(scanClass == CLASS_POLICE))
2105 {
2106 ShipEntity *ship = [self primaryTarget];
2107 if ((ship == nil) || ([ship status] == STATUS_DEAD) || ([ship status] == STATUS_DOCKED))
2108 {
2109 [self noteLostTarget];
2110 return;
2111 }
2112 NSString *finalValue = OOExpand(valueString); // expand values
2113 [ship markAsOffender:[finalValue intValue] withReason:kOOLegalStatusReasonSeenByPolice];
2114 }
2115}
#define OOExpand(string,...)
OOEntityStatus status()
Definition Entity.m:794

◆ messageMother:

- (void) messageMother: (NSString *)  msgString

Definition at line 1 of file ShipEntityAI.m.

1910 :(NSString *)msgString
1911{
1912 ShipEntity *mother = [self owner];
1913 if (mother != nil && mother != self)
1914 {
1915 NSString *context = nil;
1916#ifndef NDEBUG
1917 context = [NSString stringWithFormat:@"%@ messageMother", [self shortDescription]];
1918#endif
1919 [mother reactToAIMessage:msgString context:context];
1920 }
1921}
void reactToAIMessage:context:(NSString *message,[context] NSString *debugContext)

◆ messageSelf:

- (void) messageSelf: (NSString *)  msgString
implementation

Definition at line 1 of file ShipEntityAI.m.

1924 :(NSString *)msgString
1925{
1926 [self sendAIMessage:msgString];
1927}

◆ patrolReportIn

- (void) patrolReportIn

Definition at line 1 of file ShipEntityAI.m.

2051{
2052 // Set a report time in the patrolled station to delay a new launch.
2053 ShipEntity *the_station = [[self group] leader];
2054 if(!the_station || ![the_station isStation]) the_station = [UNIVERSE station];
2055 [(StationEntity*)the_station acceptPatrolReportFrom:self];
2056}

◆ pauseAI:

- (void) pauseAI: (NSString *)  intervalString

Definition at line 1 of file ShipEntityAI.m.

848 :(NSString *)intervalString
849{
850 [shipAI setNextThinkTime:[UNIVERSE getTime] + [intervalString doubleValue]];
851}

◆ performFlyRacepoints

- (void) performFlyRacepoints

Definition at line 1 of file ShipEntityAI.m.

2726{
2727 next_navpoint_index = 0;
2728 desired_range = collision_radius;
2729 behaviour = BEHAVIOUR_FLY_THRU_NAVPOINTS;
2730}

◆ performHyperSpaceExit

- (void) performHyperSpaceExit

Definition at line 1 of file ShipEntityAI.m.

1624{
1625 [self performHyperSpaceExitReplace:YES];
1626}

◆ performHyperSpaceExitWithoutReplacing

- (void) performHyperSpaceExitWithoutReplacing

Definition at line 1 of file ShipEntityAI.m.

1630{
1631 [self performHyperSpaceExitReplace:NO];
1632}

◆ randomPauseAI:

- (void) randomPauseAI: (NSString *)  intervalString

Definition at line 1 of file ShipEntityAI.m.

854 :(NSString *)intervalString
855{
856 NSArray* tokens = ScanTokensFromString(intervalString);
857 double start, end;
858
859 if ([tokens count] != 2)
860 {
861 OOLog(@"ai.syntax.randomPauseAI", @"***** ERROR: cannot read min and max value for randomPauseAI:, needs 2 values: '%@'.", intervalString);
862 return;
863 }
864
865 start = [tokens oo_doubleAtIndex:0];
866 end = [tokens oo_doubleAtIndex:1];
867
868 [shipAI setNextThinkTime:[UNIVERSE getTime] + (start + (end - start)*randf())];
869}
NSMutableArray * ScanTokensFromString(NSString *values)

◆ recallStoredTarget

- (void) recallStoredTarget

Definition at line 1 of file ShipEntityAI.m.

2134{
2135 ShipEntity *oldTarget = (ShipEntity*)[self rememberedShip];
2136 BOOL found = NO;
2137
2138 if (oldTarget && ![oldTarget isCloaked])
2139 {
2140 GLfloat range2 = HPdistance2([oldTarget position], position);
2141 if (range2 <= scannerRange * scannerRange && range2 <= SCANNER_MAX_RANGE2)
2142 {
2143 found = YES;
2144 }
2145 }
2146
2147 if (found)
2148 {
2149 [self setFoundTarget:oldTarget];
2150 [shipAI message:@"TARGET_FOUND"];
2151 }
2152 else
2153 {
2154 if (oldTarget == nil) DESTROY(_rememberedShip); // ship no longer exists
2155 [shipAI message:@"NOTHING_FOUND"];
2156 }
2157
2158}

◆ requestNewTarget

- (void) requestNewTarget

Definition at line 1 of file ShipEntityAI.m.

2227{
2228 ShipEntity *mother = [[self group] leader];
2229 if (mother == nil)
2230 {
2231 [shipAI message:@"MOTHER_LOST"];
2232 return;
2233 }
2234
2235 /*-- Locates all the ships in range targeting the mother ship and chooses the nearest/biggest --*/
2236 DESTROY(_foundTarget);
2237 [self checkScanner];
2238 unsigned i;
2239 GLfloat found_d2 = scannerRange * scannerRange;
2240 GLfloat max_e = 0;
2241 for (i = 0; i < n_scanned_ships ; i++)
2242 {
2243 ShipEntity *thing = scanned_ships[i];
2244 GLfloat d2 = distance2_scanned_ships[i];
2245 GLfloat e1 = [thing energy];
2246 if ((d2 < found_d2) && ![thing isCloaked] && (([thing isThargoid] && ![mother isThargoid]) || (([thing primaryTarget] == mother) && [thing hasHostileTarget])))
2247 {
2248 if (e1 > max_e)
2249 {
2250 [self setFoundTarget:thing];
2251 max_e = e1;
2252 }
2253 }
2254 }
2255
2256 [self checkFoundTarget];
2257}
GLfloat energy
Definition Entity.h:142

◆ rollD:

- (void) rollD: (NSString *)  die_number

Definition at line 1 of file ShipEntityAI.m.

2260 :(NSString *)die_number
2261{
2262 int die_sides = [die_number intValue];
2263 if (die_sides > 0)
2264 {
2265 int die_roll = 1 + (ranrot_rand() % die_sides);
2266 NSString* result = [NSString stringWithFormat:@"ROLL_%d", die_roll];
2267 [shipAI reactToMessage:result context:@"rollD:"];
2268 }
2269 else
2270 {
2271 OOLog(@"ai.rollD.invalidValue", @"***** ERROR: invalid value supplied to rollD: '%@'.", die_number);
2272 }
2273}

◆ safeScriptActionOnTarget:

- (void) safeScriptActionOnTarget: (NSString *)  action
implementation

Definition at line 1 of file ShipEntityAI.m.

2594 :(NSString *)action
2595{
2596 PlayerEntity *player = PLAYER;
2597 ShipEntity *targEnt = [self primaryTarget];
2598 ShipEntity *oldTarget = nil;
2599
2600 if ([targEnt isShip])
2601 {
2602 oldTarget = [player scriptTarget];
2603 [player setScriptTarget:(ShipEntity*)targEnt];
2604 [player runUnsanitizedScriptActions:[NSArray arrayWithObject:action]
2606 withContextName:[NSString stringWithFormat:@"<AI \"%@\" state %@ - safeScriptActionOnTarget:>", [[self getAI] name], [[self getAI] state]]
2607 forTarget:targEnt];
2608 [player setScriptTarget:oldTarget];
2609 }
2610}
#define PLAYER
void runUnsanitizedScriptActions:allowingAIMethods:withContextName:forTarget:(NSArray *unsanitizedActions,[allowingAIMethods] BOOL allowAIMethods,[withContextName] NSString *contextName,[forTarget] ShipEntity *target)
void setScriptTarget:(ShipEntity *ship)

◆ scanForFormationLeader

- (void) scanForFormationLeader

Definition at line 1 of file ShipEntityAI.m.

1875{
1876 //-- Locates the nearest suitable formation leader in range --//
1877 DESTROY(_foundTarget);
1878 [self checkScannerIgnoringUnpowered];
1879 unsigned i;
1880 GLfloat found_d2 = scannerRange * scannerRange;
1881 for (i = 0; i < n_scanned_ships; i++)
1882 {
1883 ShipEntity *ship = scanned_ships[i];
1884 if ((ship != self) && (!ship->isPlayer) && (ship->scanClass == scanClass) && [ship primaryTarget] != self && ![ship isCloaked]) // look for alike
1885 {
1886 GLfloat d2 = distance2_scanned_ships[i];
1887 if ((d2 < found_d2) && [ship canAcceptEscort:self])
1888 {
1889 found_d2 = d2;
1890 [self setFoundTarget:ship];
1891 }
1892 }
1893 }
1894
1895 if ([self foundTarget] != nil) [shipAI message:@"TARGET_FOUND"];
1896 else
1897 {
1898 [shipAI message:@"NOTHING_FOUND"];
1899 if ([self hasPrimaryRole:@"wingman"])
1900 {
1901 // become free-lance police :)
1902 [self setAITo:@"route1patrolAI.plist"]; // use this to avoid referencing a released AI
1903 [self setPrimaryRole:@"police"]; // other wingman can now select this ship as leader.
1904 }
1905 }
1906
1907}
unsigned isPlayer
Definition Entity.h:93

◆ scanForLoot

- (void) scanForLoot

Definition at line 1 of file ShipEntityAI.m.

1054{
1055 /*-- Locates the nearest debris in range --*/
1056 if (!isStation)
1057 {
1058 if (![self hasCargoScoop])
1059 {
1060 [shipAI message:@"NOTHING_FOUND"]; //can't collect loot if you have no scoop!
1061 return;
1062 }
1063 if ([cargo count] >= [self maxAvailableCargoSpace])
1064 {
1065 if (max_cargo) [shipAI message:@"HOLD_FULL"]; //can't collect loot if holds are full!
1066 [shipAI message:@"NOTHING_FOUND"]; //can't collect loot if holds are full!
1067 return;
1068 }
1069 }
1070 else
1071 {
1072 if (magnitude2([self velocity]))
1073 {
1074 [shipAI message:@"NOTHING_FOUND"]; //can't collect loot if you're a moving station
1075 return;
1076 }
1077 }
1078
1079 [self checkScanner];
1080
1081 double found_d2 = scannerRange * scannerRange;
1082 DESTROY(_foundTarget);
1083 unsigned i;
1084 for (i = 0; i < n_scanned_ships; i++)
1085 {
1086 ShipEntity *other = (ShipEntity *)scanned_ships[i];
1087 if ([other scanClass] == CLASS_CARGO && [other cargoType] != CARGO_NOT_CARGO && [other status] != STATUS_BEING_SCOOPED)
1088 {
1089 if ((![self isPolice]) || ([[other commodityType] isEqualToString:@"slaves"])) // police only rescue lifepods and slaves
1090 {
1091 GLfloat d2 = distance2_scanned_ships[i];
1092 if (d2 < found_d2)
1093 {
1094 found_d2 = d2;
1095 [self setFoundTarget:other];
1096 }
1097 }
1098 }
1099 }
1100 [self checkFoundTarget];
1101}
@ CARGO_NOT_CARGO
Definition OOTypes.h:70

◆ scanForNearestMerchantman

- (void) scanForNearestMerchantman

Definition at line 1 of file ShipEntityAI.m.

991{
992 float d2, found_d2;
993 unsigned i;
994 ShipEntity *ship = nil;
995
996 //-- Locates the nearest merchantman in range.
997 [self checkScannerIgnoringUnpowered];
998
999 found_d2 = scannerRange * scannerRange;
1000 DESTROY(_foundTarget);
1001
1002 for (i = 0; i < n_scanned_ships ; i++)
1003 {
1004 ship = scanned_ships[i];
1005 if ([ship isPirateVictim] && ([ship status] != STATUS_DEAD) && ([ship status] != STATUS_DOCKED) && ![ship isCloaked])
1006 {
1007 d2 = distance2_scanned_ships[i];
1008 if (PIRATES_PREFER_PLAYER && (d2 < desired_range * desired_range) && ship->isPlayer && [self isPirate])
1009 {
1010 d2 = 0.0;
1011 }
1012 else d2 = distance2_scanned_ships[i];
1013 if (d2 < found_d2)
1014 {
1015 found_d2 = d2;
1016 [self setFoundTarget:ship];
1017 }
1018 }
1019 }
1020 [self checkFoundTarget];
1021}
#define PIRATES_PREFER_PLAYER
Definition ShipEntity.h:40

◆ scanForNearestShipHavingAnyRole:

- (void) scanForNearestShipHavingAnyRole: (NSString *)  scanRoles

Definition at line 1 of file ShipEntityAI.m.

2295 :(NSString *)scanRoles
2296{
2297 NSSet *set = [NSSet setWithArray:ScanTokensFromString(scanRoles)];
2298 [self scanForNearestShipWithPredicate:HasRoleInSetPredicate parameter:set];
2299}

◆ scanForNearestShipHavingRole:

- (void) scanForNearestShipHavingRole: (NSString *)  scanRole

Definition at line 1 of file ShipEntityAI.m.

2282 :(NSString *)scanRole
2283{
2284 [self scanForNearestShipWithPredicate:HasRolePredicate parameter:scanRole];
2285}

◆ scanForNearestShipMatchingPredicate:

- (void) scanForNearestShipMatchingPredicate: (NSString *)  predicateExpression
implementation

Definition at line 1 of file ShipEntityAI.m.

2342 :(NSString *)predicateExpression
2343{
2344 /* Takes a boolean-valued JS expression where "ship" is the ship being
2345 evaluated and "this" is our ship's ship script. the expression is
2346 turned into a JS function of the form:
2347
2348 function _oo_AIScanPredicate(ship)
2349 {
2350 return $expression;
2351 }
2352
2353 Examples of expressions:
2354 ship.isWeapon
2355 this.someComplicatedPredicate(ship)
2356 function (ship) { ...do something complicated... } ()
2357 */
2358
2359 static NSMutableDictionary *scriptCache = nil;
2360 NSString *aiName = nil;
2361 NSString *key = nil;
2362 OOJSFunction *function = nil;
2363 JSContext *context = NULL;
2364
2365 context = OOJSAcquireContext();
2366
2367 if (predicateExpression == nil) predicateExpression = @"false";
2368
2369 aiName = [[self getAI] name];
2370#ifndef NDEBUG
2371 /* In debug/test release builds, scripts are cached per AI in order to be
2372 able to report errors correctly. For end-user releases, we only cache
2373 one copy of each predicate, potentially leading to error messages for
2374 the wrong AI.
2375 */
2376 key = [NSString stringWithFormat:@"%@\n%@", aiName, predicateExpression];
2377#else
2378 key = predicateExpression;
2379#endif
2380
2381 // Look for cached function
2382 function = [scriptCache objectForKey:key];
2383 if (function == nil)
2384 {
2385 NSString *predicateCode = nil;
2386 const char *argNames[] = { "ship" };
2387
2388 // Stuff expression in a function.
2389 predicateCode = [NSString stringWithFormat:@"return %@;", predicateExpression];
2390 function = [[OOJSFunction alloc] initWithName:@"_oo_AIScanPredicate"
2391 scope:NULL
2392 code:predicateCode
2393 argumentCount:1
2394 argumentNames:argNames
2395 fileName:aiName
2396 lineNumber:0
2397 context:context];
2398 [function autorelease];
2399
2400 // Cache function.
2401 if (function != nil)
2402 {
2403 if (scriptCache == nil) scriptCache = [[NSMutableDictionary alloc] init];
2404 [scriptCache setObject:function forKey:key];
2405 }
2406 }
2407
2408 if (function != nil)
2409 {
2411 {
2412 .context = context,
2413 .function = [function functionValue],
2414 .jsThis = OOJSObjectFromNativeObject(context, self)
2415 };
2416 [self scanForNearestShipWithPredicate:JSFunctionPredicate parameter:&param];
2417 }
2418 else
2419 {
2420 // Report error (once per occurrence)
2421 static NSMutableSet *errorCache = nil;
2422
2423 if (![errorCache containsObject:key])
2424 {
2425 OOLog(@"ai.scanForNearestShipMatchingPredicate.compile.failed", @"Could not compile JavaScript predicate \"%@\" for AI %@.", predicateExpression, [[self getAI] name]);
2426 if (errorCache == nil) errorCache = [[NSMutableSet alloc] init];
2427 [errorCache addObject:key];
2428 }
2429
2430 // Select nothing
2431 DESTROY(_foundTarget);
2432 [[self getAI] message:@"NOTHING_FOUND"];
2433 }
2434
2435 JS_ReportPendingException(context);
2436 OOJSRelinquishContext(context);
2437}
JSObject * OOJSObjectFromNativeObject(JSContext *context, id object)
OOINLINE JSContext * OOJSAcquireContext(void)
OOINLINE void OOJSRelinquishContext(JSContext *context)

◆ scanForNearestShipNotHavingAnyRole:

- (void) scanForNearestShipNotHavingAnyRole: (NSString *)  scanRoles

Definition at line 1 of file ShipEntityAI.m.

2328 :(NSString *)scanRoles
2329{
2330 NSSet *set = [NSSet setWithArray:ScanTokensFromString(scanRoles)];
2331 [self scanForNearestShipWithNegatedPredicate:HasRoleInSetPredicate parameter:set];
2332}

◆ scanForNearestShipNotHavingRole:

- (void) scanForNearestShipNotHavingRole: (NSString *)  scanRole

Definition at line 1 of file ShipEntityAI.m.

2315 :(NSString *)scanRole
2316{
2317 [self scanForNearestShipWithNegatedPredicate:HasRolePredicate parameter:scanRole];
2318}

◆ scanForNearestShipWithAnyPrimaryRole:

- (void) scanForNearestShipWithAnyPrimaryRole: (NSString *)  scanRoles

Definition at line 1 of file ShipEntityAI.m.

2288 :(NSString *)scanRoles
2289{
2290 NSSet *set = [NSSet setWithArray:ScanTokensFromString(scanRoles)];
2291 [self scanForNearestShipWithPredicate:HasPrimaryRoleInSetPredicate parameter:set];
2292}

◆ scanForNearestShipWithoutAnyPrimaryRole:

- (void) scanForNearestShipWithoutAnyPrimaryRole: (NSString *)  scanRoles

Definition at line 1 of file ShipEntityAI.m.

2321 :(NSString *)scanRoles
2322{
2323 NSSet *set = [NSSet setWithArray:ScanTokensFromString(scanRoles)];
2324 [self scanForNearestShipWithNegatedPredicate:HasPrimaryRoleInSetPredicate parameter:set];
2325}

◆ scanForNearestShipWithoutPrimaryRole:

- (void) scanForNearestShipWithoutPrimaryRole: (NSString *)  scanRole

Definition at line 1 of file ShipEntityAI.m.

2309 :(NSString *)scanRole
2310{
2311 [self scanForNearestShipWithNegatedPredicate:HasPrimaryRolePredicate parameter:scanRole];
2312}

◆ scanForNearestShipWithoutScanClass:

- (void) scanForNearestShipWithoutScanClass: (NSString *)  scanScanClass

Definition at line 1 of file ShipEntityAI.m.

2335 :(NSString *)scanScanClass
2336{
2337 NSNumber *parameter = [NSNumber numberWithInt:OOScanClassFromString(scanScanClass)];
2338 [self scanForNearestShipWithNegatedPredicate:HasScanClassPredicate parameter:parameter];
2339}

◆ scanForNearestShipWithPrimaryRole:

- (void) scanForNearestShipWithPrimaryRole: (NSString *)  scanRole

Definition at line 1 of file ShipEntityAI.m.

2276 :(NSString *)scanRole
2277{
2278 [self scanForNearestShipWithPredicate:HasPrimaryRolePredicate parameter:scanRole];
2279}

◆ scanForNearestShipWithScanClass:

- (void) scanForNearestShipWithScanClass: (NSString *)  scanScanClass

Definition at line 1 of file ShipEntityAI.m.

2302 :(NSString *)scanScanClass
2303{
2304 NSNumber *parameter = [NSNumber numberWithInt:OOScanClassFromString(scanScanClass)];
2305 [self scanForNearestShipWithPredicate:HasScanClassPredicate parameter:parameter];
2306}

◆ scanForNonThargoid

- (void) scanForNonThargoid

Definition at line 1 of file ShipEntityAI.m.

1692{
1693 /*-- Locates all the non thargoid ships in range and chooses the nearest --*/
1694 DESTROY(_foundTarget);
1695
1696 [self checkScanner];
1697 unsigned i;
1698 GLfloat found_d2 = scannerRange * scannerRange;
1699 for (i = 0; i < n_scanned_ships ; i++)
1700 {
1701 ShipEntity *thing = scanned_ships[i];
1702 GLfloat d2 = distance2_scanned_ships[i];
1703 if (([thing scanClass] != CLASS_CARGO) && ([thing status] != STATUS_DOCKED) && ![thing isThargoid] && ![thing isCloaked] && (d2 < found_d2))
1704 {
1705 [self setFoundTarget:thing];
1706 if ([thing isPlayer]) d2 = 0.0; // prefer the player
1707 found_d2 = d2;
1708 }
1709 }
1710
1711 [self checkFoundTarget];
1712}

◆ scanForOffenders

- (void) scanForOffenders

Definition at line 1 of file ShipEntityAI.m.

1558{
1559 /*-- Locates all the ships in range and compares their legal status or bounty against ranrot_rand() & 255 - chooses the worst offender --*/
1560 NSDictionary *systeminfo = [UNIVERSE currentSystemData];
1561 float gov_factor = 0.4 * [(NSNumber *)[systeminfo objectForKey:KEY_GOVERNMENT] intValue]; // 0 .. 7 (0 anarchic .. 7 most stable) --> [0.0, 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 2.8]
1562 //
1563 if ([UNIVERSE sun] == nil)
1564 gov_factor = 1.0;
1565 //
1566 DESTROY(_foundTarget);
1567
1568 // find the worst offender on the scanner
1569 //
1570 [self checkScanner];
1571 unsigned i;
1572 float worst_legal_factor = 0;
1573 GLfloat found_d2 = scannerRange * scannerRange;
1574 OOShipGroup *group = [self group];
1575 for (i = 0; i < n_scanned_ships ; i++)
1576 {
1577 ShipEntity *ship = scanned_ships[i];
1578 if ((ship->scanClass != CLASS_CARGO)&&([ship status] != STATUS_DEAD)&&([ship status] != STATUS_DOCKED)&& ![ship isCloaked])
1579 {
1580 GLfloat d2 = distance2_scanned_ships[i];
1581 float legal_factor = [ship legalStatus] * gov_factor;
1582 int random_factor = ranrot_rand() & 255; // 25% chance of spotting a fugitive in 15s
1583 if ((d2 < found_d2)&&(random_factor < legal_factor)&&(legal_factor > worst_legal_factor))
1584 {
1585 if (group == nil || group != [ship group]) // fellows with bounty can't be offenders
1586 {
1587 [self setFoundTarget:ship];
1588 worst_legal_factor = legal_factor;
1589 }
1590 }
1591 }
1592 }
1593
1594 [self checkFoundTarget];
1595}

◆ scanForRandomLoot

- (void) scanForRandomLoot

Definition at line 1 of file ShipEntityAI.m.

1105{
1106 /*-- Locates the all debris in range and chooses a piece at random from the first sixteen found --*/
1107 if (![self isStation] && ![self hasCargoScoop])
1108 {
1109 [shipAI message:@"NOTHING_FOUND"]; //can't collect loot if you have no scoop!
1110 return;
1111 }
1112 //
1113 [self checkScanner];
1114 //
1115 ShipEntity* thing_uids_found[16];
1116 unsigned things_found = 0;
1117 DESTROY(_foundTarget);
1118 unsigned i;
1119 for (i = 0; (i < n_scanned_ships)&&(things_found < 16) ; i++)
1120 {
1121 ShipEntity *other = scanned_ships[i];
1122 if ([other scanClass] == CLASS_CARGO && [other cargoType] != CARGO_NOT_CARGO && [other status] != STATUS_BEING_SCOOPED)
1123 {
1124 thing_uids_found[things_found++] = other;
1125 }
1126 }
1127
1128 if (things_found != 0)
1129 {
1130 [self setFoundTarget:thing_uids_found[ranrot_rand() % things_found]];
1131 [shipAI message:@"TARGET_FOUND"];
1132 }
1133 else
1134 [shipAI message:@"NOTHING_FOUND"];
1135}

◆ scanForRandomMerchantman

- (void) scanForRandomMerchantman

Definition at line 1 of file ShipEntityAI.m.

1025{
1026 unsigned n_found, i;
1027
1028 //-- Locates one of the merchantman in range.
1029 [self checkScannerIgnoringUnpowered];
1030 ShipEntity* ids_found[n_scanned_ships];
1031
1032 n_found = 0;
1033 DESTROY(_foundTarget);
1034 for (i = 0; i < n_scanned_ships ; i++)
1035 {
1036 ShipEntity *ship = scanned_ships[i];
1037 if (([ship status] != STATUS_DEAD) && ([ship status] != STATUS_DOCKED) && [ship isPirateVictim] && ![ship isCloaked])
1038 ids_found[n_found++] = ship;
1039 }
1040 if (n_found == 0)
1041 {
1042 [shipAI message:@"NOTHING_FOUND"];
1043 }
1044 else
1045 {
1046 i = ranrot_rand() % n_found; // pick a number from 0 -> (n_found - 1)
1047 [self setFoundTarget:ids_found[i]];
1048 [shipAI message:@"TARGET_FOUND"];
1049 }
1050}

◆ scanForRocks

- (void) scanForRocks

Definition at line 1 of file ShipEntityAI.m.

2161{
2162 /*-- Locates the all boulders and asteroids in range and selects nearest --*/
2163
2164 // find boulders then asteroids within range
2165 //
2166 DESTROY(_foundTarget);
2167 [self checkScanner];
2168 unsigned i;
2169 GLfloat found_d2 = scannerRange * scannerRange;
2170 for (i = 0; i < n_scanned_ships; i++)
2171 {
2172 ShipEntity *thing = scanned_ships[i];
2173 if ([thing isBoulder])
2174 {
2175 GLfloat d2 = distance2_scanned_ships[i];
2176 if (d2 < found_d2)
2177 {
2178 [self setFoundTarget:thing];
2179 found_d2 = d2;
2180 }
2181 }
2182 }
2183 if ([self foundTarget] == nil)
2184 {
2185 for (i = 0; i < n_scanned_ships; i++)
2186 {
2187 ShipEntity *thing = scanned_ships[i];
2188 if ([thing hasRole:@"asteroid"])
2189 {
2190 GLfloat d2 = distance2_scanned_ships[i];
2191 if (d2 < found_d2)
2192 {
2193 [self setFoundTarget:thing];
2194 found_d2 = d2;
2195 }
2196 }
2197 }
2198 }
2199
2200 [self checkFoundTarget];
2201}

◆ scanForThargoid

- (void) scanForThargoid

Definition at line 1 of file ShipEntityAI.m.

1686{
1687 return [self scanForNearestShipWithPrimaryRole:@"thargoid"];
1688}

◆ scriptActionOnTarget:

- (void) scriptActionOnTarget: (NSString *)  action

Definition at line 1 of file ShipEntityAI.m.

2560 :(NSString *)action
2561{
2562 PlayerEntity *player = PLAYER;
2563 ShipEntity *targEnt = [self primaryTarget];
2564 ShipEntity *oldTarget = nil;
2565
2566#ifndef NDEBUG
2567 static BOOL deprecationWarning = NO;
2568
2569 if (!deprecationWarning)
2570 {
2571 deprecationWarning = YES;
2572 OOLog(@"script.deprecated.scriptActionOnTarget", @"----- WARNING in AI %@: the AI method scriptActionOnTarget: is deprecated and should not be used. It is slow and has unpredictable side effects. The recommended alternative is to use sendScriptMessage: to call a function in a ship's JavaScript ship script instead. scriptActionOnTarget: should not be used at all from scripts. An alternative is safeScriptActionOnTarget:, which is similar to scriptActionOnTarget: but has less side effects.", [AI currentlyRunningAIDescription]);
2573 }
2574 else
2575 {
2576 OOLog(@"script.deprecated.scriptActionOnTarget.repeat", @"----- WARNING in AI %@: the AI method scriptActionOnTarget: is deprecated and should not be used.", [AI currentlyRunningAIDescription]);
2577 }
2578#endif
2579
2580 if ([targEnt isShip])
2581 {
2582 oldTarget = [player scriptTarget];
2583 [player setScriptTarget:(ShipEntity*)targEnt];
2584 [player runUnsanitizedScriptActions:[NSArray arrayWithObject:action]
2586 withContextName:[NSString stringWithFormat:@"<AI \"%@\" state %@ - scriptActionOnTarget:>", [[self getAI] name], [[self getAI] state]]
2587 forTarget:targEnt];
2588 [player checkScript]; // react immediately to any changes this makes
2589 [player setScriptTarget:oldTarget];
2590 }
2591}
Definition AI.h:38

◆ sendScriptMessage:

- (void) sendScriptMessage: (NSString *)  message

Definition at line 1 of file ShipEntityAI.m.

2614 :(NSString *)message
2615{
2616 NSArray *components = ScanTokensFromString(message);
2617
2618 if ([components count] == 1)
2619 {
2620 [self doScriptEvent:OOJSIDFromString(message)];
2621 }
2622 else
2623 {
2624 NSString *function = [components objectAtIndex:0];
2625 components = [components subarrayWithRange:NSMakeRange(1, [components count] - 1)];
2626 [self doScriptEvent:OOJSIDFromString(function) withArgument:components];
2627 }
2628}

◆ sendTargetCommsMessage:

- (void) sendTargetCommsMessage: (NSString *)  message

Definition at line 1 of file ShipEntityAI.m.

2078 :(NSString*) message
2079{
2080 ShipEntity *ship = [self primaryTarget];
2081 if ((ship == nil) || ([ship status] == STATUS_DEAD) || ([ship status] == STATUS_DOCKED))
2082 {
2083 [self noteLostTarget];
2084 return;
2085 }
2086 [self sendExpandedMessage:message toShip:[self primaryTarget]];
2087}

◆ setCoordinates:

- (void) setCoordinates: (NSString *)  system_x_y_z

Definition at line 1 of file ShipEntityAI.m.

2440 :(NSString *)system_x_y_z
2441{
2442 NSArray* tokens = ScanTokensFromString(system_x_y_z);
2443 NSString* systemString = nil;
2444 NSString* xString = nil;
2445 NSString* yString = nil;
2446 NSString* zString = nil;
2447
2448 if ([tokens count] != 4)
2449 {
2450 OOLog(@"ai.syntax.setCoordinates", @"***** ERROR: cannot setCoordinates: '%@'.",system_x_y_z);
2451 return;
2452 }
2453
2454 systemString = (NSString *)[tokens objectAtIndex:0];
2455 xString = (NSString *)[tokens objectAtIndex:1];
2456 if ([xString hasPrefix:@"rand:"])
2457 xString = [NSString stringWithFormat:@"%.3f", bellf([(NSString*)[[xString componentsSeparatedByString:@":"] objectAtIndex:1] intValue])];
2458 yString = (NSString *)[tokens objectAtIndex:2];
2459 if ([yString hasPrefix:@"rand:"])
2460 yString = [NSString stringWithFormat:@"%.3f", bellf([(NSString*)[[yString componentsSeparatedByString:@":"] objectAtIndex:1] intValue])];
2461 zString = (NSString *)[tokens objectAtIndex:3];
2462 if ([zString hasPrefix:@"rand:"])
2463 zString = [NSString stringWithFormat:@"%.3f", bellf([(NSString*)[[zString componentsSeparatedByString:@":"] objectAtIndex:1] intValue])];
2464
2465 HPVector posn = make_HPvector([xString floatValue], [yString floatValue], [zString floatValue]);
2466 GLfloat scalar = 1.0;
2467
2468 coordinates = [UNIVERSE coordinatesForPosition:posn withCoordinateSystem:systemString returningScalar:&scalar];
2469
2470 [shipAI message:@"APPROACH_COORDINATES"];
2471}
float bellf(int n)

◆ setCoordinatesFromPosition

- (void) setCoordinatesFromPosition

Definition at line 1 of file ShipEntityAI.m.

1222{
1223 coordinates = position;
1224}

◆ setCourseToPlanet

- (void) setCourseToPlanet

Definition at line 1 of file ShipEntityAI.m.

1306{
1307 /*- selects the nearest planet it can find -*/
1308 OOPlanetEntity *the_planet = [self findNearestPlanetExcludingMoons];
1309 if (the_planet)
1310 {
1311 double variation = (aegis_status == AEGIS_NONE ? 0.5 : 0.2); // more random deviation when far from planet.
1312 HPVector p_pos = the_planet->position;
1313 double p_cr = the_planet->collision_radius; // the surface
1314 HPVector p1 = HPvector_between(p_pos, position);
1315 p1 = HPvector_normal(p1); // vector towards ship
1316 p1.x += variation * (randf() - variation);
1317 p1.y += variation * (randf() - variation);
1318 p1.z += variation * (randf() - variation);
1319 p1 = HPvector_normal(p1);
1320 _destination = HPvector_add(p_pos, HPvector_multiply_scalar(p1, p_cr)); // on surface
1321 desired_range = collision_radius + 100.0; // +100m from the destination
1322 }
1323 else
1324 {
1325 [shipAI message:@"NO_PLANET_FOUND"];
1326 }
1327}
GLfloat collision_radius
Definition Entity.h:111

◆ setCourseToWitchpoint

- (void) setCourseToWitchpoint

Definition at line 1 of file ShipEntityAI.m.

1599{
1600 if (UNIVERSE)
1601 {
1602 _destination = [UNIVERSE getWitchspaceExitPosition];
1603 desired_range = 10000.0; // 10km away
1604 }
1605}

◆ setDesiredRangeForWaypoint

- (void) setDesiredRangeForWaypoint

Definition at line 1 of file ShipEntityAI.m.

913{
914 desired_range = fmax(maxFlightSpeed / max_flight_pitch / 6, 50.0); // some ships need a longer range to reach a waypoint.
915}

◆ setDesiredRangeTo:

- (void) setDesiredRangeTo: (NSString *)  rangeString

Definition at line 1 of file ShipEntityAI.m.

907 :(NSString *)rangeString
908{
909 desired_range = [rangeString doubleValue];
910}

◆ setDestinationFromCoordinates

- (void) setDestinationFromCoordinates

Definition at line 1 of file ShipEntityAI.m.

1216{
1217 _destination = coordinates;
1218}

◆ setDestinationToCurrentLocation

- (void) setDestinationToCurrentLocation

Definition at line 1 of file ShipEntityAI.m.

893{
894 // randomly add a .5m variance
895 _destination = HPvector_add(position, OOHPVectorRandomSpatial(0.5));
896}
HPVector OOHPVectorRandomSpatial(OOHPScalar maxLength)
Definition OOHPVector.m:82

◆ setDestinationToDockingAbort

- (void) setDestinationToDockingAbort

Definition at line 1 of file ShipEntityAI.m.

2205{
2206 Entity *the_target = [self targetStation];
2207 if (!the_target) {
2208 /* Probably the player trying to dock with docking computer
2209 * from out of scanner range */
2210 the_target = [UNIVERSE station];
2211 }
2212 double bo_distance = 8000; // 8km back off
2213 HPVector v0 = position;
2214 HPVector d0 = (the_target) ? the_target->position : kZeroHPVector;
2215 v0.x += (randf() - 0.5)*collision_radius; v0.y += (randf() - 0.5)*collision_radius; v0.z += (randf() - 0.5)*collision_radius;
2216 v0.x -= d0.x; v0.y -= d0.y; v0.z -= d0.z;
2217 v0 = HPvector_normal_or_fallback(v0, make_HPvector(0, 0, -1));
2218
2219 v0.x *= bo_distance; v0.y *= bo_distance; v0.z *= bo_distance;
2220 v0.x += d0.x; v0.y += d0.y; v0.z += d0.z;
2221 coordinates = v0;
2222 _destination = v0;
2223}
const HPVector kZeroHPVector
Definition OOHPVector.m:28
float y
float x

◆ setDestinationToJinkPosition

- (void) setDestinationToJinkPosition
implementation

Definition at line 1 of file ShipEntityAI.m.

900{
901 Vector front = vector_multiply_scalar([self forwardVector], flightSpeed / max_flight_pitch * 2);
902 _destination = HPvector_add(position, vectorToHPVector(vector_add(front, OOVectorRandomSpatial(100))));
903 pitching_over = YES; // don't complete roll first, but immediately start with pitching.
904}
Vector OOVectorRandomSpatial(OOScalar maxLength)
Definition OOVector.m:99

◆ setDestinationToStationBeacon

- (void) setDestinationToStationBeacon

Definition at line 1 of file ShipEntityAI.m.

1615{
1616 if ([UNIVERSE station])
1617 {
1618 _destination = [[UNIVERSE station] beaconPosition];
1619 }
1620}

◆ setDestinationToTarget

- (void) setDestinationToTarget

Definition at line 1 of file ShipEntityAI.m.

1420{
1421 Entity *the_target = [self primaryTarget];
1422 if (the_target)
1423 _destination = the_target->position;
1424}

◆ setDestinationToWitchpoint

- (void) setDestinationToWitchpoint

Definition at line 1 of file ShipEntityAI.m.

1609{
1610 _destination = [UNIVERSE getWitchspaceExitPosition];
1611}

◆ setDestinationWithinTarget

- (void) setDestinationWithinTarget

Definition at line 1 of file ShipEntityAI.m.

1428{
1429 Entity *the_target = [self primaryTarget];
1430 if (the_target)
1431 {
1432 HPVector pos = the_target->position;
1433 Quaternion q; quaternion_set_random(&q);
1434 Vector v = vector_forward_from_quaternion(q);
1435 GLfloat d = (randf() - randf()) * the_target->collision_radius;
1436 _destination = make_HPvector(pos.x + d * v.x, pos.y + d * v.y, pos.z + d * v.z);
1437 }
1438}
Vector vector_forward_from_quaternion(Quaternion quat)
void quaternion_set_random(Quaternion *quat)

◆ setPlanetPatrolCoordinates

- (void) setPlanetPatrolCoordinates

Definition at line 1 of file ShipEntityAI.m.

1931{
1932 // check we've arrived near the last given coordinates
1933 HPVector r_pos = HPvector_subtract(position, coordinates);
1934 if (HPmagnitude2(r_pos) < 1000000 || patrol_counter == 0)
1935 {
1936 Entity *the_sun = [UNIVERSE sun];
1937 ShipEntity *the_station = [[self group] leader];
1938 if(!the_station || ![the_station isStation]) the_station = [UNIVERSE station];
1939 if ((!the_sun)||(!the_station))
1940 return;
1941 HPVector sun_pos = the_sun->position;
1942 HPVector stn_pos = the_station->position;
1943 HPVector sun_dir = HPvector_subtract(sun_pos,stn_pos);
1944 Vector vSun = make_vector(0, 0, 1);
1945 if (sun_dir.x||sun_dir.y||sun_dir.z)
1946 vSun = HPVectorToVector(HPvector_normal(sun_dir));
1947 Vector v0 = [the_station forwardVector];
1948 Vector v1 = cross_product(v0, vSun);
1949 Vector v2 = cross_product(v0, v1);
1950 switch (patrol_counter)
1951 {
1952 case 0: // first go to 5km ahead of the station
1953 coordinates = make_HPvector(stn_pos.x + 5000 * v0.x, stn_pos.y + 5000 * v0.y, stn_pos.z + 5000 * v0.z);
1954 desired_range = 250.0;
1955 break;
1956 case 1: // go to 25km N of the station
1957 coordinates = make_HPvector(stn_pos.x + 25000 * v1.x, stn_pos.y + 25000 * v1.y, stn_pos.z + 25000 * v1.z);
1958 desired_range = 250.0;
1959 break;
1960 case 2: // go to 25km E of the station
1961 coordinates = make_HPvector(stn_pos.x + 25000 * v2.x, stn_pos.y + 25000 * v2.y, stn_pos.z + 25000 * v2.z);
1962 desired_range = 250.0;
1963 break;
1964 case 3: // go to 25km S of the station
1965 coordinates = make_HPvector(stn_pos.x - 25000 * v1.x, stn_pos.y - 25000 * v1.y, stn_pos.z - 25000 * v1.z);
1966 desired_range = 250.0;
1967 break;
1968 case 4: // go to 25km W of the station
1969 coordinates = make_HPvector(stn_pos.x - 25000 * v2.x, stn_pos.y - 25000 * v2.y, stn_pos.z - 25000 * v2.z);
1970 desired_range = 250.0;
1971 break;
1972 default: // We should never come here
1973 coordinates = make_HPvector(stn_pos.x + 5000 * v0.x, stn_pos.y + 5000 * v0.y, stn_pos.z + 5000 * v0.z);
1974 desired_range = 250.0;
1975 break;
1976 }
1977 patrol_counter++;
1978 if (patrol_counter > 4)
1979 {
1980 if (randf() < .25)
1981 {
1982 // consider docking
1983 [self setTargetStation:the_station];
1984 [self setAITo:@"dockingAI.plist"];
1985 return;
1986 }
1987 else
1988 {
1989 // go around again
1990 patrol_counter = 1;
1991 }
1992 }
1993 }
1994 [shipAI message:@"APPROACH_COORDINATES"];
1995}
Vector forwardVector()

◆ setRacepointsFromTarget

- (void) setRacepointsFromTarget

Definition at line 1 of file ShipEntityAI.m.

2704{
2705 // two point - one at z - cr one at z + cr
2706 ShipEntity *ship = [self primaryTarget];
2707 if (ship == nil)
2708 {
2709 [shipAI message:@"NOTHING_FOUND"];
2710 return;
2711 }
2712 Vector k = ship->v_forward;
2713 GLfloat c = ship->collision_radius;
2714 HPVector o = ship->position;
2715 navpoints[0] = make_HPvector(o.x - c * k.x, o.y - c * k.y, o.z - c * k.z);
2716 navpoints[1] = make_HPvector(o.x + c * k.x, o.y + c * k.y, o.z + c * k.z);
2717 navpoints[2] = make_HPvector(o.x + 2.0 * c * k.x, o.y + 2.0 * c * k.y, o.z + 2.0 * c * k.z);
2718 number_of_navpoints = 2;
2719 next_navpoint_index = 0;
2720 _destination = navpoints[0];
2721 [shipAI message:@"RACEPOINTS_SET"];
2722}
Vector v_forward
Definition ShipEntity.h:200

◆ setSpeedFactorTo:

- (void) setSpeedFactorTo: (NSString *)  speedString

Definition at line 1 of file ShipEntityAI.m.

923 :(NSString *)speedString
924{
925 desired_speed = maxFlightSpeed * [speedString doubleValue];
926}

◆ setSpeedTo:

- (void) setSpeedTo: (NSString *)  speedString

Definition at line 1 of file ShipEntityAI.m.

917 :(NSString *)speedString
918{
919 desired_speed = [speedString doubleValue];
920}

◆ setSpeedToCruiseSpeed

- (void) setSpeedToCruiseSpeed

Definition at line 1 of file ShipEntityAI.m.

929{
930 desired_speed = cruiseSpeed;
931}

◆ setStateTo:

- (void) setStateTo: (NSString *)  state

Definition at line 1 of file ShipEntityAI.m.

842 :(NSString *)state
843{
844 [[self getAI] setState:state];
845}

◆ setSunSkimEndCoordinates

- (void) setSunSkimEndCoordinates

Definition at line 1 of file ShipEntityAI.m.

2021{
2022 if ([UNIVERSE sun] == nil)
2023 {
2024 [shipAI message:@"NO_SUN_FOUND"];
2025 return;
2026 }
2027
2028 coordinates = [UNIVERSE getSunSkimEndPositionForShip:self];
2029 [shipAI message:@"APPROACH_COORDINATES"];
2030}

◆ setSunSkimExitCoordinates

- (void) setSunSkimExitCoordinates

Definition at line 1 of file ShipEntityAI.m.

2034{
2035 Entity *the_sun = [UNIVERSE sun];
2036 if (the_sun == nil) return;
2037 HPVector v1 = [UNIVERSE getSunSkimEndPositionForShip:self];
2038 HPVector vs = the_sun->position;
2039 HPVector vout = HPvector_subtract(v1,vs);
2040 if (vout.x||vout.y||vout.z)
2041 vout = HPvector_normal(vout);
2042 else
2043 vout.z = 1.0;
2044 v1.x += 10000 * vout.x; v1.y += 10000 * vout.y; v1.z += 10000 * vout.z;
2045 coordinates = v1;
2046 [shipAI message:@"APPROACH_COORDINATES"];
2047}

◆ setSunSkimStartCoordinates

- (void) setSunSkimStartCoordinates

Definition at line 1 of file ShipEntityAI.m.

1999{
2000 if ([UNIVERSE sun] == nil)
2001 {
2002 [shipAI message:@"NO_SUN_FOUND"];
2003 return;
2004 }
2005
2006 HPVector v0 = [UNIVERSE getSunSkimStartPositionForShip:self];
2007
2008 if (!HPvector_equal(v0, kZeroHPVector))
2009 {
2010 coordinates = v0;
2011 [shipAI message:@"APPROACH_COORDINATES"];
2012 }
2013 else
2014 {
2015 [shipAI message:@"WAIT_FOR_SUN"];
2016 }
2017}

◆ setTakeOffFromPlanet

- (void) setTakeOffFromPlanet

Definition at line 1 of file ShipEntityAI.m.

1331{
1332 /*- selects the nearest planet it can find -*/
1333 OOPlanetEntity *the_planet = [self findNearestPlanet];
1334 if (the_planet)
1335 {
1336 _destination = HPvector_add([the_planet position], HPvector_multiply_scalar(
1337 HPvector_normal(HPvector_subtract([the_planet position],position)),-10000.0-the_planet->collision_radius));// 10km straight up
1338 desired_range = 50.0;
1339 }
1340 else
1341 {
1342 OOLog(@"ai.setTakeOffFromPlanet.noPlanet", @"%@", @"***** Error. Planet not found during take off!");
1343 }
1344}

◆ setTargetToFoundTarget

- (void) setTargetToFoundTarget

Definition at line 1 of file ShipEntityAI.m.

1139{
1140 if ([self foundTarget] != nil)
1141 {
1142 [self addTarget:[self foundTarget]];
1143 }
1144 else
1145 {
1146 [shipAI message:@"TARGET_LOST"]; // to prevent the ship going for a wrong, previous target. Should not be a reactToMessage.
1147 }
1148}

◆ setTargetToLastStation

- (void) setTargetToLastStation

Definition at line 1 of file ShipEntityAI.m.

2537{
2538 Entity *station = [self targetStation];
2539
2540 if (station != nil && [station isStation])
2541 {
2542 [self addTarget:station];
2543 }
2544 else
2545 {
2546 [shipAI message:@"NO_STATION_FOUND"];
2547 [self setTargetStation:nil];
2548 }
2549
2550}

◆ setTargetToPrimaryAggressor

- (void) setTargetToPrimaryAggressor

Definition at line 1 of file ShipEntityAI.m.

940{
941 Entity *primeAggressor = [self primaryAggressor];
942 if (!primeAggressor)
943 return;
944 if ([self primaryTarget] == primeAggressor)
945 return;
946
947 // a more considered approach here:
948 // if we're already busy attacking a target we don't necessarily want to break off
949 //
950 if ([self hasHostileTarget] && randf() < 0.75) // if I'm attacking, ignore 75% of new aggressor's attacks
951 {
952 // but add them as a secondary target anyway
953 [self addDefenseTarget:(ShipEntity*)primeAggressor];
954 return;
955 }
956 // react only if the primary aggressor is not a friendly ship, else ignore it
957 if ([primeAggressor isShip] && ![(ShipEntity *)primeAggressor isFriendlyTo:self])
958 {
959 // inform our old target of our new target
960 //
961 Entity *primeTarget = [self primaryTarget];
962 if ((primeTarget)&&(primeTarget->isShip))
963 {
964 ShipEntity *currentShip = [self primaryTarget];
965 [[currentShip getAI] message:[NSString stringWithFormat:@"%@ %d %d", AIMS_AGGRESSOR_SWITCHED_TARGET, universalID, [[self primaryAggressor] universalID]]];
966 [currentShip doScriptEvent:OOJSID("shipAttackerDistracted") withArgument:[self primaryAggressor]];
967 }
968
969 // okay, so let's now target the aggressor
970 [self addTarget:[self primaryAggressor]];
971 }
972}
void message:(NSString *ms)
Definition AI.m:600
unsigned isShip
Definition Entity.h:91

◆ setTargetToRandomStation

- (void) setTargetToRandomStation

Definition at line 1 of file ShipEntityAI.m.

2484{
2485 /*- selects the nearest station it can find -*/
2486 int ent_count = UNIVERSE->n_entities;
2487 Entity **uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
2488 Entity *my_entities[ent_count];
2489 StationEntity *station = nil, *my_station = nil;
2490 double maxRange2 = desired_range * desired_range;
2491 int i;
2492 int station_count = 0;
2493
2494 for (i = 0; i < ent_count; i++)
2495 {
2496 // find stations within range but exclude carriers.
2497 if (uni_entities[i]->isStation)
2498 {
2499 my_station = (StationEntity*)uni_entities[i];
2500 if ([my_station maxFlightSpeed] == 0 && [my_station hasNPCTraffic] && HPdistance2(position, [my_station position]) < maxRange2)
2501 {
2502 my_entities[station_count++] = [uni_entities[i] retain]; // retained
2503 }
2504 }
2505 }
2506
2507 if (station_count != 0)
2508 {
2509 // select a random station
2510 station = (StationEntity *)my_entities[ranrot_rand() % station_count];
2511 // if more than one candidate do not select main station
2512 if (station == [UNIVERSE station] && station_count > 1)
2513 {
2514 while (station == [UNIVERSE station])
2515 {
2516 station = (StationEntity *)my_entities[ranrot_rand() % station_count];
2517 }
2518 }
2519 }
2520
2521 for (i = 0; i < station_count; i++)
2522 [my_entities[i] release]; // released
2523 //
2524 if (station)
2525 {
2526 [self addTarget:station];
2527 [self setTargetStation:station];
2528 [shipAI message:@"STATION_FOUND"];
2529 }
2530 else
2531 {
2532 [shipAI message:@"NO_STATION_IN_RANGE"];
2533 }
2534}

◆ setThrustFactorTo:

- (void) setThrustFactorTo: (NSString *)  thrustFactorString

Definition at line 1 of file ShipEntityAI.m.

933 :(NSString *)thrustFactorString
934{
935 thrust = OOClamp_0_1_f([thrustFactorString doubleValue]) * max_thrust;
936}

◆ storeTarget

- (void) storeTarget

Definition at line 1 of file ShipEntityAI.m.

2119{
2120 Entity *target = [self primaryTarget];
2121
2122 if (target)
2123 {
2124 [self setRememberedShip:target];
2125 }
2126 else
2127 {
2128 DESTROY(_rememberedShip);
2129 }
2130
2131}

◆ suggestEscort

- (void) suggestEscort

Definition at line 1 of file ShipEntityAI.m.

1826{
1827 ShipEntity *mother = [self primaryTarget];
1828 [self suggestEscortTo:mother];
1829}

◆ targetFirstBeaconWithCode:

- (void) targetFirstBeaconWithCode: (NSString *)  code

Definition at line 1 of file ShipEntityAI.m.

2653 :(NSString*) code
2654{
2655 NSArray *all_beacons = [UNIVERSE listBeaconsWithCode: code];
2656 if ([all_beacons count])
2657 {
2658 [self addTarget:(ShipEntity*)[all_beacons objectAtIndex:0]];
2659 [shipAI message:@"TARGET_FOUND"];
2660 }
2661 else
2662 [shipAI message:@"NOTHING_FOUND"];
2663}

◆ targetNextBeaconWithCode:

- (void) targetNextBeaconWithCode: (NSString *)  code

Definition at line 1 of file ShipEntityAI.m.

2666 :(NSString*) code
2667{
2668 NSArray *all_beacons = [UNIVERSE listBeaconsWithCode: code];
2669 ShipEntity *current_beacon = [self primaryTarget];
2670
2671 if ((!current_beacon)||(![current_beacon isBeacon]))
2672 {
2673 [shipAI message:@"NO_CURRENT_BEACON"];
2674 [shipAI message:@"NOTHING_FOUND"];
2675 return;
2676 }
2677
2678 // find the current beacon in the list..
2679 NSUInteger i = [all_beacons indexOfObject:current_beacon];
2680
2681 if (i == NSNotFound)
2682 {
2683 [shipAI message:@"NOTHING_FOUND"];
2684 return;
2685 }
2686
2687 i++; // next index
2688
2689 if (i < [all_beacons count])
2690 {
2691 // locate current target in list
2692 [self addTarget:(ShipEntity*)[all_beacons objectAtIndex:i]];
2693 [shipAI message:@"TARGET_FOUND"];
2694 }
2695 else
2696 {
2697 [shipAI message:@"LAST_BEACON"];
2698 [shipAI message:@"NOTHING_FOUND"];
2699 }
2700}
BOOL isBeacon()

◆ thargonCheckMother

- (void) thargonCheckMother

Definition at line 1 of file ShipEntityAI.m.

1716{
1717 ShipEntity *mother = [self owner];
1718 if (mother == nil && [self group]) mother = [[self group] leader];
1719
1720 double maxRange2 = scannerRange * scannerRange;
1721
1722 if (mother && mother != self && HPdistance2(mother->position, position) < maxRange2)
1723 {
1724 [shipAI message:@"TARGET_FOUND"]; // no need for scanning, we still have our mother.
1725 }
1726 else
1727 {
1728 // we lost the old mother, search for a new one
1729 [self scanForNearestShipHavingRole:@"thargoid-mothership"]; // the scan will send further AI messages.
1730 if ([self foundTarget] != nil)
1731 {
1732 mother = (ShipEntity*)[self foundTarget];
1733 [self setOwner:mother];
1734 if ([mother group] != [mother escortGroup]) // avoid adding thargon to an escort group.
1735 {
1736 [self setGroup:[mother group]];
1737 }
1738 };
1739 }
1740}
OOShipGroup * group()

◆ wormholeGroup

- (void) wormholeGroup

Definition at line 1 of file ShipEntityAI.m.

1642{
1643 ShipEntity *ship = nil;
1644 WormholeEntity *whole = nil;
1645
1646 whole = [self primaryTarget];
1647 if (![whole isWormhole]) return;
1648
1649 foreach (ship, [[self group] mutationSafeEnumerator])
1650 {
1651 [ship addTarget:whole];
1652 [ship reactToAIMessage:@"ENTER WORMHOLE" context:@"wormholeGroup"];
1653 [ship doScriptEvent:OOJSID("wormholeSuggested") withArgument:whole];
1654 }
1655}
void addTarget:(Entity *targetEntity)

The documentation for this category was generated from the following file: