Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
ShipEntity Class Reference

#include <ShipEntity.h>

+ Inheritance diagram for ShipEntity:
+ Collaboration diagram for ShipEntity:

Instance Methods

(void) - setStateMachine:
 
(void) - setAI:
 
(AI *) - getAI
 
(BOOL) - hasAutoAI
 
(BOOL) - hasNewAI
 
(void) - setShipScript:
 
(void) - removeScript
 
(OOScript *) - shipScript
 
(OOScript *) - shipAIScript
 
(OOTimeAbsolute- shipAIScriptWakeTime
 
(void) - setAIScriptWakeTime:
 
(double) - frustration
 
(void) - setLaunchDelay:
 
(void) - interpretAIMessage:
 
(GLfloat) - accuracy
 
(void) - setAccuracy:
 
(OOMesh *) - mesh
 
(void) - setMesh:
 
(BoundingBox) - totalBoundingBox
 
(Vector) - forwardVector
 
(Vector) - upVector
 
(Vector) - rightVector
 
(NSArray *) - subEntities
 
(NSUInteger) - subEntityCount
 
(BOOL) - hasSubEntity:
 
(NSEnumerator *) - subEntityEnumerator
 
(NSEnumerator *) - shipSubEntityEnumerator
 
(NSEnumerator *) - flasherEnumerator
 
(NSEnumerator *) - exhaustEnumerator
 
(ShipEntity *) - subEntityTakingDamage
 
(void) - setSubEntityTakingDamage:
 
(void) - clearSubEntities
 
(Quaternion) - subEntityRotationalVelocity
 
(void) - setSubEntityRotationalVelocity:
 
(NSString *) - serializeShipSubEntities
 
(void) - deserializeShipSubEntitiesFrom:
 
(NSUInteger) - maxShipSubEntities
 
(void) - setSubIdx:
 
(NSUInteger) - subIdx
 
(Octree *) - octree
 
(float) - volume
 
(GLfloat) - doesHitLine:v0:
 
(GLfloat) - doesHitLine:v0:v1:
 
(GLfloat) - doesHitLine:v0:withPosition:andIJK:i:j:
 
(BoundingBox) - findBoundingBoxRelativeToPosition:InVectors:i:j:
 
(HPVector) - absoluteTractorPosition
 
(void) - setIsBoulder:
 
(BOOL) - isBoulder
 
(BOOL) - isMinable
 
(BOOL) - countsAsKill
 
(void) - setUpEscorts
 
(void) - updateEscortFormation
 
(id) - initWithKey:definition:
 
(BOOL) - setUpFromDictionary:
 
(BOOL) - setUpShipFromDictionary:
 
(BOOL) - setUpSubEntities
 
(BOOL) - setUpOneStandardSubentity:asTurret:
 
(GLfloat) - frustumRadius
 
(NSString *) - shipDataKey
 
(NSString *) - shipDataKeyAutoRole
 
(void) - setShipDataKey:
 
(NSDictionary *) - shipInfoDictionary
 
(NSArray *) - getWeaponOffsetFrom:withKey:inMode:
 
(NSArray *) - aftWeaponOffset
 
(NSArray *) - forwardWeaponOffset
 
(NSArray *) - portWeaponOffset
 
(NSArray *) - starboardWeaponOffset
 
(BOOL) - hasAutoWeapons
 
(BOOL) - isFrangible
 
(BOOL) - suppressFlightNotifications
 
(void) - respondToAttackFrom:becauseOf:
 
(OOWeaponFacingSet- weaponFacings
 
(BOOL) - hasEquipmentItem:includeWeapons:whileLoading:
 
(BOOL) - hasEquipmentItem:
 
(NSUInteger) - countEquipmentItem:
 
(NSString *) - equipmentItemProviding:
 
(BOOL) - hasEquipmentItemProviding:
 
(BOOL) - hasAllEquipment:includeWeapons:whileLoading:
 
(BOOL) - hasAllEquipment:
 
(BOOL) - setWeaponMount:toWeapon:
 
(BOOL) - canAddEquipment:inContext:
 
(BOOL) - equipmentValidToAdd:inContext:
 
(BOOL) - equipmentValidToAdd:whileLoading:inContext:
 
(BOOL) - addEquipmentItem:inContext:
 
(BOOL) - addEquipmentItem:withValidation:inContext:
 
(BOOL) - hasHyperspaceMotor
 
(float) - hyperspaceSpinTime
 
(void) - setHyperspaceSpinTime:
 
(NSEnumerator *) - equipmentEnumerator
 
(NSUInteger) - equipmentCount
 
(void) - removeEquipmentItem:
 
(void) - removeAllEquipment
 
(OOEquipmentType *) - selectMissile
 
(OOCreditsQuantity- removeMissiles
 
(BOOL) - hasOneEquipmentItem:includeWeapons:whileLoading:
 
(BOOL) - hasOneEquipmentItem:includeMissiles:whileLoading:
 
(BOOL) - hasPrimaryWeapon:
 
(BOOL) - removeExternalStore:
 
(NSUInteger) - parcelCount
 
(NSUInteger) - passengerCount
 
(NSUInteger) - passengerCapacity
 
(NSUInteger) - missileCount
 
(NSUInteger) - missileCapacity
 
(NSUInteger) - extraCargo
 
(BOOL) - hasScoop
 
(BOOL) - hasFuelScoop
 
(BOOL) - hasCargoScoop
 
(BOOL) - hasECM
 
(BOOL) - hasCloakingDevice
 
(BOOL) - hasMilitaryScannerFilter
 
(BOOL) - hasMilitaryJammer
 
(BOOL) - hasExpandedCargoBay
 
(BOOL) - hasShieldBooster
 
(BOOL) - hasMilitaryShieldEnhancer
 
(BOOL) - hasHeatShield
 
(BOOL) - hasFuelInjection
 
(BOOL) - hasCascadeMine
 
(BOOL) - hasEscapePod
 
(BOOL) - hasDockingComputer
 
(BOOL) - hasGalacticHyperdrive
 
(float) - shieldBoostFactor
 
(float) - maxForwardShieldLevel
 
(float) - maxAftShieldLevel
 
(float) - shieldRechargeRate
 
(double) - maxHyperspaceDistance
 
(float) - afterburnerFactor
 
(float) - afterburnerRate
 
(void) - setAfterburnerFactor:
 
(void) - setAfterburnerRate:
 
(float) - maxThrust
 
(float) - thrust
 
(void) - setMaxThrust:
 
(void) - setMaxFlightPitch:
 
(void) - setMaxFlightSpeed:
 
(void) - setMaxFlightRoll:
 
(void) - setMaxFlightYaw:
 
(void) - setEnergyRechargeRate:
 
(void) - processBehaviour:
 
(void) - behaviour_stop_still:
 
(void) - behaviour_idle:
 
(void) - behaviour_tumble:
 
(void) - behaviour_tractored:
 
(void) - behaviour_track_target:
 
(void) - behaviour_intercept_target:
 
(void) - behaviour_attack_target:
 
(void) - behaviour_attack_slow_dogfight:
 
(void) - behaviour_evasive_action:
 
(void) - behaviour_attack_break_off_target:
 
(void) - behaviour_fly_to_target_six:
 
(void) - behaviour_attack_mining_target:
 
(void) - behaviour_attack_fly_to_target:
 
(void) - behaviour_attack_fly_from_target:
 
(void) - behaviour_running_defense:
 
(void) - behaviour_flee_target:
 
(void) - behaviour_attack_broadside:
 
(void) - behaviour_attack_broadside_left:
 
(void) - behaviour_attack_broadside_right:
 
(void) - behaviour_close_to_broadside_range:
 
(void) - behaviour_close_with_target:
 
(void) - behaviour_attack_broadside_target:leftside:
 
(void) - behaviour_attack_sniper:
 
(void) - behaviour_fly_range_from_destination:
 
(void) - behaviour_face_destination:
 
(void) - behaviour_land_on_planet:
 
(void) - behaviour_formation_form_up:
 
(void) - behaviour_fly_to_destination:
 
(void) - behaviour_fly_from_destination:
 
(void) - behaviour_avoid_collision:
 
(void) - behaviour_track_as_turret:
 
(void) - behaviour_fly_thru_navpoints:
 
(void) - behaviour_scripted_ai:
 
(float) - reactionTime
 
(void) - setReactionTime:
 
(HPVector) - calculateTargetPosition
 
(void) - startTrackingCurve
 
(void) - updateTrackingCurve
 
(void) - calculateTrackingCurve
 
(GLfloat *) - scannerDisplayColorForShip:otherShip:isHostile:flash:scannerDisplayColor1:scannerDisplayColor2:scannerDisplayColorH1:
 
(void) - setScannerDisplayColor1:
 
(void) - setScannerDisplayColor2:
 
(OOColor *) - scannerDisplayColor1
 
(OOColor *) - scannerDisplayColor2
 
(void) - setScannerDisplayColorHostile1:
 
(void) - setScannerDisplayColorHostile2:
 
(OOColor *) - scannerDisplayColorHostile1
 
(OOColor *) - scannerDisplayColorHostile2
 
(BOOL) - isCloaked
 
(void) - setCloaked:
 
(BOOL) - hasAutoCloak
 
(void) - setAutoCloak:
 
(void) - applyThrust:
 
(void) - applyAttitudeChanges:
 
(void) - avoidCollision
 
(void) - resumePostProximityAlert
 
(double) - messageTime
 
(void) - setMessageTime:
 
(OOShipGroup *) - group
 
(void) - setGroup:
 
(OOShipGroup *) - escortGroup
 
(void) - setEscortGroup:
 
(OOShipGroup *) - stationGroup
 
(BOOL) - hasEscorts
 
(NSEnumerator *) - escortEnumerator
 
(NSArray *) - escortArray
 
(uint8_t) - escortCount
 
(uint8_t) - pendingEscortCount
 
(void) - setPendingEscortCount:
 
(uint8_t) - maxEscortCount
 
(void) - setMaxEscortCount:
 
(NSUInteger) - turretCount
 
(NSString *) - name
 
(NSString *) - shipUniqueName
 
(NSString *) - shipClassName
 
(NSString *) - displayName
 
(NSString *) - scanDescription
 
(NSString *) - scanDescriptionForScripting
 
(void) - setName:
 
(void) - setShipUniqueName:
 
(void) - setShipClassName:
 
(void) - setDisplayName:
 
(void) - setScanDescription:
 
(NSString *) - identFromShip:
 
(BOOL) - hasRole:
 
(OORoleSet *) - roleSet
 
(void) - addRole:
 
(void) - addRole:withProbability:
 
(void) - removeRole:
 
(NSString *) - primaryRole
 
(void) - setPrimaryRole:
 
(BOOL) - hasPrimaryRole:
 
(BOOL) - isPolice
 
(BOOL) - isThargoid
 
(BOOL) - isTrader
 
(BOOL) - isPirate
 
(BOOL) - isMissile
 
(BOOL) - isMine
 
(BOOL) - isWeapon
 
(BOOL) - isEscort
 
(BOOL) - isShuttle
 
(BOOL) - isTurret
 
(BOOL) - isPirateVictim
 
(BOOL) - isExplicitlyUnpiloted
 
(BOOL) - isUnpiloted
 
(OOAlertCondition- alertCondition
 
(OOAlertCondition- realAlertCondition
 
(BOOL) - hasHostileTarget
 
(BOOL) - isHostileTo:
 
(NSUInteger) - defenseTargetCount
 
(NSArray *) - allDefenseTargets
 
(NSEnumerator *) - defenseTargetEnumerator
 
(void) - validateDefenseTargets
 
(BOOL) - addDefenseTarget:
 
(BOOL) - isDefenseTarget:
 
(void) - removeDefenseTarget:
 
(void) - removeAllDefenseTargets
 
(NSArray *) - collisionExceptions
 
(void) - addCollisionException:
 
(void) - removeCollisionException:
 
(BOOL) - collisionExceptedFor:
 
(GLfloat) - weaponRange
 
(void) - setWeaponRange:
 
(void) - setWeaponDataFromType:
 
(float) - energyRechargeRate
 
(float) - weaponRechargeRate
 
(void) - setWeaponRechargeRate:
 
(void) - setWeaponEnergy:
 
(OOWeaponFacing- currentWeaponFacing
 
(GLfloat) - scannerRange
 
(void) - setScannerRange:
 
(Vector) - reference
 
(void) - setReference:
 
(BOOL) - reportAIMessages
 
(void) - setReportAIMessages:
 
(void) - transitionToAegisNone
 
(OOPlanetEntity *) - findNearestPlanet
 
(Entity< OOStellarBody > *) - findNearestStellarBody
 
(OOPlanetEntity *) - findNearestPlanetExcludingMoons
 
(OOAegisStatus- checkForAegis
 
(void) - forceAegisCheck
 
(BOOL) - withinStationAegis
 
(void) - setLastAegisLock:
 
(OOSystemID- homeSystem
 
(OOSystemID- destinationSystem
 
(void) - setHomeSystem:
 
(void) - setDestinationSystem:
 
(NSArray *) - crew
 
(NSArray *) - crewForScripting
 
(void) - setCrew:
 
(void) - setSingleCrewWithRole:
 
(OOFuelQuantity- fuel
 
(void) - setFuel:
 
(OOFuelQuantity- fuelCapacity
 
(GLfloat) - fuelChargeRate
 
(void) - setRoll:
 
(void) - setRawRoll:
 
(void) - setPitch:
 
(void) - setYaw:
 
(void) - setThrust:
 
(void) - applySticks:
 
(void) - setThrustForDemo:
 
(void) - setBounty:
 
(void) - setBounty:withReason:
 
(void) - setBounty:withReasonAsString:
 
(OOCreditsQuantity- bounty
 
(int- legalStatus
 
(BOOL) - isTemplateCargoPod
 
(void) - setUpCargoType:
 
(void) - setCommodity:andAmount:
 
(void) - setCommodityForPod:andAmount:
 
(OOCommodityType- commodityType
 
(OOCargoQuantity- commodityAmount
 
(OOCargoQuantity- maxAvailableCargoSpace
 
(void) - setMaxAvailableCargoSpace:
 
(OOCargoQuantity- availableCargoSpace
 
(OOCargoQuantity- cargoQuantityOnBoard
 
(OOCargoType- cargoType
 
(NSArray *) - cargoListForScripting
 
(NSMutableArray *) - cargo
 
(void) - setCargo:
 
(BOOL) - addCargo:
 
(BOOL) - removeCargo:amount:
 
(BOOL) - showScoopMessage
 
(NSArray *) - passengerListForScripting
 
(NSArray *) - parcelListForScripting
 
(NSArray *) - contractListForScripting
 
(NSArray *) - equipmentListForScripting
 
(OOWeaponType- weaponTypeIDForFacing:strict:
 
(OOEquipmentType *) - weaponTypeForFacing:strict:
 
(NSArray *) - missilesList
 
(OOCargoFlag- cargoFlag
 
(void) - setCargoFlag:
 
(void) - setSpeed:
 
(double) - desiredSpeed
 
(void) - setDesiredSpeed:
 
(double) - desiredRange
 
(void) - setDesiredRange:
 
(double) - cruiseSpeed
 
(Vector) - thrustVector
 
(void) - setTotalVelocity:
 
(void) - increase_flight_speed:
 
(void) - decrease_flight_speed:
 
(void) - increase_flight_roll:
 
(void) - decrease_flight_roll:
 
(void) - increase_flight_pitch:
 
(void) - decrease_flight_pitch:
 
(void) - increase_flight_yaw:
 
(void) - decrease_flight_yaw:
 
(GLfloat) - flightRoll
 
(GLfloat) - flightPitch
 
(GLfloat) - flightYaw
 
(GLfloat) - flightSpeed
 
(GLfloat) - maxFlightPitch
 
(GLfloat) - maxFlightSpeed
 
(GLfloat) - maxFlightRoll
 
(GLfloat) - maxFlightYaw
 
(GLfloat) - speedFactor
 
(GLfloat) - temperature
 
(void) - setTemperature:
 
(GLfloat) - heatInsulation
 
(void) - setHeatInsulation:
 
(float) - randomEjectaTemperature
 
(float) - randomEjectaTemperatureWithMaxFactor:
 
(int- damage
 
(void) - dealEnergyDamage:atRange:withBias:
 
(void) - dealEnergyDamageWithinDesiredRange
 
(void) - dealMomentumWithinDesiredRange:
 
(void) - noteTakingDamage:from:type:
 
(void) - noteKilledBy:damageType:
 
(void) - getDestroyedBy:damageType:
 
(void) - becomeExplosion
 
(void) - becomeLargeExplosion:
 
(void) - becomeEnergyBlast
 
(void) - broadcastEnergyBlastImminent
 
(void) - setIsWreckage:
 
(BOOL) - showDamage
 
(Vector) - positionOffsetForAlignment:
 
(Vector) - positionOffsetForShipInRotationToAlignment
 
(void) - collectBountyFor:
 
(BoundingBox) - findSubentityBoundingBox
 
(Triangle) - absoluteIJKForSubentity
 
(GLfloat) - weaponRecoveryTime
 
(GLfloat) - laserHeatLevel
 
(GLfloat) - laserHeatLevelAft
 
(GLfloat) - laserHeatLevelForward
 
(GLfloat) - laserHeatLevelPort
 
(GLfloat) - laserHeatLevelStarboard
 
(GLfloat) - hullHeatLevel
 
(GLfloat) - entityPersonality
 
(GLint) - entityPersonalityInt
 
(void) - setEntityPersonalityInt:
 
(void) - setSuppressExplosion:
 
(void) - resetExhaustPlumes
 
(void) - removeExhaust:
 
(void) - removeFlasher:
 
(void) - checkScanner
 
(void) - checkScannerIgnoringUnpowered
 
(ShipEntity **) - scannedShips
 
(int- numberOfScannedShips
 
(Entity *) - foundTarget
 
(Entity *) - primaryAggressor
 
(Entity *) - lastEscortTarget
 
(Entity *) - thankedShip
 
(Entity *) - rememberedShip
 
(Entity *) - proximityAlert
 
(void) - setFoundTarget:
 
(void) - setPrimaryAggressor:
 
(void) - setLastEscortTarget:
 
(void) - setThankedShip:
 
(void) - setRememberedShip:
 
(void) - setProximityAlert:
 
(void) - setTargetStation:
 
(BOOL) - isValidTarget:
 
(void) - addTarget:
 
(void) - removeTarget:
 
(BOOL) - canStillTrackPrimaryTarget
 
(id) - primaryTarget
 
(id) - primaryTargetWithoutValidityCheck
 
(StationEntity *) - targetStation
 
(BOOL) - isFriendlyTo:
 
(ShipEntity *) - shipHitByLaser
 
(void) - noteLostTarget
 
(void) - noteLostTargetAndGoIdle
 
(void) - noteTargetDestroyed:
 
(OOBehaviour- behaviour
 
(void) - setBehaviour:
 
(void) - trackOntoTarget:withDForward:
 
(double) - ballTrackLeadingTarget:atTarget:
 
(GLfloat) - rollToMatchUp:rotating:
 
(GLfloat) - rangeToDestination
 
(double) - trackDestination:delta_t:
 
(void) - setCoordinate:
 
(HPVector) - coordinates
 
(HPVector) - destination
 
(HPVector) - distance_six:
 
(HPVector) - distance_twelve:withOffset:
 
(void) - setEvasiveJink:
 
(void) - evasiveAction:
 
(double) - trackPrimaryTarget:delta_t:
 
(double) - trackSideTarget:delta_t:
 
(double) - missileTrackPrimaryTarget:
 
(double) - rangeToPrimaryTarget
 
(double) - approachAspectToPrimaryTarget
 
(double) - rangeToSecondaryTarget:
 
(BOOL) - hasProximityAlertIgnoringTarget:
 
(GLfloat) - currentAimTolerance
 
(GLfloat) - lookingAtSunWithThresholdAngleCos:
 
(BOOL) - onTarget:withWeapon:
 
(OOTimeDelta- shotTime
 
(void) - resetShotTime
 
(BOOL) - fireMainWeapon:
 
(BOOL) - fireAftWeapon:
 
(BOOL) - firePortWeapon:
 
(BOOL) - fireStarboardWeapon:
 
(BOOL) - fireTurretCannon:
 
(void) - setLaserColor:
 
(void) - setExhaustEmissiveColor:
 
(OOColor *) - laserColor
 
(OOColor *) - exhaustEmissiveColor
 
(BOOL) - fireSubentityLaserShot:
 
(BOOL) - fireDirectLaserShot:
 
(BOOL) - fireDirectLaserDefensiveShot
 
(BOOL) - fireDirectLaserShotAt:
 
(NSArray *) - laserPortOffset:
 
(BOOL) - fireLaserShotInDirection:weaponIdentifier:
 
(void) - adjustMissedShots:
 
(int- missedShots
 
(void) - considerFiringMissile:
 
(Vector) - missileLaunchPosition
 
(ShipEntity *) - fireMissile
 
(ShipEntity *) - fireMissileWithIdentifier:andTarget:
 
(BOOL) - isMissileFlagSet
 
(void) - setIsMissileFlag:
 
(OOTimeDelta- missileLoadTime
 
(void) - setMissileLoadTime:
 
(void) - noticeECM
 
(BOOL) - fireECM
 
(BOOL) - cascadeIfAppropriateWithDamageAmount:cascadeOwner:
 
(BOOL) - activateCloakingDevice
 
(void) - deactivateCloakingDevice
 
(BOOL) - launchCascadeMine
 
(ShipEntity *) - launchEscapeCapsule
 
(OOCommodityType- dumpCargo
 
(ShipEntity *) - dumpCargoItem:
 
(OOCargoType- dumpItem:
 
(void) - manageCollisions
 
(BOOL) - collideWithShip:
 
(void) - adjustVelocity:
 
(void) - addImpactMoment:fraction:
 
(BOOL) - canScoop:
 
(void) - getTractoredBy:
 
(void) - scoopIn:
 
(void) - scoopUp:
 
(void) - scoopUpProcess:processEvents:processMessages:
 
(BOOL) - abandonShip
 
(void) - takeScrapeDamage:from:
 
(void) - takeHeatDamage:
 
(void) - enterDock:
 
(void) - leaveDock:
 
(void) - enterWormhole:
 
(void) - enterWormhole:replacing:
 
(void) - enterWitchspace
 
(void) - leaveWitchspace
 
(BOOL) - witchspaceLeavingEffects
 
(void) - markAsOffender:
 
(void) - markAsOffender:withReason:
 
(void) - switchLightsOn
 
(void) - switchLightsOff
 
(BOOL) - lightsActive
 
(void) - setDestination:
 
(void) - setEscortDestination:
 
(BOOL) - canAcceptEscort:
 
(BOOL) - acceptAsEscort:
 
(void) - deployEscorts
 
(void) - dockEscorts
 
(void) - setTargetToNearestFriendlyStation
 
(void) - setTargetToNearestStation
 
(void) - setTargetToSystemStation
 
(void) - landOnPlanet:
 
(void) - abortDocking
 
(NSDictionary *) - dockingInstructions
 
(void) - broadcastThargoidDestroyed
 
(void) - broadcastHitByLaserFrom:
 
(GLfloat) - sunGlareFilter
 
(void) - setSunGlareFilter:
 
(void) - sendExpandedMessage:toShip:
 
(void) - sendMessage:toShip:withUnpilotedOverride:
 
(void) - broadcastAIMessage:
 
(void) - broadcastMessage:withUnpilotedOverride:
 
(void) - setCommsMessageColor
 
(void) - receiveCommsMessage:from:
 
(void) - commsMessage:withUnpilotedOverride:
 
(BOOL) - markedForFines
 
(BOOL) - markForFines
 
(BOOL) - isMining
 
(void) - spawn:
 
(int- checkShipsInVicinityForWitchJumpExit
 
(BOOL) - trackCloseContacts
 
(void) - setTrackCloseContacts:
 
(void) - setHulk:
 
(BOOL) - isHulk
 
(OOJSScript *) - script
 
(NSDictionary *) - scriptInfo
 
(void) - overrideScriptInfo:
 
(BOOL) - scriptedMisjump
 
(void) - setScriptedMisjump:
 
(GLfloat) - scriptedMisjumpRange
 
(void) - setScriptedMisjumpRange:
 
(Entity *) - entityForShaderProperties
 
(void) - setDemoShip:
 
(BOOL) - isDemoShip
 
(void) - setDemoStartTime:
 
(void) - doScriptEvent:
 
(void) - doScriptEvent:withArgument:
 
(void) - doScriptEvent:withArgument:andArgument:
 
(void) - doScriptEvent:withArguments:
 
(void) - doScriptEvent:withArguments:count:
 
(void) - doScriptEvent:inContext:withArguments:count:
 
(void) - reactToAIMessage:context:
 
(void) - sendAIMessage:
 
(void) - doScriptEvent:andReactToAIMessage:
 
(void) - doScriptEvent:withArgument:andReactToAIMessage:
 
(id) - init [implementation]
 
(id) - initBypassForPlayer [implementation]
 
(NSString *) - repeatString:times: [implementation]
 
(BOOL) - setUpOneSubentity: [implementation]
 
(BOOL) - setUpOneFlasher: [implementation]
 
(void) - dealloc [implementation]
 
(NSString *) - descriptionComponents [implementation]
 
(NSString *) - shortDescriptionComponents [implementation]
 
(BoundingBox) - findBoundingBoxRelativeToPosition:InVectors:_i:_j: [implementation]
 
(void) - wasAddedToUniverse [implementation]
 
(void) - wasRemovedFromUniverse [implementation]
 
(NSString *) - beaconCode [implementation]
 
(void) - setBeaconCode: [implementation]
 
(NSString *) - beaconLabel [implementation]
 
(void) - setBeaconLabel: [implementation]
 
(BOOL) - isVisible [implementation]
 
(BOOL) - isBeacon [implementation]
 
(id< OOHUDBeaconIcon >) - beaconDrawable [implementation]
 
(Entity< OOBeaconEntity > *) - prevBeacon [implementation]
 
(Entity< OOBeaconEntity > *) - nextBeacon [implementation]
 
(void) - setPrevBeacon: [implementation]
 
(void) - setNextBeacon: [implementation]
 
(void) - setUpMixedEscorts [implementation]
 
(void) - setUpOneEscort:inGroup:withRole:atPosition:andCount: [implementation]
 
(OOScanClass- scanClass [implementation]
 
(BOOL) - canCollide [implementation]
 
(ShipEntity *) - doOctreesCollide [implementation]
 
(BOOL) - checkCloseCollisionWith: [implementation]
 
(void) - addSubentityToCollisionRadius: [implementation]
 
(ShipEntity *) - launchPodWithCrew: [implementation]
 
(BOOL) - validForAddToUniverse [implementation]
 
(void) - update: [implementation]
 
(void) - noteFrustration: [implementation]
 
(OOEquipmentType *) - generateMissileEquipmentTypeFrom: [implementation]
 
(OOEquipmentType *) - verifiedMissileTypeFromRole: [implementation]
 
(void) - drawImmediate:translucent: [implementation]
 
(void) - drawDebugStuff [implementation]
 
(void) - drawSubEntityImmediate:translucent: [implementation]
 
(BOOL) - isJammingScanning [implementation]
 
(void) - addSubEntity: [implementation]
 
(void) - setOwner: [implementation]
 
(void) - orientationChanged [implementation]
 
(void) - applyRoll:andClimb: [implementation]
 
(void) - applyRoll:climb:andYaw: [implementation]
 
(OOShipGroup *) - rawEscortGroup [implementation]
 
(NSComparisonResult) - ComparePlanetsBySurfaceDistance [implementation]
 
(Entity< OOStellarBody > *) - lastAegisLock [implementation]
 
(void) - setStatus: [implementation]
 
(void) - rescaleBy: [implementation]
 
(void) - rescaleBy:writeToCache: [implementation]
 
(void) - releaseCargoPodsDebris [implementation]
 
(void) - subEntityDied: [implementation]
 
(void) - subEntityReallyDied: [implementation]
 
(NSComparisonResult) - compareBeaconCodeWith: [implementation]
 
(uint32_t) - randomSeedForShaders [implementation]
 
(void) - setShipHitByLaser: [implementation]
 
(BOOL) - fireWeapon:direction:range: [implementation]
 
(void) - throwSparks [implementation]
 
(Vector) - velocity [implementation]
 
(void) - suppressTargetLost [implementation]
 
(void) - takeEnergyDamage:from:becauseOf:weaponIdentifier: [implementation]
 
(void) - refreshEscortPositions [implementation]
 
(HPVector) - coordinatesForEscortPosition: [implementation]
 
(void) - setTargetToNearestStationIncludingHostiles: [implementation]
 
(BoundingBox) - findBoundingBoxRelativeTo:InVectors:_i:_j: [implementation]
 
(void) - dumpSelfState [implementation]
 
(OOTimeAbsolute- getDemoStartTime [implementation]
 
(void) - doNothing [implementation]
 
(NSString *) - descriptionForObjDump [implementation]
 
(void) - setAITo:
 
(void) - setAIScript:
 
(void) - switchAITo:
 
(void) - scanForHostiles
 
(BOOL) - performHyperSpaceToSpecificSystem:
 
(void) - scanForNearestIncomingMissile
 
(void) - enterTargetWormhole
 
(void) - enterPlayerWormhole
 
(void) - wormholeEscorts
 
(void) - wormholeEntireGroup
 
(BOOL) - suggestEscortTo:
 
(void) - groupAttackTarget
 
(void) - performAttack
 
(void) - performCollect
 
(void) - performEscort
 
(void) - performFaceDestination
 
(void) - performFlee
 
(void) - performFlyToRangeFromDestination
 
(void) - performHold
 
(void) - performIdle
 
(void) - performIntercept
 
(void) - performLandOnPlanet
 
(void) - performMining
 
(void) - performScriptedAI
 
(void) - performScriptedAttackAI
 
(void) - performStop
 
(void) - performTumble
 
(void) - broadcastDistressMessage
 
(void) - broadcastDistressMessageWithDumping:
 
(void) - requestDockingCoordinates
 
(void) - recallDockingInstructions
 
(void) - performBuoyTumble [implementation]
 
(NSDictionary *) - savedShipDictionaryWithContext:
 
(void) - simplifyShipdata:andGetDeletes: [implementation]
 
(void) - checkFoundTarget [implementation]
 
(BOOL) - performHyperSpaceExitReplace: [implementation]
 
(BOOL) - performHyperSpaceExitReplace:toSystem: [implementation]
 
(void) - scanForNearestShipWithPredicate:parameter: [implementation]
 
(void) - scanForNearestShipWithNegatedPredicate:parameter: [implementation]
 
(void) - acceptDistressMessageFrom: [implementation]
 
(BOOL) - launchPatrol [implementation]
 
(BOOL) - inspHasSecondaryIdentityLine [implementation]
 
(NSString *) - inspSecondaryIdentityLine [implementation]
 
(NSString *) - inspDescription [implementation]
 
(NSString *) - inspTargetLine [implementation]
 
(BOOL) - inspCanBecomeTarget [implementation]
 
(void) - inspBecomeTarget [implementation]
 
(NSArray *) - subEntitiesForScript
 
(void) - setTargetForScript:
 
(BOOL) - isVisibleToScripts [implementation]
 
(void) - getJSClass:andPrototype: [implementation]
 
(NSString *) - oo_jsClassName [implementation]
 
(NSArray *) - debugInspectorModules [implementation]
 
(void) - setStateTo: [implementation]
 
(void) - pauseAI: [implementation]
 
(void) - randomPauseAI: [implementation]
 
(void) - dropMessages: [implementation]
 
(void) - debugDumpPendingMessages [implementation]
 
(void) - setDestinationToCurrentLocation [implementation]
 
(void) - setDesiredRangeTo: [implementation]
 
(void) - setDesiredRangeForWaypoint [implementation]
 
(void) - setSpeedTo: [implementation]
 
(void) - setSpeedFactorTo: [implementation]
 
(void) - setSpeedToCruiseSpeed [implementation]
 
(void) - setThrustFactorTo: [implementation]
 
(void) - setTargetToPrimaryAggressor [implementation]
 
(void) - scanForNearestMerchantman [implementation]
 
(void) - scanForRandomMerchantman [implementation]
 
(void) - scanForLoot [implementation]
 
(void) - scanForRandomLoot [implementation]
 
(void) - setTargetToFoundTarget [implementation]
 
(void) - checkForFullHold [implementation]
 
(void) - getWitchspaceEntryCoordinates [implementation]
 
(void) - setDestinationFromCoordinates [implementation]
 
(void) - setCoordinatesFromPosition [implementation]
 
(void) - fightOrFleeMissile [implementation]
 
(void) - setCourseToPlanet [implementation]
 
(void) - setTakeOffFromPlanet [implementation]
 
(void) - landOnPlanet [implementation]
 
(void) - checkTargetLegalStatus [implementation]
 
(void) - checkOwnLegalStatus [implementation]
 
(void) - exitAIWithMessage: [implementation]
 
(void) - setDestinationToTarget [implementation]
 
(void) - setDestinationWithinTarget [implementation]
 
(void) - checkCourseToDestination [implementation]
 
(void) - checkAegis [implementation]
 
(void) - checkEnergy [implementation]
 
(void) - checkHeatInsulation [implementation]
 
(void) - scanForOffenders [implementation]
 
(void) - setCourseToWitchpoint [implementation]
 
(void) - setDestinationToWitchpoint [implementation]
 
(void) - setDestinationToStationBeacon [implementation]
 
(void) - performHyperSpaceExit [implementation]
 
(void) - performHyperSpaceExitWithoutReplacing [implementation]
 
(void) - wormholeGroup [implementation]
 
(void) - commsMessage: [implementation]
 
(void) - commsMessageByUnpiloted: [implementation]
 
(void) - ejectCargo [implementation]
 
(void) - scanForThargoid [implementation]
 
(void) - scanForNonThargoid [implementation]
 
(void) - thargonCheckMother [implementation]
 
(void) - becomeUncontrolledThargon [implementation]
 
(void) - checkDistanceTravelled [implementation]
 
(void) - fightOrFleeHostiles [implementation]
 
(void) - suggestEscort [implementation]
 
(void) - escortCheckMother [implementation]
 
(void) - checkGroupOddsVersusTarget [implementation]
 
(void) - scanForFormationLeader [implementation]
 
(void) - messageMother: [implementation]
 
(void) - setPlanetPatrolCoordinates [implementation]
 
(void) - setSunSkimStartCoordinates [implementation]
 
(void) - setSunSkimEndCoordinates [implementation]
 
(void) - setSunSkimExitCoordinates [implementation]
 
(void) - patrolReportIn [implementation]
 
(void) - checkForMotherStation [implementation]
 
(void) - sendTargetCommsMessage: [implementation]
 
(void) - markTargetForFines [implementation]
 
(void) - markTargetForOffence: [implementation]
 
(void) - storeTarget [implementation]
 
(void) - recallStoredTarget [implementation]
 
(void) - scanForRocks [implementation]
 
(void) - setDestinationToDockingAbort [implementation]
 
(void) - requestNewTarget [implementation]
 
(void) - rollD: [implementation]
 
(void) - scanForNearestShipWithPrimaryRole: [implementation]
 
(void) - scanForNearestShipHavingRole: [implementation]
 
(void) - scanForNearestShipWithAnyPrimaryRole: [implementation]
 
(void) - scanForNearestShipHavingAnyRole: [implementation]
 
(void) - scanForNearestShipWithScanClass: [implementation]
 
(void) - scanForNearestShipWithoutPrimaryRole: [implementation]
 
(void) - scanForNearestShipNotHavingRole: [implementation]
 
(void) - scanForNearestShipWithoutAnyPrimaryRole: [implementation]
 
(void) - scanForNearestShipNotHavingAnyRole: [implementation]
 
(void) - scanForNearestShipWithoutScanClass: [implementation]
 
(void) - setCoordinates: [implementation]
 
(void) - checkForNormalSpace [implementation]
 
(void) - setTargetToRandomStation [implementation]
 
(void) - setTargetToLastStation [implementation]
 
(void) - addFuel: [implementation]
 
(void) - scriptActionOnTarget: [implementation]
 
(void) - sendScriptMessage: [implementation]
 
(void) - ai_throwSparks [implementation]
 
(void) - explodeSelf [implementation]
 
(void) - ai_debugMessage: [implementation]
 
(void) - targetFirstBeaconWithCode: [implementation]
 
(void) - targetNextBeaconWithCode: [implementation]
 
(void) - setRacepointsFromTarget [implementation]
 
(void) - performFlyRacepoints [implementation]
 
(void) - addPrimaryAggressorAsDefenseTarget [implementation]
 
(void) - addFoundTargetAsDefenseTarget [implementation]
 
(void) - findNewDefenseTarget [implementation]
 
(void) - setDestinationToJinkPosition [implementation]
 
(void) - disengageAutopilot [implementation]
 
(void) - messageSelf: [implementation]
 
(void) - scanForNearestShipMatchingPredicate: [implementation]
 
(void) - safeScriptActionOnTarget: [implementation]
 
(ShipEntity *) - ejectShipOfType:
 
(ShipEntity *) - ejectShipOfRole:
 
(NSArray *) - spawnShipsWithRole:count:
 
(BOOL) - isShipWithSubEntityShip: [implementation]
 
- Instance Methods inherited from OOEntityWithDrawable
(OODrawable *) - drawable
 
(void) - setDrawable:
 
(double) - findCollisionRadius [implementation]
 
(NSSet *) - allTextures [implementation]
 
- Instance Methods inherited from Entity
(NSUInteger) - sessionID
 
(BOOL) - isShip
 
(BOOL) - isDock
 
(BOOL) - isStation
 
(BOOL) - isSubEntity
 
(BOOL) - isPlayer
 
(BOOL) - isPlanet
 
(BOOL) - isSun
 
(BOOL) - isSunlit
 
(BOOL) - isStellarObject
 
(BOOL) - isSky
 
(BOOL) - isWormhole
 
(BOOL) - isEffect
 
(BOOL) - isVisualEffect
 
(BOOL) - isWaypoint
 
(void) - addToLinkedLists
 
(void) - removeFromLinkedLists
 
(void) - updateLinkedLists
 
(void) - warnAboutHostiles
 
(CollisionRegion *) - collisionRegion
 
(void) - setCollisionRegion:
 
(void) - setUniversalID:
 
(OOUniversalID- universalID
 
(BOOL) - throwingSparks
 
(void) - setThrowSparks:
 
(id) - owner
 
(ShipEntity *) - parentEntity
 
(ShipEntity *) - rootShipEntity
 
(void) - setPosition:
 
(void) - setPositionX:y:z:
 
(HPVector) - position
 
(Vector) - cameraRelativePosition
 
(GLfloat) - cameraRangeFront
 
(GLfloat) - cameraRangeBack
 
(void) - updateCameraRelativePosition
 
(Vector) - vectorTo:
 
(HPVector) - absolutePositionForSubentity
 
(HPVector) - absolutePositionForSubentityOffset:
 
(double) - zeroDistance
 
(double) - camZeroDistance
 
(NSComparisonResult) - compareZeroDistance:
 
(BoundingBox) - boundingBox
 
(GLfloat) - mass
 
(Quaternion) - orientation
 
(void) - setOrientation:
 
(Quaternion) - normalOrientation
 
(void) - setNormalOrientation:
 
(void) - setVelocity:
 
(double) - speed
 
(GLfloat) - distanceTravelled
 
(void) - setDistanceTravelled:
 
(OOEntityStatus- status
 
(void) - setScanClass:
 
(void) - setEnergy:
 
(GLfloat) - energy
 
(void) - setMaxEnergy:
 
(GLfloat) - maxEnergy
 
(void) - moveForward:
 
(OOMatrix) - rotationMatrix
 
(OOMatrix) - drawRotationMatrix
 
(OOMatrix) - transformationMatrix
 
(OOMatrix) - drawTransformationMatrix
 
(GLfloat) - collisionRadius
 
(void) - setCollisionRadius:
 
(NSMutableArray *) - collisionArray
 
(void) - applyVelocity:
 
(void) - dumpState
 
(BOOL) - isInSpace
 
(BOOL) - isImmuneToBreakPatternHide
 
(GLfloat) - universalTime
 
(GLfloat) - spawnTime
 
(GLfloat) - timeElapsedSinceSpawn
 
(void) - setAtmosphereFogging:
 
(OOColor *) - fogUniform
 
(NSString *) - descriptionForObjDumpBasic
 
(BOOL) - checkLinkedLists [implementation]
 
(id< OOWeakReferenceSupport >) - superShaderBindingTarget [implementation]
 
(Vector) - relativePosition [implementation]
 
(BOOL) - isBreakPattern
 
(void) - inspect [implementation]
 
(BOOL) - isECMBlast
 
(NSString *) - inspScanClassLine
 
(NSString *) - inspStatusLine
 
(NSString *) - inspRetainCountLine
 
(NSString *) - inspPositionLine
 
(NSString *) - inspVelocityLine
 
(NSString *) - inspOrientationLine
 
(NSString *) - inspEnergyLine
 
(NSString *) - inspOwnerLine
 
(NSString *) - inspBasicIdentityLine [implementation]
 
(BOOL) - isExhaust
 
(BOOL) - isFlasher
 
(void) - deleteJSSelf
 
(jsval) - oo_jsValueInContext: [implementation]
 
(BOOL) - isCascadeWeapon
 
(BOOL) - isPlayerLikeShip
 
(GLfloat) - clock [implementation]
 
(unsigned) - pseudoFixedD100 [implementation]
 
(unsigned) - pseudoFixedD256 [implementation]
 
(unsigned) - systemGovernment [implementation]
 
(unsigned) - systemEconomy [implementation]
 
(unsigned) - systemTechLevel [implementation]
 
(unsigned) - systemPopulation [implementation]
 
(unsigned) - systemProductivity [implementation]
 
- Instance Methods inherited from OOWeakRefObject
(id) - weakSelf
 
(id) - weakRetain [implementation]
 
(void) - weakRefDied: [implementation]
 
- Instance Methods inherited from <OOWeakReferenceSupport>
(id) - OO_RETURNS_RETAINED
 
- Instance Methods inherited from <OOSubEntity>
- Instance Methods inherited from <OOBeaconEntity>

Class Methods

(static BOOL) + IsBehaviourHostile [implementation]
 
(static float) + SurfaceDistanceSqaredV [implementation]
 
(static float) + SurfaceDistanceSqared [implementation]
 
(static BOOL) + AuthorityPredicate [implementation]
 
(id) + shipRestoredFromDictionary:useFallback:context:
 

Public Attributes

OOTimeDelta shot_time
 
Vector v_forward
 
Vector v_up
 
Vector v_right
 
HPVector _destination
 
GLfloat desired_range
 
GLfloat desired_speed
 
GLfloat stick_roll
 
GLfloat stick_pitch
 
GLfloat stick_yaw
 
OOBehaviour behaviour
 
BoundingBox totalBoundingBox
 
- Public Attributes inherited from Entity
OOUniversalID universalID
 
unsigned isShip: 1
 
unsigned isStation: 1
 
unsigned isPlayer: 1
 
unsigned isWormhole: 1
 
unsigned isSubEntity: 1
 
unsigned hasMoved: 1
 
unsigned hasRotated: 1
 
unsigned hasCollided: 1
 
unsigned isSunlit: 1
 
unsigned collisionTestFilter: 2
 
unsigned throw_sparks: 1
 
unsigned isImmuneToBreakPatternHide: 1
 
unsigned isExplicitlyNotMainStation: 1
 
unsigned isVisualEffect: 1
 
OOScanClass scanClass
 
GLfloat zero_distance
 
GLfloat cam_zero_distance
 
GLfloat no_draw_distance
 
GLfloat collision_radius
 
HPVector position
 
Vector cameraRelativePosition
 
Quaternion orientation
 
OOColoratmosphereFogging
 
int zero_index
 
Entityx_previous
 
Entityx_next
 
Entityy_previous
 
Entityy_next
 
Entityz_previous
 
Entityz_next
 
Entitycollision_chain
 
OOUniversalID shadingEntityID
 
Entitycollider
 
CollisionRegioncollisionRegion
 

Protected Attributes

NSDictionary * shipinfoDictionary
 
Quaternion subentityRotationalVelocity
 
OOJSScriptscript
 
OOJSScriptaiScript
 
OOTimeAbsolute aiScriptWakeTime
 
NSDictionary * dockingInstructions
 
OOColorlaser_color
 
OOColordefault_laser_color
 
OOColorexhaust_emissive_color
 
OOColorscanner_display_color1
 
OOColorscanner_display_color2
 
OOColorscanner_display_color_hostile1
 
OOColorscanner_display_color_hostile2
 
GLfloat maxFlightSpeed
 
GLfloat max_flight_roll
 
GLfloat max_flight_pitch
 
GLfloat max_flight_yaw
 
GLfloat cruiseSpeed
 
GLfloat max_thrust
 
GLfloat thrust
 
float hyperspaceMotorSpinTime
 
unsigned military_jammer_active: 1
 
unsigned docking_match_rotation: 1
 
unsigned pitching_over: 1
 
unsigned rolling_over: 1
 
unsigned reportAIMessages: 1
 
unsigned being_mined: 1
 
unsigned being_fined: 1
 
unsigned isHulk: 1
 
unsigned trackCloseContacts: 1
 
unsigned isNearPlanetSurface: 1
 
unsigned isFrangible: 1
 
unsigned cloaking_device_active: 1
 
unsigned cloakPassive: 1
 
unsigned cloakAutomatic: 1
 
unsigned canFragment: 1
 
unsigned isWreckage: 1
 
unsigned _showDamage: 1
 
unsigned suppressExplosion: 1
 
unsigned suppressAegisMessages: 1
 
unsigned isMissile: 1
 
unsigned _explicitlyUnpiloted: 1
 
unsigned hasScoopMessage: 1
 
unsigned scripted_misjump: 1
 
unsigned haveExecutedSpawnAction: 1
 
unsigned haveStartedJSAI: 1
 
unsigned noRocks: 1
 
unsigned _lightsActive: 1
 
GLfloat _scriptedMisjumpRange
 
GLfloat sunGlareFilter
 
OOFuelQuantity fuel
 
GLfloat fuel_accumulator
 
GLfloat afterburner_rate
 
GLfloat afterburner_speed_factor
 
OOCargoQuantity likely_cargo
 
OOCargoQuantity max_cargo
 
OOCargoQuantity extra_cargo
 
OOCargoQuantity equipment_weight
 
OOCargoType cargo_type
 
OOCargoFlag cargo_flag
 
OOCreditsQuantity bounty
 
GLfloat energy_recharge_rate
 
OOWeaponFacingSet weapon_facings
 
OOWeaponType forward_weapon_type
 
OOWeaponType aft_weapon_type
 
OOWeaponType port_weapon_type
 
OOWeaponType starboard_weapon_type
 
GLfloat weapon_damage
 
GLfloat weapon_damage_override
 
GLfloat weaponRange
 
OOWeaponFacing currentWeaponFacing
 
GLfloat weapon_energy_use
 
GLfloat weapon_temp
 
GLfloat weapon_shot_temperature
 
GLfloat forward_weapon_temp
 
GLfloat aft_weapon_temp
 
GLfloat port_weapon_temp
 
GLfloat starboard_weapon_temp
 
GLfloat scannerRange
 
unsigned missiles
 
unsigned max_missiles
 
NSString * _missileRole
 
OOTimeDelta missile_load_time
 
OOTimeAbsolute missile_launch_time
 
AIshipAI
 
NSString * name
 
NSString * shipUniqueName
 
NSString * shipClassName
 
NSString * displayName
 
NSString * scan_description
 
OORoleSetroleSet
 
NSString * primaryRole
 
NSArray * explosionType
 
Vector jink
 
HPVector coordinates
 
Vector reference
 
NSUInteger _subIdx
 
NSUInteger _maxShipSubIdx
 
double launch_time
 
double launch_delay
 
OOUniversalID planetForLanding
 
GLfloat frustration
 
GLfloat success_factor
 
int patrol_counter
 
NSMutableDictionary * previousCondition
 
float weapon_recharge_rate
 
int shot_counter
 
OOTimeAbsolute cargo_dump_time
 
OOTimeAbsolute last_shot_time
 
NSMutableArray * cargo
 
OOCommodityType commodity_type
 
OOCargoQuantity commodity_amount
 
GLfloat flightSpeed
 
GLfloat flightRoll
 
GLfloat flightPitch
 
GLfloat flightYaw
 
GLfloat accuracy
 
GLfloat pitch_tolerance
 
GLfloat aim_tolerance
 
int _missed_shots
 
OOAegisStatus aegis_status
 
OOSystemID home_system
 
OOSystemID destination_system
 
double messageTime
 
double next_spark_time
 
Vector collision_vector
 
GLfloat _scaleFactor
 
BOOL _multiplyWeapons
 
NSArray * forwardWeaponOffset
 
NSArray * aftWeaponOffset
 
NSArray * portWeaponOffset
 
NSArray * starboardWeaponOffset
 
NSArray * crew
 
NSMutableDictionary * closeContactsInfo
 
NSString * lastRadioMessage
 
Vector tractor_position
 
float ship_temperature
 
ShipEntityscanned_ships [MAX_SCAN_NUMBER+1]
 
GLfloat distance2_scanned_ships [MAX_SCAN_NUMBER+1]
 
unsigned n_scanned_ships
 
HPVector navpoints [32]
 
unsigned next_navpoint_index
 
unsigned number_of_navpoints
 
Octreeoctree
 
OOBehaviour debugLastBehaviour
 
uint16_t entity_personality
 
NSDictionary * scriptInfo
 
NSMutableArray * subEntities
 
OOEquipmentTypemissile_list [SHIPENTITY_MAX_MISSILES]
 
OOWeakReference_primaryTarget
 
OOWeakReference_primaryAggressor
 
OOWeakReference_targetStation
 
OOWeakReference_foundTarget
 
OOWeakReference_lastEscortTarget
 
OOWeakReference_thankedShip
 
OOWeakReference_rememberedShip
 
OOWeakReference_proximityAlert
 
float reactionTime
 
HPVector trackingCurvePositions [4]
 
OOTimeAbsolute trackingCurveTimes [4]
 
HPVector trackingCurveCoeffs [3]
 
- Protected Attributes inherited from Entity
HPVector lastPosition
 
Quaternion lastOrientation
 
GLfloat distanceTravelled
 
OOMatrix rotMatrix
 
Vector velocity
 
GLfloat energy
 
GLfloat maxEnergy
 
BoundingBox boundingBox
 
GLfloat mass
 
NSMutableArray * collidingEntities
 
OOTimeAbsolute spawnTime
 
struct JSObject * _jsSelf
 
- Protected Attributes inherited from OOWeakRefObject
OOWeakReferenceweakSelf
 

Private Attributes

OOWeakReference_subEntityTakingDamage
 
NSString * _shipKey
 
NSMutableArray * _equipment
 
float _heatInsulation
 
OOWeakReference_lastAegisLock
 
OOShipGroup_group
 
OOShipGroup_escortGroup
 
uint8_t _maxEscortCount
 
uint8_t _pendingEscortCount
 
Vector _escortPositions [MAX_ESCORTS]
 
BOOL _escortPositionsValid
 
OOWeakSet_defenseTargets
 
OOWeakSet_collisionExceptions
 
GLfloat _profileRadius
 
OOWeakReference_shipHitByLaser
 
NSString * _beaconCode
 
NSString * _beaconLabel
 
OOWeakReference_prevBeacon
 
OOWeakReference_nextBeacon
 
id< OOHUDBeaconIcon_beaconDrawable
 
double _nextAegisCheck
 
BOOL isDemoShip
 
OOScalar demoRate
 
OOTimeAbsolute demoStartTime
 
Quaternion demoStartOrientation
 

Detailed Description

Definition at line 192 of file ShipEntity.h.

Method Documentation

◆ abandonShip

- (BOOL) abandonShip

Definition at line 9593 of file ShipEntity.m.

13309{
13310 BOOL OK = NO;
13311 if ([self isPlayer] && [(PlayerEntity *)self isDocked])
13312 {
13313 OOLog(@"ShipEntity.abandonShip.failed", @"%@", @"Player cannot abandon ship while docked.");
13314 return OK;
13315 }
13316
13317 if (![self hasEscapePod])
13318 {
13319 OOLog(@"ShipEntity.abandonShip.failed", @"Ship abandonment was requested for %@, but this ship does not carry escape pod(s).", self);
13320 return OK;
13321 }
13322
13323 if (EXPECT([self launchEscapeCapsule] != NO_TARGET)) // -launchEscapeCapsule takes care of everything for the player
13324 {
13325 if (![self isPlayer])
13326 {
13327 OK = YES;
13328 // if multiple items providing escape pod, remove all of them (NPC process)
13329 while ([self hasEquipmentItemProviding:@"EQ_ESCAPE_POD"])
13330 {
13331 [self removeEquipmentItem:[self equipmentItemProviding:@"EQ_ESCAPE_POD"]];
13332 }
13333 [self setAITo:@"nullAI.plist"];
13334 behaviour = BEHAVIOUR_IDLE;
13335 frustration = 0.0;
13336 [self setScanClass: CLASS_CARGO]; // we're unmanned now!
13337 thrust = thrust * 0.5;
13338 if (thrust > 5) thrust = 5; // 5 is the thrust of an escape-capsule
13339 desired_speed = 0.0;
13340 if ([self group]) [self setGroup:nil]; // remove self from group.
13341 if (![self isSubEntity] && [self owner]) [self setOwner:nil]; //unset owner, but not if we are a subent
13342 if ([self hasEscorts])
13343 {
13344 OOShipGroup *escortGroup = [self escortGroup];
13345 NSEnumerator *escortEnum = nil;
13346 ShipEntity *escort = nil;
13347 // Note: works on escortArray rather than escortEnumerator because escorts may be mutated.
13348 for (escortEnum = [[self escortArray] objectEnumerator]; (escort = [escortEnum nextObject]); )
13349 {
13350 // act individually now!
13351 if ([escort group] == escortGroup) [escort setGroup:nil];
13352 if ([escort owner] == self) [escort setOwner:escort];
13353 }
13354
13355 // We now have no escorts.
13356 [_escortGroup release];
13357 _escortGroup = nil;
13358 }
13359 }
13360 }
13361 else if (EXPECT([self isSubEntity]))
13362 {
13363 // may still have launched passenger pods even if no crew
13364 // if multiple items providing escape pod, remove all of them (NPC process)
13365 while ([self hasEquipmentItemProviding:@"EQ_ESCAPE_POD"])
13366 {
13367 [self removeEquipmentItem:[self equipmentItemProviding:@"EQ_ESCAPE_POD"]];
13368 }
13369
13370 }
13371 else
13372 {
13373 // this shouldn't happen any more!
13374 OOLog(@"ShipEntity.abandonShip.notPossible", @"Ship %@ cannot be abandoned at this time.", self);
13375 }
13376 return OK;
13377}
#define EXPECT(x)
#define OOLog(class, format,...)
Definition OOLogging.h:88
return nil
@ NO_TARGET
Definition OOTypes.h:194
unsigned isSubEntity
Definition Entity.h:95
unsigned isPlayer
Definition Entity.h:93
id owner()
Definition Entity.m:583
BOOL hasEscorts()
GLfloat frustration
Definition ShipEntity.h:348
OOShipGroup * escortGroup()
void setGroup:(OOShipGroup *group)
OOShipGroup * group()
NSArray * escortArray()
BOOL hasEscapePod()
GLfloat thrust
Definition ShipEntity.h:246
ShipEntity * launchEscapeCapsule()
OOBehaviour behaviour
Definition ShipEntity.h:211
OOShipGroup * _escortGroup
Definition ShipEntity.h:467
GLfloat desired_speed
Definition ShipEntity.h:206
void setOwner:(Entity *who_owns_entity)

References findBoundingBoxRelativeToPosition:InVectors:i:j:, kZeroVector, vector_forward_from_quaternion(), vector_right_from_quaternion(), and vector_up_from_quaternion().

+ Here is the call graph for this function:

◆ abortDocking

- (void) abortDocking

Definition at line 9593 of file ShipEntity.m.

14048{
14049 [[UNIVERSE findEntitiesMatchingPredicate:IsStationPredicate
14050 parameter:nil
14051 inRange:-1
14052 ofEntity:nil]
14053 makeObjectsPerformSelector:@selector(abortDockingForShip:) withObject:self];
14054}

◆ absoluteIJKForSubentity

- (Triangle) absoluteIJKForSubentity

Definition at line 2093 of file ShipEntity.m.

2235{
2236 Triangle result = {{ kBasisXVector, kBasisYVector, kBasisZVector }};
2237 Entity *last = nil;
2238 Entity *father = self;
2239 OOMatrix r_mat;
2240
2241 while ((father)&&(father != last) && (father != NO_TARGET))
2242 {
2243 r_mat = [father drawRotationMatrix];
2244 result.v[0] = OOVectorMultiplyMatrix(result.v[0], r_mat);
2245 result.v[1] = OOVectorMultiplyMatrix(result.v[1], r_mat);
2246 result.v[2] = OOVectorMultiplyMatrix(result.v[2], r_mat);
2247
2248 last = father;
2249 if (![last isSubEntity]) break;
2250 father = [father owner];
2251 }
2252 return result;
2253}
Vector OOVectorMultiplyMatrix(Vector v, OOMatrix m)
Definition OOMatrix.m:129
const Vector kBasisYVector
Definition OOVector.m:30
const Vector kBasisZVector
Definition OOVector.m:31
const Vector kBasisXVector
Definition OOVector.m:29
OOMatrix drawRotationMatrix()
Definition Entity.m:879

References absoluteIJKForSubentity, Entity::absolutePositionForSubentity, doOctreesCollide(), isHitByOctree(), nil, octree, and subEntities.

Referenced by absoluteIJKForSubentity.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ absoluteTractorPosition

- (HPVector) absoluteTractorPosition

Definition at line 14954 of file ShipEntity.m.

1541{
1542 return HPvector_add(position, vectorToHPVector(quaternion_rotate_vector([self normalOrientation], tractor_position)));
1543}
Vector quaternion_rotate_vector(Quaternion q, Vector v)
HPVector position
Definition Entity.h:112
Quaternion normalOrientation()
Definition Entity.m:738
Vector tractor_position
Definition ShipEntity.h:407

References OOEquipmentType::identifier, and nil.

+ Here is the call graph for this function:

◆ acceptAsEscort:

- (BOOL) acceptAsEscort: (ShipEntity *) other_ship

Definition at line 9593 of file ShipEntity.m.

13710 :(ShipEntity *) other_ship
13711{
13712 // can't pair with self
13713 if (self == other_ship) return NO;
13714
13715 // no longer in flight, probably entered wormhole without telling escorts.
13716 if ([self status] != STATUS_IN_FLIGHT) return NO;
13717
13718 //increased stack depth at which it can accept escorts to avoid rejections at this stage.
13719 //doesn't seem to have any adverse effect for now. - Kaks.
13720 if ([shipAI stackDepth] > 3)
13721 {
13722 OOLog(@"ship.escort.reject", @"%@ rejecting escort %@ because AI stack depth is %lu.",self, other_ship, [shipAI stackDepth]);
13723 return NO;
13724 }
13725
13726 if ([self canAcceptEscort:other_ship])
13727 {
13728 OOShipGroup *escortGroup = [self escortGroup];
13729
13730 if ([escortGroup containsShip:other_ship]) return YES;
13731
13732 // check total number acceptable
13733 // the system's patrols don't have escorts set inside their dictionary, but accept max escorts.
13734 if (_maxEscortCount == 0 && ([self hasPrimaryRole:@"police"] || [self hasPrimaryRole:@"hunter"] || [self hasRole:@"thargoid-mothership"]))
13735 {
13737 }
13738
13739 NSUInteger maxEscorts = _maxEscortCount; // never bigger than MAX_ESCORTS.
13740 NSUInteger escortCount = [escortGroup count] - 1; // always 0 or higher.
13741
13742 if (escortCount < maxEscorts)
13743 {
13744 [other_ship setGroup:escortGroup];
13745 if ([self group] == nil)
13746 {
13747 [self setGroup:escortGroup];
13748 }
13749 else if ([self group] != escortGroup) [[self group] addShip:other_ship];
13750
13751 if (([other_ship maxFlightSpeed] < cruiseSpeed) && ([other_ship maxFlightSpeed] > cruiseSpeed * 0.3))
13752 {
13753 cruiseSpeed = [other_ship maxFlightSpeed] * 0.99;
13754 }
13755
13756 OOLog(@"ship.escort.accept", @"%@ accepting escort %@.", self, other_ship);
13757
13758 [self doScriptEvent:OOJSID("shipAcceptedEscort") withArgument:other_ship];
13759 [other_ship doScriptEvent:OOJSID("escortAccepted") withArgument:self];
13760 [shipAI message:@"ACCEPTED_ESCORT"];
13761 return YES;
13762 }
13763 else
13764 {
13765 OOLog(@"ship.escort.reject", @"%@ already got max escorts(%ld). Escort rejected: %@.", self, escortCount, other_ship);
13766 }
13767 }
13768 else
13769 {
13770 OOLog(@"ship.escort.reject", @"%@ failed canAcceptEscort for escort %@.", self, other_ship);
13771 }
13772
13773
13774 return NO;
13775}
#define MAX_ESCORTS
Definition ShipEntity.h:74
OOEntityStatus status()
Definition Entity.m:793
NSUInteger count()
uint8_t _maxEscortCount
Definition ShipEntity.h:468
uint8_t escortCount()
GLfloat maxFlightSpeed
Definition ShipEntity.h:239
GLfloat cruiseSpeed
Definition ShipEntity.h:243

Referenced by ShipGroupAddShip().

+ Here is the caller graph for this function:

◆ acceptDistressMessageFrom:

- (void) acceptDistressMessageFrom: (ShipEntity *) other
implementation

Reimplemented in StationEntity.

Provided by category ShipEntity(OOAIPrivate).

Definition at line 1 of file ShipEntityAI.m.

2884 :(ShipEntity *)other
2885{
2886 [self setFoundTarget:[other primaryTarget]];
2887 if ([self isPolice])
2888 {
2889 [(ShipEntity*)[self foundTarget] markAsOffender:8 withReason:kOOLegalStatusReasonDistressCall]; // you have been warned!!
2890 }
2891
2892 NSString *context = nil;
2893#ifndef NDEBUG
2894 context = [NSString stringWithFormat:@"%@ broadcastDistressMessage", [other shortDescription]];
2895#endif
2896 [shipAI reactToMessage:@"ACCEPT_DISTRESS_CALL" context:context];
2897
2898}

◆ accuracy

- (GLfloat) accuracy

◆ activateCloakingDevice

- (BOOL) activateCloakingDevice

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12366{
12367 if (![self hasCloakingDevice] || cloaking_device_active) return cloaking_device_active; // no changes.
12368
12370 if (cloaking_device_active) [self doScriptEvent:OOJSID("shipCloakActivated")];
12372}
#define CLOAKING_DEVICE_START_ENERGY
Definition ShipEntity.h:49
GLfloat maxEnergy
Definition Entity.h:143
GLfloat energy
Definition Entity.h:142
unsigned cloaking_device_active
Definition ShipEntity.h:265
BOOL hasCloakingDevice()

◆ addCargo:

- (BOOL) addCargo: (NSArray *) some_cargo

Definition at line 7619 of file ShipEntity.m.

8456 :(NSArray *) some_cargo
8457{
8458 if ([cargo count] + [some_cargo count] > [self maxAvailableCargoSpace])
8459 {
8460 return NO;
8461 }
8462 else
8463 {
8464 [cargo addObjectsFromArray:some_cargo];
8465 return YES;
8466 }
8467}
unsigned count
NSMutableArray * cargo
Definition ShipEntity.h:361
OOCargoQuantity maxAvailableCargoSpace()

◆ addCollisionException:

- (void) addCollisionException: (ShipEntity *) ship

Definition at line 9593 of file ShipEntity.m.

11128 :(ShipEntity *)ship
11129{
11131 {
11132 // Allocate lazily for the benefit of the ships that never need this.
11133 _collisionExceptions = [[OOWeakSet alloc] init];
11134 }
11135 [_collisionExceptions addObject:ship];
11136}
OOWeakSet * _collisionExceptions
Definition ShipEntity.h:477

Referenced by ShipAddCollisionException().

+ Here is the caller graph for this function:

◆ addDefenseTarget:

- (BOOL) addDefenseTarget: (Entity *) target

Definition at line 9593 of file ShipEntity.m.

11177 :(Entity *)target
11178{
11179 if ([self defenseTargetCount] >= MAX_TARGETS)
11180 {
11181 return NO;
11182 }
11183 // primary target can be a wormhole, defense targets shouldn't be
11184 if (target == nil || [self isDefenseTarget:target] || ![target isShip])
11185 {
11186 return NO;
11187 }
11188 if (_defenseTargets == nil)
11189 {
11190 // Allocate lazily for the benefit of the ships that never get in fights.
11191 _defenseTargets = [[OOWeakSet alloc] init];
11192 }
11193
11194 [_defenseTargets addObject:target];
11195 return YES;
11196}
#define MAX_TARGETS
Definition ShipEntity.h:36
unsigned isShip
Definition Entity.h:91
NSUInteger defenseTargetCount()
OOWeakSet * _defenseTargets
Definition ShipEntity.h:474

◆ addEquipmentItem:inContext:

- (BOOL) addEquipmentItem: (NSString *) equipmentKey
inContext: (NSString *) context 

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3531 :(NSString *)equipmentKey inContext:(NSString *)context
3532{
3533 return [self addEquipmentItem:equipmentKey withValidation:YES inContext:context];
3534}

◆ addEquipmentItem:withValidation:inContext:

- (BOOL) addEquipmentItem: (NSString *) equipmentKey
withValidation: (BOOL) validateAddition
inContext: (NSString *) context 

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3537 :(NSString *)equipmentKey withValidation:(BOOL)validateAddition inContext:(NSString *)context
3538{
3539 OOEquipmentType *eqType = nil;
3540 NSString *lcEquipmentKey = [equipmentKey lowercaseString];
3541 NSString *damagedKey;
3542 BOOL isEqThargon = [lcEquipmentKey hasSuffix:@"thargon"] || [lcEquipmentKey hasPrefix:@"thargon"];
3543 BOOL isRepairedEquipment = NO;
3544
3545 if([lcEquipmentKey isEqualToString:@"thargon"]) equipmentKey = @"EQ_THARGON";
3546
3547 // canAddEquipment always checks if the undamaged version is equipped.
3548 if (validateAddition == YES && ![self canAddEquipment:equipmentKey inContext:context]) return NO;
3549
3550 if ([equipmentKey hasSuffix:@"_DAMAGED"])
3551 {
3552 eqType = [OOEquipmentType equipmentTypeWithIdentifier:[equipmentKey substringToIndex:[equipmentKey length] - [@"_DAMAGED" length]]];
3553 }
3554 else
3555 {
3556 eqType = [OOEquipmentType equipmentTypeWithIdentifier:equipmentKey];
3557 // in case we have the damaged version!
3558 if (![eqType canCarryMultiple])
3559 {
3560 damagedKey = [equipmentKey stringByAppendingString:@"_DAMAGED"];
3561 if ([_equipment containsObject:damagedKey])
3562 {
3563 [_equipment removeObject:damagedKey];
3564 isRepairedEquipment = YES;
3565 }
3566 }
3567 }
3568
3569 // does this equipment actually exist?
3570 if (eqType == nil) return NO;
3571
3572 // special cases
3573 if ([eqType isMissileOrMine] || ([self isThargoid] && isEqThargon))
3574 {
3575 if (missiles >= max_missiles) return NO;
3576
3577 missile_list[missiles] = eqType;
3578 missiles++;
3579 return YES;
3580 }
3581
3582 // don't add any thargons to non-thargoid ships.
3583 if(isEqThargon) return NO;
3584
3585 // we can theoretically add a damaged weapon, but not a working one.
3586 if([equipmentKey hasPrefix:@"EQ_WEAPON"] && ![equipmentKey hasSuffix:@"_DAMAGED"])
3587 {
3588 return NO;
3589 }
3590 // end special cases
3591
3592 if (_equipment == nil) _equipment = [[NSMutableArray alloc] init];
3593
3594 if (![equipmentKey isEqualToString:@"EQ_PASSENGER_BERTH"] && !isRepairedEquipment)
3595 {
3596 // Add to equipment_weight with all other equipment.
3597 equipment_weight += [eqType requiredCargoSpace];
3599 {
3600 // should not even happen with old save games. Reject equipment now.
3601 equipment_weight -= [eqType requiredCargoSpace];
3602 return NO;
3603 }
3604 }
3605
3606
3607 if (!isPlayer)
3608 {
3609 if ([equipmentKey isEqual:@"EQ_CARGO_BAY"])
3610 {
3612 }
3613 else if([equipmentKey isEqualToString:@"EQ_SHIELD_BOOSTER"])
3614 {
3615 maxEnergy += 256.0f;
3616 }
3617 if([equipmentKey isEqualToString:@"EQ_SHIELD_ENHANCER"])
3618 {
3619 maxEnergy += 256.0f;
3620 energy_recharge_rate *= 1.5;
3621 }
3622 }
3623 // add the equipment
3624 [_equipment addObject:equipmentKey];
3625 [self doScriptEvent:OOJSID("equipmentAdded") withArgument:equipmentKey];
3626 return YES;
3627}
OOEquipmentType * equipmentTypeWithIdentifier:(NSString *identifier)
NSMutableArray * _equipment
Definition ShipEntity.h:461
unsigned missiles
Definition ShipEntity.h:319
unsigned max_missiles
Definition ShipEntity.h:320
OOEquipmentType * missile_list[SHIPENTITY_MAX_MISSILES]
Definition ShipEntity.h:434
GLfloat energy_recharge_rate
Definition ShipEntity.h:302
OOCargoQuantity max_cargo
Definition ShipEntity.h:295
OOCargoQuantity extra_cargo
Definition ShipEntity.h:296
OOCargoQuantity equipment_weight
Definition ShipEntity.h:297
BOOL isThargoid()

Referenced by ShipAwardEquipment(), and ShipSetEquipmentStatus().

+ Here is the caller graph for this function:

◆ addFoundTargetAsDefenseTarget

- (void) addFoundTargetAsDefenseTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1156{
1157 Entity* fTarget = [self foundTarget];
1158 if (fTarget != nil)
1159 {
1160 if ([fTarget isShip] && ![(ShipEntity *)fTarget isFriendlyTo:self])
1161 {
1162 [self addDefenseTarget:fTarget];
1163 }
1164 }
1165}

◆ addFuel:

- (void) addFuel: (NSString *) fuel_number
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2560 :(NSString*) fuel_number
2561{
2562 [self setFuel:[self fuel] + [fuel_number intValue] * 10];
2563}

◆ addImpactMoment:fraction:

- (void) addImpactMoment: (Vector) moment
fraction: (GLfloat) howmuch 

Definition at line 9593 of file ShipEntity.m.

12855 :(Vector) moment fraction:(GLfloat) howmuch
12856{
12857 velocity = vector_add(velocity, vector_multiply_scalar(moment, howmuch / mass));
12858}
GLfloat mass
Definition Entity.h:146
Vector velocity()

◆ addPrimaryAggressorAsDefenseTarget

- (void) addPrimaryAggressorAsDefenseTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

980{
981 Entity *primeAggressor = [self primaryAggressor];
982 if (!primeAggressor)
983 return;
984 if ([self isDefenseTarget:primeAggressor])
985 return;
986
987 if ([primeAggressor isShip] && ![(ShipEntity*)primeAggressor isFriendlyTo:self])
988 {
989 [self addDefenseTarget:primeAggressor];
990 }
991}

◆ addRole:

- (void) addRole: (NSString *) role

Definition at line 6496 of file ShipEntity.m.

7266 :(NSString *)role
7267{
7268 [self addRole:role withProbability:0.0f];
7269}

◆ addRole:withProbability:

- (void) addRole: (NSString *) role
withProbability: (float) probability 

Definition at line 6496 of file ShipEntity.m.

7272 :(NSString *)role withProbability:(float)probability
7273{
7274 if (![self hasRole:role])
7275 {
7276 OORoleSet *newRoles = nil;
7277 if (roleSet != nil) newRoles = [roleSet roleSetWithAddedRole:role probability:probability];
7278 else newRoles = [OORoleSet roleSetWithRole:role probability:probability];
7279 if (newRoles != nil)
7280 {
7281 [roleSet release];
7282 roleSet = [newRoles retain];
7283 }
7284 }
7285}
instancetype roleSetWithRole:probability:(NSString *role,[probability] float probability)
Definition OORoleSet.m:50
OORoleSet * roleSet
Definition ShipEntity.h:332

◆ addSubEntity:

- (void) addSubEntity: (Entity<OOSubEntity> *) sub
implementation

Provided by category ShipEntity(Private).

Definition at line 6496 of file ShipEntity.m.

6707 :(Entity<OOSubEntity> *)sub
6708{
6709 if (sub == nil) return;
6710
6711 if (subEntities == nil) subEntities = [[NSMutableArray alloc] init];
6712 sub->isSubEntity = YES;
6713 // Order matters - need consistent state in setOwner:. -- Ahruman 2008-04-20
6714 [subEntities addObject:sub];
6715 [sub setOwner:self];
6716
6717 [self addSubentityToCollisionRadius:sub];
6718}
void setOwner:(Entity *ent)
Definition Entity.m:576
NSMutableArray * subEntities
Definition ShipEntity.h:433

◆ addSubentityToCollisionRadius:

- (void) addSubentityToCollisionRadius: (Entity<OOSubEntity> *) subent
implementation

Provided by category ShipEntity(Private).

Definition at line 2093 of file ShipEntity.m.

2256 :(Entity<OOSubEntity> *)subent
2257{
2258 if (!subent) return;
2259
2260 double distance = HPmagnitude([subent position]) + [subent findCollisionRadius];
2261 if ([subent isKindOfClass:[ShipEntity class]]) // Solid subentity
2262 {
2263 if (distance > collision_radius)
2264 {
2265 collision_radius = distance;
2266 }
2267
2268 mass += [subent mass];
2269 }
2270 if (distance > _profileRadius)
2271 {
2272 _profileRadius = distance;
2273 }
2274}
GLfloat collision_radius
Definition Entity.h:111
GLfloat _profileRadius
Definition ShipEntity.h:479

◆ addTarget:

- (void) addTarget: (Entity *) targetEntity

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

10058 :(Entity *) targetEntity
10059{
10060 if (targetEntity == self) return;
10061 if (targetEntity != nil)
10062 {
10064 _primaryTarget = [targetEntity weakRetain];
10065 [self startTrackingCurve];
10066 }
10067
10068 [[self shipSubEntityEnumerator] makeObjectsPerformSelector:@selector(addTarget:) withObject:targetEntity];
10069 if (![self isSubEntity]) [self doScriptEvent:OOJSID("shipTargetAcquired") withArgument:targetEntity];
10070}
#define DESTROY(x)
Definition OOCocoa.h:77
OOWeakReference * _primaryTarget
Definition ShipEntity.h:437

◆ adjustMissedShots:

- (void) adjustMissedShots: (int) delta

Definition at line 9593 of file ShipEntity.m.

12068 :(int) delta
12069{
12070 if ([self isSubEntity])
12071 {
12072 [[self owner] adjustMissedShots:delta];
12073 }
12074 else
12075 {
12076 _missed_shots += delta;
12077 if (_missed_shots < 0)
12078 {
12079 _missed_shots = 0;
12080 }
12081 }
12082}
int _missed_shots
Definition ShipEntity.h:376
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque

◆ adjustVelocity:

- (void) adjustVelocity: (Vector) xVel

Reimplemented in StationEntity.

Definition at line 9593 of file ShipEntity.m.

12849 :(Vector) xVel
12850{
12851 velocity = vector_add(velocity, xVel);
12852}

◆ afterburnerFactor

- (float) afterburnerFactor

Definition at line 2093 of file ShipEntity.m.

4096{
4098}
GLfloat afterburner_speed_factor
Definition ShipEntity.h:292

◆ afterburnerRate

- (float) afterburnerRate

Definition at line 2093 of file ShipEntity.m.

4102{
4103 return afterburner_rate;
4104}
GLfloat afterburner_rate
Definition ShipEntity.h:291

◆ aftWeaponOffset

- (NSArray *) aftWeaponOffset

◆ ai_debugMessage:

- (void) ai_debugMessage: (NSString *) message
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2650 :(NSString *)message
2651{
2652 NSString *desc = [NSString stringWithFormat:@"%@ %d", [self name], [self universalID]];
2653 if ([self isPlayer]) desc = @"player autopilot";
2654 OOLog(@"ai.takeAction.debugMessage", @"DEBUG: AI MESSAGE from %@: %@", desc, message);
2655}

◆ ai_throwSparks

- (void) ai_throwSparks
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2639{
2640 [self setThrowSparks:YES];
2641}

◆ alertCondition

- (OOAlertCondition) alertCondition

Reimplemented in PlayerEntity, and ProxyPlayerEntity.

Definition at line 14073 of file ShipEntity.m.

14746{
14747 if ([self status] == STATUS_DOCKED)
14748 {
14750 }
14751 if ([self hasHostileTarget] || energy < maxEnergy / 4)
14752 {
14753 return ALERT_CONDITION_RED;
14754 }
14756}
@ ALERT_CONDITION_RED
Definition ShipEntity.h:178
@ ALERT_CONDITION_YELLOW
Definition ShipEntity.h:177
@ ALERT_CONDITION_DOCKED
Definition ShipEntity.h:175
BOOL hasHostileTarget()

References SCANNER_MAX_RANGE2, and UNIVERSE.

◆ allDefenseTargets

- (NSArray *) allDefenseTargets

Definition at line 9593 of file ShipEntity.m.

11166{
11167 return [_defenseTargets allObjects];
11168}

◆ applyAttitudeChanges:

- (void) applyAttitudeChanges: (double) delta_t

Reimplemented in PlayerEntity.

Definition at line 6496 of file ShipEntity.m.

6830 :(double) delta_t
6831{
6832 [self applyRoll:flightRoll*delta_t climb:flightPitch*delta_t andYaw:flightYaw*delta_t];
6833}

◆ applyRoll:andClimb:

- (void) applyRoll: (GLfloat) roll1
andClimb: (GLfloat) climb1 
implementation

Reimplemented from Entity.

Reimplemented in PlayerEntity.

Definition at line 6496 of file ShipEntity.m.

6797 :(GLfloat) roll1 andClimb:(GLfloat) climb1
6798{
6799 Quaternion q1 = kIdentityQuaternion;
6800
6801 if (!roll1 && !climb1 && !hasRotated) return;
6802
6803 if (roll1) quaternion_rotate_about_z(&q1, -roll1);
6804 if (climb1) quaternion_rotate_about_x(&q1, -climb1);
6805
6807 [self orientationChanged];
6808}
void quaternion_rotate_about_x(Quaternion *quat, OOScalar angle)
void quaternion_rotate_about_z(Quaternion *quat, OOScalar angle)
const Quaternion kIdentityQuaternion
Quaternion quaternion_multiply(Quaternion q1, Quaternion q2)
unsigned hasRotated
Definition Entity.h:97
Quaternion orientation
Definition Entity.h:114

◆ applyRoll:climb:andYaw:

- (void) applyRoll: (GLfloat) roll1
climb: (GLfloat) climb1
andYaw: (GLfloat) yaw1 
implementation

Reimplemented from Entity.

Definition at line 6496 of file ShipEntity.m.

6811 :(GLfloat) roll1 climb:(GLfloat) climb1 andYaw:(GLfloat) yaw1
6812{
6813 if ((roll1 == 0.0)&&(climb1 == 0.0)&&(yaw1 == 0.0)&&(!hasRotated))
6814 return;
6815
6816 Quaternion q1 = kIdentityQuaternion;
6817
6818 if (roll1)
6819 quaternion_rotate_about_z(&q1, -roll1);
6820 if (climb1)
6821 quaternion_rotate_about_x(&q1, -climb1);
6822 if (yaw1)
6823 quaternion_rotate_about_y(&q1, -yaw1);
6824
6826 [self orientationChanged];
6827}
void quaternion_rotate_about_y(Quaternion *quat, OOScalar angle)

◆ applySticks:

- (void) applySticks: (double) delta_t

Definition at line 7619 of file ShipEntity.m.

8143 :(double)delta_t
8144{
8145
8146 double rate1 = 2.0 * delta_t; //roll
8147 double rate2 = 4.0 * delta_t; //pitch
8148 double rate3 = 4.0 * delta_t; //yaw
8149
8150 if (((stick_roll > 0.0)&&(flightRoll < 0.0))||((stick_roll < 0.0)&&(flightRoll > 0.0)))
8151 rate1 *= 4.0; // much faster correction
8152 if (((stick_pitch > 0.0)&&(flightPitch < 0.0))||((stick_pitch < 0.0)&&(flightPitch > 0.0)))
8153 rate2 *= 4.0; // much faster correction
8154 if (((stick_yaw > 0.0)&&(flightYaw < 0.0))||((stick_yaw < 0.0)&&(flightYaw > 0.0)))
8155 rate3 *= 4.0; // much faster correction
8156
8158 {
8159 if (stick_roll == 0.0)
8160 rate1 *= 2.0; // faster correction
8161 if (stick_pitch == 0.0)
8162 rate2 *= 2.0; // faster correction
8163 if (stick_yaw == 0.0)
8164 rate3 *= 2.0; // faster correction
8165 }
8166
8167 // apply stick movement limits
8168 if (flightRoll < stick_roll - rate1)
8169 {
8170 flightRoll = flightRoll + rate1;
8171 }
8172 else if (flightRoll > stick_roll + rate1)
8173 {
8174 flightRoll = flightRoll - rate1;
8175 }
8176 else
8177 {
8179 }
8180
8181 if (flightPitch < stick_pitch - rate2)
8182 {
8183 flightPitch = flightPitch + rate2;
8184 }
8185 else if (flightPitch > stick_pitch + rate2)
8186 {
8187 flightPitch = flightPitch - rate2;
8188 }
8189 else
8190 {
8192 }
8193
8194 if (flightYaw < stick_yaw - rate3)
8195 {
8196 flightYaw = flightYaw + rate3;
8197 }
8198 else if (flightYaw > stick_yaw + rate3)
8199 {
8200 flightYaw = flightYaw - rate3;
8201 }
8202 else
8203 {
8205 }
8206
8207}
#define COMBAT_AI_TRACKS_CLOSER
Definition ShipEntity.h:131
GLfloat stick_pitch
Definition ShipEntity.h:209
GLfloat stick_yaw
Definition ShipEntity.h:210
GLfloat flightPitch
Definition ShipEntity.h:370
GLfloat accuracy
Definition ShipEntity.h:373
GLfloat stick_roll
Definition ShipEntity.h:208
GLfloat flightRoll
Definition ShipEntity.h:369
GLfloat flightYaw
Definition ShipEntity.h:371

◆ applyThrust:

- (void) applyThrust: (double) delta_t

Definition at line 6496 of file ShipEntity.m.

6737 :(double) delta_t
6738{
6739 GLfloat dt_thrust = SHIP_THRUST_FACTOR * thrust * delta_t;
6740 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
6741 BOOL isUsingAfterburner = (canBurn && (flightSpeed > maxFlightSpeed) && (desired_speed >= flightSpeed));
6742 float max_available_speed = maxFlightSpeed;
6743 if (canBurn) max_available_speed *= [self afterburnerFactor];
6744
6745 if (thrust)
6746 {
6747 // If we have Newtonian (non-thrust) velocity, brake it.
6748 GLfloat velmag = magnitude(velocity);
6749 if (velmag)
6750 {
6751 GLfloat vscale = fmaxf((velmag - dt_thrust) / velmag, 0.0f);
6752 scale_vector(&velocity, vscale);
6753 }
6754 }
6755
6756 if (behaviour == BEHAVIOUR_TUMBLE) return;
6757
6758 // check for speed
6759 if (desired_speed > max_available_speed)
6760 desired_speed = max_available_speed;
6761
6763 {
6764 [self decrease_flight_speed: dt_thrust];
6766 }
6768 {
6769 [self increase_flight_speed: dt_thrust];
6771 }
6772 [self moveForward: delta_t*flightSpeed];
6773
6774 // burn fuel at the appropriate rate
6775 if (isUsingAfterburner) // no fuelconsumption on slowdown
6776 {
6778 while (fuel_accumulator < 0.0)
6779 {
6780 fuel--;
6781 fuel_accumulator += 1.0;
6782 }
6783 }
6784}
#define MIN_FUEL
Definition ShipEntity.h:102
#define SHIP_THRUST_FACTOR
Definition ShipEntity.h:44
GLfloat flightSpeed
Definition ShipEntity.h:368
OOFuelQuantity fuel
Definition ShipEntity.h:288
GLfloat fuel_accumulator
Definition ShipEntity.h:289

◆ approachAspectToPrimaryTarget

- (double) approachAspectToPrimaryTarget

Definition at line 9593 of file ShipEntity.m.

11258{
11259 Vector delta;
11260 Entity *target = [self primaryTarget];
11261 if (target == nil || ![target isShip]) // leave now!
11262 {
11263 return 0.0;
11264 }
11265 ShipEntity *ship_target = (ShipEntity *)target;
11266
11267 delta = HPVectorToVector(HPvector_subtract(position, target->position));
11268
11269 return dot_product(vector_normal(delta), ship_target->v_forward);
11270}
Vector v_forward
Definition ShipEntity.h:200

◆ AuthorityPredicate

+ (static BOOL) AuthorityPredicate (Entity *) entity
(void *) parameter 
implementation

Definition at line 14073 of file ShipEntity.m.

14074{
14075 ShipEntity *victim = parameter;
14076
14077 // Select main station, if victim is in aegis
14078 if (entity == [UNIVERSE station] && [victim withinStationAegis])
14079 {
14080 return YES;
14081 }
14082
14083 // Select police units in typical scanner range
14084 if ([entity scanClass] == CLASS_POLICE &&
14085 HPdistance2([victim position], [entity position]) < SCANNER_MAX_RANGE2)
14086 {
14087 return YES;
14088 }
14089
14090 // Reject others
14091 return NO;
14092}
#define SCANNER_MAX_RANGE2
Definition Entity.h:52
#define UNIVERSE
Definition Universe.h:833
OOScanClass scanClass()
BOOL withinStationAegis()

◆ availableCargoSpace

- (OOCargoQuantity) availableCargoSpace

Definition at line 7619 of file ShipEntity.m.

8381{
8382 // OOCargoQuantity is unsigned, we need to check for underflows.
8383 if (EXPECT_NOT([self cargoQuantityOnBoard] + equipment_weight >= max_cargo)) return 0;
8384 return [self maxAvailableCargoSpace] - [self cargoQuantityOnBoard];
8385}
#define EXPECT_NOT(x)
return self
OOCargoQuantity cargoQuantityOnBoard()

Referenced by ShipAwardEquipment(), and ShipSetProperty().

+ Here is the caller graph for this function:

◆ avoidCollision

- (void) avoidCollision

Definition at line 6496 of file ShipEntity.m.

6837{
6838 if (scanClass == CLASS_MISSILE)
6839 return; // missiles are SUPPOSED to collide!
6840
6841 ShipEntity* prox_ship = (ShipEntity*)[self proximityAlert];
6842
6843 if (prox_ship)
6844 {
6846 {
6847 [previousCondition release];
6849 }
6850
6851 previousCondition = [[NSMutableDictionary dictionaryWithCapacity:5] retain];
6852
6853 [previousCondition oo_setInteger:behaviour forKey:@"behaviour"];
6854 if ([self primaryTarget] != nil)
6855 {
6856 // must use the weak ref here to prevent potential over-retention
6857 [previousCondition setObject:[[self primaryTarget] weakSelf] forKey:@"primaryTarget"];
6858 }
6859 [previousCondition oo_setFloat:desired_range forKey:@"desired_range"];
6860 [previousCondition oo_setFloat:desired_speed forKey:@"desired_speed"];
6861 [previousCondition oo_setHPVector:_destination forKey:@"destination"];
6862
6863 _destination = [prox_ship position];
6864 _destination = OOHPVectorInterpolate(position, [prox_ship position], 0.5); // point between us and them
6865
6867
6868 behaviour = BEHAVIOUR_AVOID_COLLISION;
6869 pitching_over = YES;
6870 }
6871}
#define PROXIMITY_AVOID_DISTANCE_FACTOR
Definition Universe.h:109
HPVector _destination
Definition ShipEntity.h:203
NSMutableDictionary * previousCondition
Definition ShipEntity.h:353
GLfloat desired_range
Definition ShipEntity.h:205
Entity * proximityAlert()
unsigned pitching_over
Definition ShipEntity.h:253

◆ ballTrackLeadingTarget:atTarget:

- (double) ballTrackLeadingTarget: (double) delta_t
atTarget: (Entity *) target 

Definition at line 9593 of file ShipEntity.m.

10330 :(double) delta_t atTarget:(Entity *)target
10331{
10332 if (!target)
10333 {
10334 return -2.0; // no target
10335 }
10336
10337 Vector vector_to_target;
10338 Vector axis_to_track_by;
10340 Vector my_ref = reference;
10341 double aim_cos, ref_cos;
10342 Vector leading = [target velocity];
10343
10344 // need to get vector to target in terms of this entities coordinate system
10345 HPVector my_position = [self absolutePositionForSubentity];
10346 vector_to_target = HPVectorToVector(HPvector_subtract([target position], my_position));
10347 // this is in absolute coordinates, so now rotate it
10348
10349 Entity *last = nil;
10350 Entity *father = [self parentEntity];
10351
10352 Quaternion q = kIdentityQuaternion;
10353 while ((father)&&(father != last) && (father != NO_TARGET))
10354 {
10355 /* Fix orientation */
10356 Quaternion fo = [father normalOrientation];
10357 fo.w = -fo.w;
10358 /* The below code works for player turrets where the
10359 * orientation is different, but not for NPC turrets. Taking
10360 * the normal orientation with -w works: there is probably a
10361 * neater way which someone who understands quaternions can
10362 * find, but this works well enough for 1.82 - CIM */
10363 q = quaternion_multiply(q,quaternion_conjugate(fo));
10364 last = father;
10365 if (![last isSubEntity]) break;
10366 father = [father owner];
10367 }
10368 q = quaternion_conjugate(q);
10369 // q now contains the rotation to the turret's reference system
10370
10371 vector_to_target = quaternion_rotate_vector(q,vector_to_target);
10372
10373 leading = quaternion_rotate_vector(q,leading);
10374 // rotate the vector to target and its velocity
10375
10376 if (magnitude(vector_to_target) > weaponRange * 1.01)
10377 {
10378 return -2.0; // out of range
10379 }
10380
10381 float lead = magnitude(vector_to_target) / TURRET_SHOT_SPEED;
10382
10383 vector_to_target = vector_add(vector_to_target, vector_multiply_scalar(leading, lead));
10384 vector_to_target = vector_normal_or_fallback(vector_to_target, kBasisZVector);
10385
10386 // do the tracking!
10387 aim_cos = dot_product(vector_to_target, my_aim);
10388 ref_cos = dot_product(vector_to_target, my_ref);
10389
10390
10391 if (ref_cos > TURRET_MINIMUM_COS) // target is forward of self
10392 {
10393 axis_to_track_by = cross_product(vector_to_target, my_aim);
10394 }
10395 else
10396 {
10397 return -2.0; // target is out of fire arc
10398 }
10399
10400 quaternion_rotate_about_axis(&orientation, axis_to_track_by, thrust * delta_t);
10401 [self orientationChanged];
10402
10403 [self setStatus:STATUS_ACTIVE];
10404
10405 return aim_cos;
10406}
Vector vector_forward_from_quaternion(Quaternion quat)
void quaternion_rotate_about_axis(Quaternion *quat, Vector axis, OOScalar angle)
#define TURRET_MINIMUM_COS
Definition ShipEntity.h:42
#define TURRET_SHOT_SPEED
Definition ShipEntity.h:80
Vector velocity
Definition Entity.h:140
GLfloat weaponRange
Definition ShipEntity.h:311
Vector reference
Definition ShipEntity.h:340

◆ beaconCode

- (NSString *) beaconCode
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1547{
1548 return _beaconCode;
1549}
NSString * _beaconCode
Definition ShipEntity.h:484

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ beaconDrawable

- (id< OOHUDBeaconIcon >) beaconDrawable
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1602{
1603 if (_beaconDrawable == nil)
1604 {
1605 NSString *beaconCode = [self beaconCode];
1606 NSUInteger length = [beaconCode length];
1607
1608 if (length > 1)
1609 {
1610 NSArray *iconData = [[UNIVERSE descriptions] oo_arrayForKey:beaconCode];
1611 if (iconData != nil) _beaconDrawable = [[OOPolygonSprite alloc] initWithDataArray:iconData outlineWidth:0.5 name:beaconCode];
1612 }
1613
1614 if (_beaconDrawable == nil)
1615 {
1616 if (length > 0) _beaconDrawable = [[beaconCode substringToIndex:1] retain];
1617 else _beaconDrawable = @"";
1618 }
1619 }
1620
1621 return _beaconDrawable;
1622}
NSString * beaconCode()
id< OOHUDBeaconIcon > _beaconDrawable
Definition ShipEntity.h:488

◆ beaconLabel

- (NSString *) beaconLabel
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1572{
1573 return _beaconLabel;
1574}
NSString * _beaconLabel
Definition ShipEntity.h:485

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ becomeEnergyBlast

- (void) becomeEnergyBlast

Reimplemented in StationEntity.

Definition at line 7619 of file ShipEntity.m.

9475{
9476 [UNIVERSE addEntity:[OOQuiriumCascadeEntity quiriumCascadeFromShip:self]];
9477 [self broadcastEnergyBlastImminent];
9478 [self noteKilledBy:nil damageType:kOODamageTypeCascadeWeapon];
9479 [UNIVERSE removeEntity:self];
9480}
instancetype quiriumCascadeFromShip:(ShipEntity *ship)

◆ becomeExplosion

- (void) becomeExplosion

Reimplemented in StationEntity.

Definition at line 7619 of file ShipEntity.m.

9171{
9172
9173 // check if we're destroying a subentity
9174 ShipEntity *parent = [self parentEntity];
9175 if (parent != nil)
9176 {
9177 ShipEntity *this_ship = [self retain];
9178 HPVector this_pos = [self absolutePositionForSubentity];
9179
9180 // remove this ship from its parent's subentity list
9181 [parent subEntityDied:self];
9182 [UNIVERSE addEntity:this_ship];
9183 [this_ship setPosition:this_pos];
9184 [this_ship release];
9185 if ([parent isPlayer])
9186 {
9187 // make the parent ship less reliable.
9188 [(PlayerEntity *)parent adjustTradeInFactorBy:-PLAYER_SHIP_SUBENTITY_TRADE_IN_VALUE];
9189 }
9190 }
9191
9192 HPVector xposition = position;
9193 NSUInteger i;
9194 Vector v;
9195 Quaternion q;
9196 int speed_low = 200;
9197 GLfloat n_alloys = sqrtf(sqrtf(mass / 6000.0f));
9198 NSUInteger numAlloys = 0;
9199 BOOL canReleaseSubWreckage = isWreckage && ([UNIVERSE detailLevel] >= DETAIL_LEVEL_EXTRAS);
9200
9201 if ([self status] == STATUS_DEAD)
9202 {
9203 [UNIVERSE removeEntity:self];
9204 return;
9205 }
9206 [self setStatus:STATUS_DEAD];
9207
9208 @try
9209 {
9210 if ([self isThargoid] && [roleSet hasRole:@"thargoid-mothership"]) [self broadcastThargoidDestroyed];
9211
9212 if (!suppressExplosion && ([self isVisible] || HPdistance2([self position], [PLAYER position]) < SCANNER_MAX_RANGE2))
9213 {
9214 if (!isWreckage && mass > 500000.0f && randf() < 0.25f) // big!
9215 {
9216 // draw an expanding ring
9218 [ring setVelocity:vector_multiply_scalar([self velocity], 0.25f)];
9219 [UNIVERSE addEntity:ring];
9220 }
9221
9222 BOOL add_debris = (UNIVERSE->n_entities < 0.95 * UNIVERSE_MAX_ENTITIES) &&
9223 ([UNIVERSE getTimeDelta] < 0.125); // FPS > 8
9224
9225
9226 // There are several parts to explosions, show only the main
9227 // explosion effect if UNIVERSE is almost full.
9228
9229 if (add_debris)
9230 {
9231 if ([UNIVERSE reducedDetail])
9232 {
9233 // Quick explosion effects for reduced detail mode
9234
9235 // 1. fast sparks
9236 [UNIVERSE addEntity:[OOSmallFragmentBurstEntity fragmentBurstFromEntity:self]];
9237 // 2. slow clouds
9238 [UNIVERSE addEntity:[OOBigFragmentBurstEntity fragmentBurstFromEntity:self]];
9239 // 3. flash
9240 [UNIVERSE addEntity:[OOFlashEffectEntity explosionFlashFromEntity:self]];
9241 /* This mode used to be the default for
9242 * cargo/munitions but this now must be explicitly
9243 * specified. */
9244 }
9245 else
9246 {
9247 NSString *explosionKey = @"oolite-default-ship-explosion";
9248 NSDictionary *explosion = nil;
9249 if (explosionType == nil)
9250 {
9251 explosion = [UNIVERSE explosionSetting:explosionKey];
9252 [UNIVERSE addEntity:[OOExplosionCloudEntity explosionCloudFromEntity:self withSettings:explosion]];
9253 // 3. flash
9254 [UNIVERSE addEntity:[OOFlashEffectEntity explosionFlashFromEntity:self]];
9255 }
9256 for (NSUInteger i=0;i<[explosionType count];i++)
9257 {
9258 explosionKey = [explosionType oo_stringAtIndex:i defaultValue:nil];
9259 if (explosionKey != nil)
9260 {
9261 // three special-case builtins
9262 if ([explosionKey isEqualToString:@"oolite-builtin-flash"])
9263 {
9264 [UNIVERSE addEntity:[OOFlashEffectEntity explosionFlashFromEntity:self]];
9265 }
9266 else if ([explosionKey isEqualToString:@"oolite-builtin-slowcloud"])
9267 {
9268 [UNIVERSE addEntity:[OOBigFragmentBurstEntity fragmentBurstFromEntity:self]];
9269 }
9270 else if ([explosionKey isEqualToString:@"oolite-builtin-fastspark"])
9271 {
9272 [UNIVERSE addEntity:[OOSmallFragmentBurstEntity fragmentBurstFromEntity:self]];
9273 }
9274 else
9275 {
9276 explosion = [UNIVERSE explosionSetting:explosionKey];
9277 [UNIVERSE addEntity:[OOExplosionCloudEntity explosionCloudFromEntity:self withSettings:explosion]];
9278 }
9279 }
9280 }
9281 // "fireball" explosion effect
9282
9283 }
9284 }
9285
9286 // If UNIVERSE is nearing limit for entities don't add to it!
9287 if (add_debris)
9288 {
9289 // we need to throw out cargo at this point.
9290 [self releaseCargoPodsDebris];
9291
9292 // Throw out rocks and alloys to be scooped up
9293 if ([self hasRole:@"asteroid"] || [self isBoulder])
9294 {
9295 if (!noRocks && (being_mined || randf() < 0.20))
9296 {
9297 NSString *defaultRole = @"boulder";
9298 float defaultSpeed = 50.0;
9299 if ([self isBoulder])
9300 {
9301 defaultRole = @"splinter";
9302 defaultSpeed = 20.0;
9303 if (likely_cargo == 0)
9304 {
9305 likely_cargo = 4; // compatibility with older boulders
9306 }
9307 }
9308 else if ([[self primaryAggressor] isPlayer])
9309 {
9310 [PLAYER addRoleForMining];
9311 }
9312 NSUInteger n_rocks = 2 + (Ranrot() % (likely_cargo + 1));
9313
9314 NSString *debrisRole = [[self shipInfoDictionary] oo_stringForKey:@"debris_role" defaultValue:defaultRole];
9315 for (i = 0; i < n_rocks; i++)
9316 {
9317 ShipEntity* rock = [UNIVERSE newShipWithRole:debrisRole]; // retain count = 1
9318 if (rock)
9319 {
9320 float r_speed = [rock maxFlightSpeed] > 0 ? 2.0 * [rock maxFlightSpeed] : defaultSpeed;
9321 float cr = (collision_radius < rock->collision_radius) ? collision_radius : 2 * rock->collision_radius;
9322 v.x = ((randf() * r_speed) - r_speed / 2);
9323 v.y = ((randf() * r_speed) - r_speed / 2);
9324 v.z = ((randf() * r_speed) - r_speed / 2);
9325 [rock setVelocity:vector_add(v,[self velocity])];
9326 HPVector rpos = HPvector_add(xposition,vectorToHPVector(vector_multiply_scalar(vector_normal(v),cr)));
9327 [rock setPosition:rpos];
9328
9330 [rock setOrientation:q];
9331
9332 [rock setTemperature:[self randomEjectaTemperature]];
9333 if ([self isBoulder])
9334 {
9335 [rock setScanClass: CLASS_CARGO];
9336 [rock setBounty: 0 withReason:kOOLegalStatusReasonSetup];
9337 // only make the rock have minerals if something isn't already defined for the rock
9338 if ([[rock shipInfoDictionary] oo_stringForKey:@"cargo_carried"] == nil)
9339 [rock setCommodity:@"minerals" andAmount: 1];
9340 }
9341 else
9342 {
9343 [rock setScanClass:CLASS_ROCK];
9344 [rock setIsBoulder:YES];
9345 }
9346 [UNIVERSE addEntity:rock]; // STATUS_IN_FLIGHT, AI state GLOBAL
9347 [rock release];
9348 }
9349 }
9350 }
9351 return;
9352 }
9353
9354 // throw out burning chunks of wreckage
9355 //
9356 if ((n_alloys && canFragment) || canReleaseSubWreckage)
9357 {
9358 NSUInteger n_wreckage = 0;
9359
9360 if (UNIVERSE->n_entities < 0.50 * UNIVERSE_MAX_ENTITIES)
9361 {
9362 // Create wreckage only when UNIVERSE is less than half full.
9363 // (condition set in r906 - was < 0.75 before) --Kaks 2011.10.17
9364 NSUInteger maxWrecks = 3;
9365 if (n_alloys == 0)
9366 {
9367 // must be sub-wreckage here
9368 n_wreckage = (mass > 600.0 && randf() < 0.2)?2:0;
9369 }
9370 else
9371 {
9372 n_wreckage = (n_alloys < maxWrecks)? floorf(randf()*(n_alloys+2)) : maxWrecks;
9373 }
9374 }
9375
9376 for (i = 0; i < n_wreckage; i++)
9377 {
9378 Vector r1 = [octree randomPoint];
9379 Vector dir = quaternion_rotate_vector([self normalOrientation], r1);
9380 HPVector rpos = HPvector_add(vectorToHPVector(dir), xposition);
9381 GLfloat lifetime = 750.0 * randf() + 250.0 * i + 100.0;
9382 ShipEntity *wreck = [UNIVERSE addWreckageFrom:self withRole:@"wreckage" at:rpos scale:1.0 lifetime:lifetime/2];
9383
9384 [wreck setVelocity:vector_add([wreck velocity],vector_multiply_scalar(vector_normal(dir),randf()*[wreck collisionRadius]))];
9385
9386 }
9387 n_alloys = randf() * n_alloys;
9388 }
9389 }
9390
9391 if (!canFragment)
9392 {
9393 n_alloys = 0.0;
9394 }
9395 // If UNIVERSE is almost full, don't create more than 1 piece of scrap metal.
9396 else if (!add_debris)
9397 {
9398 n_alloys = (n_alloys > 1.0) ? 1.0 : 0.0;
9399 }
9400
9401 // now convert to uint
9402 numAlloys = floorf(n_alloys);
9403
9404 // Throw out scrap metal
9405 //
9406 for (i = 0; i < numAlloys; i++)
9407 {
9408 ShipEntity* plate = [UNIVERSE newShipWithRole:@"alloy"]; // retain count = 1
9409 if (plate)
9410 {
9411 HPVector rpos = xposition;
9413 rpos.x += rrand.x; rpos.y += rrand.y; rpos.z += rrand.z;
9414 rpos.x += (ranrot_rand() % 7) - 3;
9415 rpos.y += (ranrot_rand() % 7) - 3;
9416 rpos.z += (ranrot_rand() % 7) - 3;
9417 [plate setPosition:rpos];
9418 v.x = 0.1 *((ranrot_rand() % speed_low) - speed_low / 2);
9419 v.y = 0.1 *((ranrot_rand() % speed_low) - speed_low / 2);
9420 v.z = 0.1 *((ranrot_rand() % speed_low) - speed_low / 2);
9421 [plate setVelocity:vector_add(v,[self velocity])];
9423 [plate setOrientation:q];
9424
9425 [plate setTemperature:[self randomEjectaTemperature]];
9426 [plate setScanClass: CLASS_CARGO];
9427 [plate setCommodity:@"alloys" andAmount:1];
9428 [UNIVERSE addEntity:plate]; // STATUS_IN_FLIGHT, AI state GLOBAL
9429
9430 [plate release];
9431 }
9432 }
9433 }
9434
9435 // Explode subentities.
9436 NSEnumerator *subEnum = nil;
9437 ShipEntity *se = nil;
9438 for (subEnum = [self shipSubEntityEnumerator]; (se = [subEnum nextObject]); )
9439 {
9440 [se setSuppressExplosion:suppressExplosion];
9441 [se becomeExplosion];
9442 }
9443 [self clearSubEntities];
9444
9445 // momentum from explosions
9446 if (!suppressExplosion)
9447 {
9449 [self dealMomentumWithinDesiredRange:0.125f * mass];
9450 }
9451
9452 if (self != PLAYER) // was if !isPlayer - but I think this may cause ghosts (Who's "I"? -- Ahruman)
9453 {
9454 if (isPlayer)
9455 {
9456 #ifndef NDEBUG
9457 OOLog(@"becomeExplosion.suspectedGhost.confirm", @"%@", @"Ship spotted with isPlayer set when not actually the player.");
9458 #endif
9459 isPlayer = NO;
9460 }
9461 }
9462 }
9463 @finally
9464 {
9465 if (self != PLAYER)
9466 {
9467 [UNIVERSE removeEntity:self];
9468 }
9469 }
9470}
void quaternion_set_random(Quaternion *quat)
float y
float x
@ DETAIL_LEVEL_EXTRAS
Definition OOTypes.h:247
@ UNIVERSE_MAX_ENTITIES
Definition OOTypes.h:193
Vector OORandomPositionInBoundingBox(BoundingBox bb)
Definition OOVector.m:121
#define PLAYER
void setVelocity:(Vector vel)
Definition Entity.m:757
void setOrientation:(Quaternion quat)
Definition Entity.m:725
GLfloat collisionRadius()
Definition Entity.m:905
void setScanClass:(OOScanClass sClass)
Definition Entity.m:799
BoundingBox boundingBox
Definition Entity.h:145
void setPosition:(HPVector posn)
Definition Entity.m:647
id fragmentBurstFromEntity:(Entity *entity)
instancetype explosionCloudFromEntity:withSettings:(Entity *entity,[withSettings] NSDictionary *settings)
instancetype explosionFlashFromEntity:(Entity *entity)
instancetype ringFromEntity:(Entity *sourceEntity)
id fragmentBurstFromEntity:(Entity *entity)
unsigned suppressExplosion
Definition ShipEntity.h:271
void setSuppressExplosion:(BOOL suppress)
unsigned noRocks
Definition ShipEntity.h:281
void setBounty:withReason:(OOCreditsQuantity amount,[withReason] OOLegalStatusReason reason)
NSDictionary * shipInfoDictionary()
unsigned isWreckage
Definition ShipEntity.h:269
Entity * primaryAggressor()
void subEntityDied:(ShipEntity *sub)
unsigned being_mined
Definition ShipEntity.h:257
OOCargoQuantity likely_cargo
Definition ShipEntity.h:294
NSEnumerator * shipSubEntityEnumerator()
void setTemperature:(GLfloat value)
void setIsBoulder:(BOOL flag)
BOOL isVisible()
BOOL isBoulder()
unsigned canFragment
Definition ShipEntity.h:268
void becomeExplosion()
void setCommodity:andAmount:(OOCommodityType co_type,[andAmount] OOCargoQuantity co_amount)
NSArray * explosionType
Definition ShipEntity.h:335
float randf(void)
unsigned Ranrot(void)
#define ranrot_rand()

◆ becomeLargeExplosion:

- (void) becomeLargeExplosion: (double) factor

Reimplemented in StationEntity.

Definition at line 9593 of file ShipEntity.m.

9644 :(double)factor
9645{
9646
9647 if ([self status] == STATUS_DEAD) return;
9648 [self setStatus:STATUS_DEAD];
9649
9650 @try
9651 {
9652 // two parts to the explosion:
9653 // 1. fast sparks
9654 float how_many = factor;
9655 while (how_many > 0.5f)
9656 {
9657 [UNIVERSE addEntity:[OOSmallFragmentBurstEntity fragmentBurstFromEntity:self]];
9658 how_many -= 1.0f;
9659 }
9660 // 2. slow clouds
9661 how_many = factor;
9662 while (how_many > 0.5f)
9663 {
9664 [UNIVERSE addEntity:[OOBigFragmentBurstEntity fragmentBurstFromEntity:self]];
9665 how_many -= 1.0f;
9666 }
9667
9668 [self releaseCargoPodsDebris];
9669
9670 NSEnumerator *subEnum = nil;
9671 ShipEntity *se = nil;
9672 for (subEnum = [self shipSubEntityEnumerator]; (se = [subEnum nextObject]); )
9673 {
9674 [se setSuppressExplosion:suppressExplosion];
9675 [se becomeExplosion];
9676 }
9677 [self clearSubEntities];
9678
9679 }
9680 @finally
9681 {
9682 if (!isPlayer) [UNIVERSE removeEntity:self];
9683 }
9684}

◆ becomeUncontrolledThargon

- (void) becomeUncontrolledThargon
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1751{
1752 int ent_count = UNIVERSE->n_entities;
1753 Entity** uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
1754 int i;
1755 for (i = 0; i < ent_count; i++) if (uni_entities[i]->isShip)
1756 {
1757 ShipEntity *other = (ShipEntity*)uni_entities[i];
1758 if ([other primaryTarget] == self)
1759 {
1760 [other removeTarget:self];
1761 }
1762 if ([other isDefenseTarget:self])
1763 {
1764 [other removeDefenseTarget:self];
1765 }
1766 }
1767 // now we're just a bunch of alien artefacts!
1768 scanClass = CLASS_CARGO;
1769 reportAIMessages = NO;
1770 [self setAITo:@"dumbAI.plist"];
1771 DESTROY(_primaryTarget);
1772 [self setSpeed: 0.0];
1773 [self setGroup:nil];
1774}
void removeTarget:(Entity *targetEntity)
void removeDefenseTarget:(Entity *target)

◆ behaviour

- (OOBehaviour) behaviour

◆ behaviour_attack_break_off_target:

- (void) behaviour_attack_break_off_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4371 :(double) delta_t
4372{
4373 if (![self canStillTrackPrimaryTarget])
4374 {
4375 [self noteLostTargetAndGoIdle];
4376 return;
4377 }
4378 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
4379 float max_available_speed = maxFlightSpeed;
4380 double range = [self rangeToPrimaryTarget];
4381 if (canBurn) max_available_speed *= [self afterburnerFactor];
4382
4383 desired_speed = max_available_speed;
4384
4385 Entity* target = [self primaryTarget];
4386
4388 {
4389 double target_speed = [target speed];
4390 if (desired_speed > target_speed * 3.0)
4391 {
4392 desired_speed = maxFlightSpeed; // don't overuse the injectors
4393 }
4394 }
4395
4396 if (cloakAutomatic) [self activateCloakingDevice];
4397 if ([self hasProximityAlertIgnoringTarget:NO])
4398 {
4399 [self avoidCollision];
4400 return;
4401 }
4402
4403 frustration += delta_t;
4404 if (frustration > 15.0 && accuracy >= COMBAT_AI_DOGFIGHTER && !canBurn)
4405 {
4407 }
4408 double aspect = [self approachAspectToPrimaryTarget];
4409 if (range > 3000.0 || ([target isShip] && [(ShipEntity*)target primaryTarget] != self) || frustration - floor(frustration) > fmin(1.6/max_flight_roll,aspect))
4410 {
4411 [self trackPrimaryTarget:delta_t:YES];
4412 }
4413 else
4414 {
4415// less useful at long range if not under direct fire
4416 [self evasiveAction:delta_t];
4417 }
4418
4420 {
4421 behaviour = BEHAVIOUR_ATTACK_TARGET;
4422 }
4423 else if (aspect < -0.75 && accuracy >= COMBAT_AI_DOGFIGHTER)
4424 {
4425 behaviour = BEHAVIOUR_ATTACK_SLOW_DOGFIGHT;
4426 }
4428 {
4429 frustration = 0.0;
4431 {
4432 behaviour = BEHAVIOUR_ATTACK_SLOW_DOGFIGHT;
4433 }
4434 else
4435 {
4436 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
4437 }
4438 }
4439
4440 flightYaw = 0.0;
4441}
#define COMBAT_AI_WEAPON_TEMP_READY
Definition ShipEntity.h:118
#define COMBAT_AI_DOGFIGHTER
Definition ShipEntity.h:129
#define COMBAT_OUT_RANGE_FACTOR
Definition ShipEntity.h:56
double speed()
Definition Entity.m:769
BOOL canStillTrackPrimaryTarget()
unsigned cloakAutomatic
Definition ShipEntity.h:267
GLfloat forward_weapon_temp
Definition ShipEntity.h:315
double approachAspectToPrimaryTarget()
GLfloat max_flight_roll
Definition ShipEntity.h:240

◆ behaviour_attack_broadside:

- (void) behaviour_attack_broadside: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4759 :(double) delta_t
4760{
4761 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
4762 float max_available_speed = maxFlightSpeed;
4763 double range = [self rangeToPrimaryTarget];
4764 if (canBurn) max_available_speed *= [self afterburnerFactor];
4765
4766 if (cloakAutomatic) [self activateCloakingDevice];
4767
4768 if (![self canStillTrackPrimaryTarget])
4769 {
4770 [self noteLostTargetAndGoIdle];
4771 return;
4772 }
4773
4774 desired_speed = max_available_speed;
4776 {
4777 behaviour = BEHAVIOUR_ATTACK_TARGET;
4778 }
4779 else
4780 {
4782 {
4784 {
4785 behaviour = BEHAVIOUR_ATTACK_BROADSIDE_RIGHT;
4786 [self setWeaponDataFromType:starboard_weapon_type];
4787 }
4788 else
4789 {
4790 behaviour = BEHAVIOUR_ATTACK_BROADSIDE_LEFT;
4791 [self setWeaponDataFromType:port_weapon_type];
4792 }
4793 }
4794 else
4795 {
4797 {
4798 behaviour = BEHAVIOUR_ATTACK_BROADSIDE_RIGHT;
4799 [self setWeaponDataFromType:starboard_weapon_type];
4800 }
4801 else
4802 {
4803 behaviour = BEHAVIOUR_ATTACK_BROADSIDE_LEFT;
4804 [self setWeaponDataFromType:port_weapon_type];
4805 }
4806 }
4807 jink = kZeroVector;
4808 if (weapon_damage == 0.0)
4809 { // safety in case side lasers no longer exist
4810 behaviour = BEHAVIOUR_ATTACK_TARGET;
4811 }
4812 else if (range > 0.9 * weaponRange)
4813 {
4814 behaviour = BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE;
4815 }
4816 }
4817
4818 frustration = 0.0; // behaviour changed, so reset frustration
4819
4820
4821
4822}
const Vector kZeroVector
Definition OOVector.m:28
#define COMBAT_BROADSIDE_IN_RANGE_FACTOR
Definition ShipEntity.h:55
BOOL isWeaponNone(OOWeaponType weapon)
GLfloat weapon_damage
Definition ShipEntity.h:309
Vector jink
Definition ShipEntity.h:338
GLfloat port_weapon_temp
Definition ShipEntity.h:315
GLfloat starboard_weapon_temp
Definition ShipEntity.h:315
OOWeaponType starboard_weapon_type
Definition ShipEntity.h:308
OOWeaponType port_weapon_type
Definition ShipEntity.h:307

◆ behaviour_attack_broadside_left:

- (void) behaviour_attack_broadside_left: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4825 :(double) delta_t
4826{
4827 [self behaviour_attack_broadside_target:delta_t leftside:YES];
4828}

◆ behaviour_attack_broadside_right:

- (void) behaviour_attack_broadside_right: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4831 :(double) delta_t
4832{
4833 [self behaviour_attack_broadside_target:delta_t leftside:NO];
4834}

◆ behaviour_attack_broadside_target:leftside:

- (void) behaviour_attack_broadside_target: (double) delta_t
leftside: (BOOL) leftside 

Definition at line 2093 of file ShipEntity.m.

4837 :(double) delta_t leftside:(BOOL) leftside
4838{
4839 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
4840 float max_available_speed = maxFlightSpeed;
4841 double range = [self rangeToPrimaryTarget];
4842 if (canBurn) max_available_speed *= [self afterburnerFactor];
4843 if ([self primaryTarget] == nil)
4844 {
4845 [self noteLostTargetAndGoIdle];
4846 return;
4847 }
4848 GLfloat currentWeaponRange = getWeaponRangeFromType(leftside?port_weapon_type:starboard_weapon_type);
4849 if (range > COMBAT_BROADSIDE_RANGE_FACTOR * currentWeaponRange)
4850 {
4851 behaviour = BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE;
4852 return;
4853 }
4854
4855// can get closer on broadsides since there's less risk of a collision
4856 if ((range < COMBAT_BROADSIDE_IN_RANGE_FACTOR * currentWeaponRange)||([self proximityAlert] != nil))
4857 {
4858 if (![self hasProximityAlertIgnoringTarget:YES])
4859 {
4860 behaviour = BEHAVIOUR_ATTACK_TARGET;
4861 }
4862 else
4863 {
4864 [self avoidCollision];
4865 return;
4866 }
4867 }
4868 else
4869 {
4870 if (![self canStillTrackPrimaryTarget])
4871 {
4872 [self noteLostTargetAndGoIdle];
4873 return;
4874 }
4875 }
4876 // control speed
4877 //
4878 BOOL isUsingAfterburner = canBurn && (flightSpeed > maxFlightSpeed);
4879 double slow_down_range = currentWeaponRange * COMBAT_WEAPON_RANGE_FACTOR * ((isUsingAfterburner)? 3.0 * [self afterburnerFactor] : 1.0);
4880// double target_speed = [target speed];
4881 if (range <= slow_down_range)
4882 desired_speed = fmin(0.8 * maxFlightSpeed, fmax((2.0-frustration)*maxFlightSpeed, 0.1 * maxFlightSpeed)); // within the weapon's range slow down to aim
4883 else
4884 desired_speed = max_available_speed; // use afterburner to approach
4885
4886 double last_success_factor = success_factor;
4887 success_factor = [self trackSideTarget:delta_t:leftside]; // do the actual piloting
4889 { // will probably have more luck with the other laser or picking a different attack method
4890 if (leftside)
4891 {
4893 {
4894 behaviour = BEHAVIOUR_ATTACK_BROADSIDE_RIGHT;
4895 }
4896 else
4897 {
4898 behaviour = BEHAVIOUR_ATTACK_TARGET;
4899 }
4900 }
4901 else
4902 {
4904 {
4905 behaviour = BEHAVIOUR_ATTACK_BROADSIDE_LEFT;
4906 }
4907 else
4908 {
4909 behaviour = BEHAVIOUR_ATTACK_TARGET;
4910 }
4911 }
4912 }
4913
4914/* FIXME: again, basically all of this next bit common with standard attack */
4915 if ((success_factor > 0.999)||(success_factor > last_success_factor))
4916 {
4917 frustration -= delta_t;
4918 if (frustration < 0.0)
4919 frustration = 0.0;
4920 }
4921 else
4922 {
4923 frustration += delta_t;
4924 if (frustration > 3.0) // 3s of frustration
4925 {
4926
4927 [self noteFrustration:@"BEHAVIOUR_ATTACK_BROADSIDE"];
4928 [self setEvasiveJink:1000.0];
4929 behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
4930 frustration = 0.0;
4932 }
4933 }
4934
4935 if (missiles) [self considerFiringMissile:delta_t];
4936
4937 if (cloakAutomatic) [self activateCloakingDevice];
4938 if (leftside)
4939 {
4940 [self firePortWeapon:range];
4941 }
4942 else
4943 {
4944 [self fireStarboardWeapon:range];
4945 }
4946
4947
4948
4950 {
4951 behaviour = BEHAVIOUR_ATTACK_TARGET;
4952 }
4953}
#define COMBAT_BROADSIDE_RANGE_FACTOR
Definition ShipEntity.h:57
#define COMBAT_AI_WEAPON_TEMP_USABLE
Definition ShipEntity.h:119
GLfloat getWeaponRangeFromType(OOWeaponType weapon_type)
#define COMBAT_WEAPON_RANGE_FACTOR
Definition ShipEntity.h:58
GLfloat weapon_temp
Definition ShipEntity.h:314
float afterburnerFactor()
GLfloat success_factor
Definition ShipEntity.h:349

◆ behaviour_attack_fly_from_target:

- (void) behaviour_attack_fly_from_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5470 :(double) delta_t
5471{
5472 double range = [self rangeToPrimaryTarget];
5473 double last_success_factor = success_factor;
5474 success_factor = range;
5475
5476 if ([self primaryTarget] == nil)
5477 {
5478 [self noteLostTargetAndGoIdle];
5479 return;
5480 }
5481 if (last_success_factor > success_factor) // our target is closing in.
5482 {
5483 frustration += delta_t;
5484 }
5485 else
5486 { // not getting away fast enough?
5487 frustration += delta_t / 4.0 ;
5488 }
5489
5490 if (frustration > 10.0)
5491 {
5492 if (randf() < 0.3) {
5493 desired_speed = maxFlightSpeed * (([self hasFuelInjection] && (fuel > MIN_FUEL)) ? [self afterburnerFactor] : 1);
5494 }
5495 else if (range > COMBAT_IN_RANGE_FACTOR * weaponRange && randf() < 0.3)
5496 {
5497 behaviour = BEHAVIOUR_ATTACK_TARGET;
5498 }
5499 GLfloat z = jink.z;
5500 if (randf() < 0.3)
5501 {
5502 z /= 2; // move the z-offset closer to the target to let him fly away from the target.
5503 desired_speed = flightSpeed * 2; // increase speed a bit.
5504 }
5505 [self setEvasiveJink:z];
5506
5507 frustration /= 2.0;
5508 }
5510 {
5511 ShipEntity* target = [self primaryTarget];
5512 double target_speed = [target speed];
5513 if (desired_speed > target_speed * 2.0)
5514 {
5515 desired_speed = maxFlightSpeed; // don't overuse the injectors
5516 }
5517 }
5518 else if (desired_speed < maxFlightSpeed * 0.5)
5519 {
5521 }
5522
5523 if (range > COMBAT_OUT_RANGE_FACTOR * weaponRange + 15.0 * jink.x ||
5524 flightSpeed > (scannerRange - range) * max_flight_pitch / 6.28)
5525 {
5526 jink = kZeroVector;
5527 behaviour = BEHAVIOUR_ATTACK_TARGET;
5528 frustration = 0.0;
5529 }
5530 [self trackPrimaryTarget:delta_t:YES];
5531
5532 if (missiles) [self considerFiringMissile:delta_t];
5533
5534 if (cloakAutomatic) [self activateCloakingDevice];
5535 if ([self hasProximityAlertIgnoringTarget:YES])
5536 [self avoidCollision];
5537
5539 {
5540 double aspect = [self approachAspectToPrimaryTarget];
5541 // if we're right in their gunsights, dodge!
5542 // need to dodge sooner if in aft sights
5543 if (aspect > 0.99999 || aspect < -0.999)
5544 {
5545 frustration = 0.0;
5546 behaviour = BEHAVIOUR_EVASIVE_ACTION;
5547 }
5548 }
5549
5550}
#define COMBAT_AI_FLEES_BETTER_2
Definition ShipEntity.h:134
#define COMBAT_IN_RANGE_FACTOR
Definition ShipEntity.h:54
GLfloat max_flight_pitch
Definition ShipEntity.h:241
GLfloat scannerRange
Definition ShipEntity.h:317

◆ behaviour_attack_fly_to_target:

- (void) behaviour_attack_fly_to_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5303 :(double) delta_t
5304{
5305 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
5306 float max_available_speed = maxFlightSpeed;
5307 double range = [self rangeToPrimaryTarget];
5308 if (canBurn) max_available_speed *= [self afterburnerFactor];
5309 if ([self primaryTarget] == nil)
5310 {
5311 [self noteLostTargetAndGoIdle];
5312 return;
5313 }
5314 Entity* rawTarget = [self primaryTarget];
5315 if (![rawTarget isShip])
5316 {
5317 // can't attack a wormhole
5318 [self noteLostTargetAndGoIdle];
5319 return;
5320 }
5321
5322 ShipEntity *target = (ShipEntity *)rawTarget;
5323 if ((range < COMBAT_IN_RANGE_FACTOR * weaponRange)||([self proximityAlert] != nil))
5324 {
5325 if (![self hasProximityAlertIgnoringTarget:YES])
5326 {
5327 behaviour = BEHAVIOUR_ATTACK_TARGET;
5328 }
5329 else
5330 {
5331 [self avoidCollision];
5332 return;
5333 }
5334 }
5335 else
5336 {
5337 if (![self canStillTrackPrimaryTarget])
5338 {
5339 [self noteLostTargetAndGoIdle];
5340 return;
5341 }
5342 }
5343
5344 // control speed
5345 //
5346 BOOL isUsingAfterburner = canBurn && (flightSpeed > maxFlightSpeed);
5347 BOOL closeQuickly = (canBurn && [target weaponRange] > weaponRange && range > weaponRange);
5348 double slow_down_range = weaponRange * COMBAT_WEAPON_RANGE_FACTOR * ((isUsingAfterburner)? 3.0 * [self afterburnerFactor] : 1.0);
5349 if (closeQuickly)
5350 {
5351 slow_down_range = weaponRange * COMBAT_OUT_RANGE_FACTOR;
5352 }
5353 double back_off_range = 10000 * COMBAT_OUT_RANGE_FACTOR * ((isUsingAfterburner)? 3.0 * [self afterburnerFactor] : 1.0);
5354 double target_speed = [target speed];
5355 double aspect = [self approachAspectToPrimaryTarget];
5356
5357 if (range <= slow_down_range)
5358 {
5359 if (range < back_off_range)
5360 {
5361 if (accuracy < COMBAT_AI_IS_SMART || ([target primaryTarget] == self && aspect > 0.8) || aim_tolerance*range > COMBAT_AI_CONFIDENCE_FACTOR)
5362 {
5363 if (accuracy >= COMBAT_AI_FLEES_BETTER && aspect > 0.8)
5364 {
5365 desired_speed = fmax(target_speed * 1.25, 0.8 * maxFlightSpeed);
5366 // stay at high speed if might be taking return fire
5367 }
5368 else
5369 {
5370 desired_speed = fmax(target_speed * 1.05, 0.25 * maxFlightSpeed); // within the weapon's range match speed
5371
5372 }
5373 }
5374 else
5375 { // smart, and not being shot at right now - slow down to attack
5376 desired_speed = fmax(0.1 * target_speed, 0.1 * maxFlightSpeed);
5377 }
5378 }
5379 else
5380 {
5381 if (accuracy < COMBAT_AI_IS_SMART || ([target isShip] && [(ShipEntity *)target primaryTarget] == self) || range > weaponRange / 2.0)
5382 {
5383 desired_speed = fmax(target_speed * 1.5, maxFlightSpeed);
5384 }
5385 else
5386 { // smart, and not being shot at right now - slow down to attack
5387 if (aspect > -0.25)
5388 {
5389 desired_speed = fmax(0.5 * target_speed, 0.5 * maxFlightSpeed);
5390 }
5391 else
5392 {
5393 desired_speed = fmax(1.25 * target_speed, 0.5 * maxFlightSpeed);
5394 }
5395 }
5396 }
5397 }
5398 else
5399 {
5400 if (closeQuickly)
5401 {
5402 desired_speed = max_available_speed; // use afterburner to approach
5403 }
5404 else
5405 {
5406 desired_speed = fmax(maxFlightSpeed,fmin(3.0 * target_speed, max_available_speed)); // possibly use afterburner to approach
5407 }
5408 }
5409
5410
5411 double last_success_factor = success_factor;
5412 success_factor = [self trackPrimaryTarget:delta_t:NO]; // do the actual piloting
5413
5414 if ((success_factor > 0.999)||(success_factor > last_success_factor))
5415 {
5416 frustration -= delta_t;
5417 if (frustration < 0.0)
5418 frustration = 0.0;
5419 }
5420 else
5421 {
5422 frustration += delta_t;
5423 if (frustration > 3.0) // 3s of frustration
5424 {
5425 [self noteFrustration:@"BEHAVIOUR_ATTACK_FLY_TO_TARGET"];
5426 [self setEvasiveJink:1000.0];
5427 behaviour = BEHAVIOUR_ATTACK_TARGET;
5428 frustration = 0.0;
5430 }
5431 }
5432
5433 if (missiles) [self considerFiringMissile:delta_t];
5434
5435 if (cloakAutomatic) [self activateCloakingDevice];
5436 [self fireMainWeapon:range];
5437
5438
5439
5441 {
5442 // don't do this if the target is fleeing and the front laser is
5443 // the only weapon, or if we're too far away to use non-front
5444 // lasers effectively
5445 if (aspect < 0 ||
5449 {
5450 frustration = 0.0;
5451 behaviour = BEHAVIOUR_ATTACK_TARGET;
5452 }
5453 }
5455 {
5456 // if we're right in their gunsights, dodge!
5457 // need to dodge sooner if in aft sights
5458 if ([target behaviour] != BEHAVIOUR_FLEE_TARGET && [target behaviour] != BEHAVIOUR_FLEE_EVASIVE_ACTION)
5459 {
5460 if ((aspect > 0.99999 && !isWeaponNone([target weaponTypeForFacing:WEAPON_FACING_FORWARD strict:NO])) || (aspect < -0.999 && !isWeaponNone([target weaponTypeForFacing:WEAPON_FACING_AFT strict:NO])))
5461 {
5462 frustration = 0.0;
5463 behaviour = BEHAVIOUR_EVASIVE_ACTION;
5464 }
5465 }
5466 }
5467}
@ WEAPON_FACING_FORWARD
Definition OOTypes.h:229
@ WEAPON_FACING_AFT
Definition OOTypes.h:230
#define COMBAT_AI_ISNT_AWFUL
Definition ShipEntity.h:123
#define COMBAT_AI_FLEES_BETTER
Definition ShipEntity.h:127
#define COMBAT_AI_CONFIDENCE_FACTOR
Definition ShipEntity.h:122
#define COMBAT_AI_IS_SMART
Definition ShipEntity.h:125
OOWeaponType aft_weapon_type
Definition ShipEntity.h:306
GLfloat aim_tolerance
Definition ShipEntity.h:375

◆ behaviour_attack_mining_target:

- (void) behaviour_attack_mining_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5262 :(double) delta_t
5263{
5264 double range = [self rangeToPrimaryTarget];
5265 if (![self canStillTrackPrimaryTarget])
5266 {
5267 [self noteLostTargetAndGoIdle];
5268 desired_speed = maxFlightSpeed * 0.375;
5269 return;
5270 }
5271 else if ((range < 650) || ([self proximityAlert] != nil))
5272 {
5273 if ([self proximityAlert] == NO_TARGET)
5274 {
5275 desired_speed = range * maxFlightSpeed / (650.0 * 16.0);
5276 }
5277 else
5278 {
5279 [self avoidCollision];
5280 }
5281 }
5282 else
5283 {
5284 //we have a target, its within scanner range, and outside 650
5285 desired_speed = maxFlightSpeed * 0.875;
5286 }
5287
5288 [self trackPrimaryTarget:delta_t:NO];
5289
5290 /* Don't open fire until within 3km - it doesn't take many mining
5291 * laser shots to destroy an asteroid, but some of these mining
5292 * ships are way too slow to effectively chase down the debris:
5293 * wait until reasonably close before trying to split it. */
5294 if (range < 3000)
5295 {
5296 [self fireMainWeapon:range];
5297 }
5298
5299
5300}

◆ behaviour_attack_slow_dogfight:

- (void) behaviour_attack_slow_dogfight: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4444 :(double) delta_t
4445{
4446 if (![self canStillTrackPrimaryTarget])
4447 {
4448 [self noteLostTargetAndGoIdle];
4449 return;
4450 }
4451 if ([self hasProximityAlertIgnoringTarget:YES])
4452 {
4453 [self avoidCollision];
4454 return;
4455 }
4456 double range = [self rangeToPrimaryTarget];
4457 ShipEntity* target = [self primaryTarget];
4458 double aspect = [self approachAspectToPrimaryTarget];
4459 if (range < 2.5*(collision_radius+target->collision_radius) && [self proximityAlert] == target && aspect > 0) {
4461 [self avoidCollision];
4462 return;
4463 }
4464 if (aspect < -0.5 && range > COMBAT_IN_RANGE_FACTOR * weaponRange * 2.0)
4465 {
4466 behaviour = BEHAVIOUR_ATTACK_TARGET;
4467 }
4468 else if (aspect < -0.5)
4469 {
4470// mostly behind target - try to stay there and keep up
4471 desired_speed = fmin(maxFlightSpeed * 0.5,[target speed]*0.5);
4472 }
4473 else if (aspect < 0.3)
4474 {
4475// to side of target - slow right down
4477 }
4478 else
4479 {
4480// coming to front of target - accelerate for a quick getaway
4481 desired_speed = maxFlightSpeed * fmin(aspect*2.5,1.0);
4482 }
4483 if (aspect > 0.85)
4484 {
4485 behaviour = BEHAVIOUR_ATTACK_BREAK_OFF_TARGET;
4486 }
4487 if (aspect > 0.0)
4488 {
4489 frustration += delta_t;
4490 }
4491 else
4492 {
4493 frustration -= delta_t;
4494 }
4495 if (frustration > 10.0)
4496 {
4497 desired_speed /= 2.0;
4498 }
4499 else if (frustration < 0.0)
4500 frustration = 0.0;
4501
4502 [self trackPrimaryTarget:delta_t:NO];
4503
4504 if (missiles) [self considerFiringMissile:delta_t];
4505
4506 if (cloakAutomatic) [self activateCloakingDevice];
4507
4508}

◆ behaviour_attack_sniper:

- (void) behaviour_attack_sniper: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5038 :(double) delta_t
5039{
5040 if (![self canStillTrackPrimaryTarget])
5041 {
5042 [self noteLostTargetAndGoIdle];
5043 return;
5044 }
5045 Entity* rawTarget = [self primaryTarget];
5046 if (![rawTarget isShip])
5047 {
5048 // can't attack a wormhole
5049 [self noteLostTargetAndGoIdle];
5050 return;
5051 }
5052 ShipEntity *target = (ShipEntity *)rawTarget;
5053
5054 double range = [self rangeToPrimaryTarget];
5055 float max_available_speed = maxFlightSpeed;
5056
5057 if (range < 15000)
5058 {
5059 behaviour = BEHAVIOUR_ATTACK_TARGET;
5060 }
5061 else
5062 {
5063 if (range > weaponRange || range > scannerRange * 0.8)
5064 {
5065 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
5066 if (canBurn && [target weaponRange] > weaponRange && range > weaponRange)
5067 {
5068 // if outside maximum weapon range, but inside target weapon range
5069 // close to fight ASAP!
5070 max_available_speed *= [self afterburnerFactor];
5071 }
5072 desired_speed = max_available_speed;
5073 }
5074 else
5075 {
5076 desired_speed = max_available_speed / 10.0f;
5077 }
5078
5079 double last_success_factor = success_factor;
5080 success_factor = [self trackPrimaryTarget:delta_t:NO];
5081
5082 if ((success_factor > 0.999)||(success_factor > last_success_factor))
5083 {
5084 frustration -= delta_t;
5085 if (frustration < 0.0)
5086 frustration = 0.0;
5087 }
5088 else
5089 {
5090 frustration += delta_t;
5091 if (frustration > 3.0) // 3s of frustration
5092 {
5093 [self noteFrustration:@"BEHAVIOUR_ATTACK_SNIPER"];
5094 [self setEvasiveJink:1000.0];
5095 behaviour = BEHAVIOUR_ATTACK_TARGET;
5096 frustration = 0.0;
5098 }
5099 }
5100
5101 }
5102
5103 if (missiles) [self considerFiringMissile:delta_t];
5104
5105 if (cloakAutomatic) [self activateCloakingDevice];
5106 [self fireMainWeapon:range];
5107
5109 {
5110 behaviour = BEHAVIOUR_ATTACK_TARGET;
5111 }
5112
5113}

◆ behaviour_attack_target:

- (void) behaviour_attack_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4560 :(double) delta_t
4561{
4562 double range = [self rangeToPrimaryTarget];
4563
4564 if (cloakAutomatic) [self activateCloakingDevice];
4565
4566/* Start of behaviour selection:
4567 * Anything beyond the basics should require accuracy >= COMBAT_AI_ISNT_AWFUL
4568 * Anything fancy should require accuracy >= COMBAT_AI_IS_SMART
4569 * If precise aim is required, behaviour should have accuracy >= COMBAT_AI_TRACKS_CLOSER
4570 * - CIM
4571 */
4572
4573 OOWeaponType forward_weapon_real_type = forward_weapon_type;
4574 GLfloat forward_weapon_real_temp = forward_weapon_temp;
4575
4576// if forward weapon is actually on a subent
4577 if (isWeaponNone(forward_weapon_real_type))
4578 {
4579 BOOL hasTurrets = NO;
4580 NSEnumerator *subEnum = [self shipSubEntityEnumerator];
4581 ShipEntity *se = nil;
4582 while (isWeaponNone(forward_weapon_real_type) && (se = [subEnum nextObject]))
4583 {
4584 forward_weapon_real_type = se->forward_weapon_type;
4585 forward_weapon_real_temp = se->forward_weapon_temp;
4586 if (se->behaviour == BEHAVIOUR_TRACK_AS_TURRET)
4587 {
4588 hasTurrets = YES;
4589 }
4590 }
4591 if (isWeaponNone(forward_weapon_real_type) && hasTurrets)
4592 { // safety for ships only equipped with turrets
4593 forward_weapon_real_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_PULSE_LASER");
4594 forward_weapon_real_temp = COMBAT_AI_WEAPON_TEMP_USABLE * 0.9;
4595 }
4596 }
4597
4598 if ([forward_weapon_real_type isTurretLaser])
4599 {
4600 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
4601 }
4602 else
4603 {
4604 BOOL in_good_range = aim_tolerance*range < COMBAT_AI_CONFIDENCE_FACTOR;
4605
4606 BOOL aft_weapon_ready = !isWeaponNone(aft_weapon_type) && (aft_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
4607 BOOL forward_weapon_ready = !isWeaponNone(forward_weapon_real_type) && (forward_weapon_real_temp < COMBAT_AI_WEAPON_TEMP_READY); // does not require in_good_range
4608 BOOL port_weapon_ready = !isWeaponNone(port_weapon_type) && (port_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
4609 BOOL starboard_weapon_ready = !isWeaponNone(starboard_weapon_type) && (starboard_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
4610// if no weapons cool enough to be good choices, be less picky
4611 BOOL weapons_heating = NO;
4612 if (!forward_weapon_ready && !aft_weapon_ready && !port_weapon_ready && !starboard_weapon_ready)
4613 {
4614 weapons_heating = YES;
4615 aft_weapon_ready = !isWeaponNone(aft_weapon_type) && (aft_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
4616 forward_weapon_ready = !isWeaponNone(forward_weapon_real_type) && (forward_weapon_real_temp < COMBAT_AI_WEAPON_TEMP_USABLE); // does not require in_good_range
4617 port_weapon_ready = !isWeaponNone(port_weapon_type) && (port_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
4618 starboard_weapon_ready = !isWeaponNone(starboard_weapon_type) && (starboard_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
4619 }
4620
4621 Entity* target = [self primaryTarget];
4622 double aspect = [self approachAspectToPrimaryTarget];
4623
4624 if (!forward_weapon_ready && !aft_weapon_ready && !port_weapon_ready && !starboard_weapon_ready)
4625 { // no usable weapons! Either not fitted or overheated
4626
4627 // if unarmed
4628 if (isWeaponNone(forward_weapon_real_type) &&
4632 {
4633 behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
4634 }
4635 else if (aspect > 0)
4636 {
4637 if (in_good_range)
4638 {
4639 if (accuracy >= COMBAT_AI_IS_SMART && randf() < 0.75)
4640 {
4641 behaviour = BEHAVIOUR_EVASIVE_ACTION;
4642 }
4643 else
4644 {
4645 behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
4646 }
4647 }
4648 else
4649 {
4650 // ready to get more accurate shots later
4651 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
4652 }
4653 }
4654 else
4655 {
4656 // if target is running away, stay on target
4657 // unless too close for safety
4658 if (range < COMBAT_IN_RANGE_FACTOR * weaponRange) {
4659 behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
4660 } else {
4661 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
4662 }
4663 }
4664 }
4665// if our current target isn't targeting us, and we have some idea of how to fight, and our weapons are running hot, and we're fairly nearby
4666 else if (weapons_heating && accuracy >= COMBAT_AI_ISNT_AWFUL && [target isShip] && [(ShipEntity *)target primaryTarget] != self && range < COMBAT_OUT_RANGE_FACTOR * weaponRange)
4667 {
4668// then back off a bit for weapons to cool so we get a good attack run later, rather than weaving closer
4669 float relativeSpeed = magnitude(vector_subtract([self velocity], [target velocity]));
4670 [self setEvasiveJink:(range + COMBAT_JINK_OFFSET - relativeSpeed / max_flight_pitch)];
4671 behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
4672 }
4673 else
4674 {
4677
4678
4679 if (nearby && aft_weapon_ready)
4680 {
4681 jink = kZeroVector; // almost all behaviours
4682 behaviour = BEHAVIOUR_RUNNING_DEFENSE;
4683 }
4684 else if (nearby && (port_weapon_ready || starboard_weapon_ready))
4685 {
4686 jink = kZeroVector; // almost all behaviours
4687 behaviour = BEHAVIOUR_ATTACK_BROADSIDE;
4688 }
4689 else if (nearby)
4690 {
4691 if (!pitching_over) // don't change jink in the middle of a sharp turn.
4692 {
4693 /*
4694 For most AIs, is behaviour_attack_target called as starting behaviour on every hit.
4695 Target can both fly towards or away from ourselves here. Both situations
4696 need a different jink.z for optimal collision avoidance at high speed approach and low speed dogfighting.
4697 The COMBAT_JINK_OFFSET intentionally over-compensates the range for collision radii to send ships towards
4698 the target at low speeds.
4699 */
4700 float relativeSpeed = magnitude(vector_subtract([self velocity], [target velocity]));
4701 [self setEvasiveJink:(range + COMBAT_JINK_OFFSET - relativeSpeed / max_flight_pitch)];
4702 }
4703 // good pilots use behaviour_attack_break_off_target instead
4705 {
4706 behaviour = BEHAVIOUR_ATTACK_BREAK_OFF_TARGET;
4707 }
4708 else
4709 {
4710 behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
4711 }
4712 }
4713 else if (forward_weapon_ready)
4714 {
4715 jink = kZeroVector; // almost all behaviours
4716
4717 // TODO: good pilots use behaviour_attack_sniper sometimes
4718 if (getWeaponRangeFromType(forward_weapon_real_type) > 12500 && range > 12500)
4719 {
4720 behaviour = BEHAVIOUR_ATTACK_SNIPER;
4721 }
4722// generally not good tactics the next two
4723 else if (accuracy < COMBAT_AI_ISNT_AWFUL && aspect < 0)
4724 {
4725 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX;
4726 }
4727 else if (accuracy < COMBAT_AI_ISNT_AWFUL)
4728 {
4729 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
4730 }
4731 else
4732 {
4733 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
4734 }
4735 }
4736 else if (port_weapon_ready || starboard_weapon_ready)
4737 {
4738 jink = kZeroVector; // almost all behaviours
4739 behaviour = BEHAVIOUR_ATTACK_BROADSIDE;
4740 }
4741 else if (aft_weapon_ready && midrange)
4742 {
4743 jink = kZeroVector; // almost all behaviours
4744 behaviour = BEHAVIOUR_RUNNING_DEFENSE;
4745 }
4746 else
4747 {
4748 jink = kZeroVector; // almost all behaviours
4749 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
4750 }
4751 }
4752 }
4753
4754 frustration = 0.0; // behaviour changed, so reset frustration
4755
4756}
OOWeaponType OOWeaponTypeFromEquipmentIdentifierSloppy(NSString *string) PURE_FUNC
GLfloat aft_weapon_temp
Definition ShipEntity.h:315
OOWeaponType forward_weapon_type
Definition ShipEntity.h:305

◆ behaviour_avoid_collision:

- (void) behaviour_avoid_collision: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5979 :(double) delta_t
5980{
5981 double distance = [self rangeToDestination];
5982 if (distance > desired_range)
5983 {
5984 [self resumePostProximityAlert];
5985 }
5986 else
5987 {
5988 ShipEntity* prox_ship = (ShipEntity*)[self proximityAlert];
5989 if (prox_ship)
5990 {
5992 _destination = prox_ship->position;
5993 }
5994 double dq = [self trackDestination:delta_t:YES]; // returns 0 when heading towards prox_ship
5995 // Heading towards target with desired_speed > 0, avoids collisions better than setting desired_speed to zero.
5996 // (tested with boa class cruiser on collisioncourse with buoy)
5997 desired_speed = maxFlightSpeed * (0.5 * dq + 0.5);
5998 }
5999
6000
6001
6002}

◆ behaviour_close_to_broadside_range:

- (void) behaviour_close_to_broadside_range: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4956 :(double) delta_t
4957{
4958 double range = [self rangeToPrimaryTarget];
4959 if ([self proximityAlert] != nil)
4960 {
4961 if ([self proximityAlert] == [self primaryTarget])
4962 {
4963 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET; // this behaviour will handle proximity_alert.
4964 [self behaviour_attack_fly_from_target: delta_t]; // do it now.
4965 }
4966 else
4967 {
4968 [self avoidCollision];
4969 }
4970 return;
4971 }
4972 if (![self canStillTrackPrimaryTarget])
4973 {
4974 [self noteLostTargetAndGoIdle];
4975 return;
4976 }
4977
4978 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
4979 [self behaviour_fly_to_target_six:delta_t];
4981 {
4982 [self setWeaponDataFromType:port_weapon_type];
4983 }
4984 else
4985 {
4986 [self setWeaponDataFromType:starboard_weapon_type];
4987 }
4989 {
4990 behaviour = BEHAVIOUR_ATTACK_BROADSIDE;
4991 }
4992 else
4993 {
4994 behaviour = BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE;
4995 }
4996}

◆ behaviour_close_with_target:

- (void) behaviour_close_with_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4999 :(double) delta_t
5000{
5001 double range = [self rangeToPrimaryTarget];
5002 if ([self proximityAlert] != nil)
5003 {
5004 if ([self proximityAlert] == [self primaryTarget])
5005 {
5006 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET; // this behaviour will handle proximity_alert.
5007 [self behaviour_attack_fly_from_target: delta_t]; // do it now.
5008 }
5009 else
5010 {
5011 [self avoidCollision];
5012 }
5013 return;
5014 }
5015 if (![self canStillTrackPrimaryTarget])
5016 {
5017 [self noteLostTargetAndGoIdle];
5018 return;
5019 }
5020 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
5021 double saved_frustration = frustration;
5022 [self behaviour_fly_to_target_six:delta_t];
5023 frustration = saved_frustration; // ignore fly-to-12 frustration
5024 frustration += delta_t;
5025 if (range <= COMBAT_IN_RANGE_FACTOR * weaponRange || frustration > 5.0)
5026 {
5027 behaviour = BEHAVIOUR_ATTACK_TARGET;
5028 }
5029 else
5030 {
5031 behaviour = BEHAVIOUR_CLOSE_WITH_TARGET;
5032 }
5033
5034
5035}

◆ behaviour_evasive_action:

- (void) behaviour_evasive_action: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4511 :(double) delta_t
4512{
4513 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
4514 float max_available_speed = maxFlightSpeed;
4515// double range = [self rangeToPrimaryTarget];
4516 if (canBurn) max_available_speed *= [self afterburnerFactor];
4517 desired_speed = max_available_speed;
4519 {
4520 ShipEntity* target = [self primaryTarget];
4521 double target_speed = [target speed];
4522 if (desired_speed > target_speed)
4523 {
4524 desired_speed = maxFlightSpeed; // don't overuse the injectors
4525 }
4526 }
4527
4528 if (cloakAutomatic) [self activateCloakingDevice];
4529 if ([self proximityAlert] != nil)
4530 {
4531 [self avoidCollision];
4532 return;
4533 }
4534
4535 [self evasiveAction:delta_t];
4536
4537 frustration += delta_t;
4538
4539 if (frustration > 0.5)
4540 {
4541 if (behaviour == BEHAVIOUR_FLEE_EVASIVE_ACTION)
4542 {
4543 [self setEvasiveJink:400.0];
4544 behaviour = BEHAVIOUR_FLEE_TARGET;
4545 }
4546 else
4547 {
4548 behaviour = BEHAVIOUR_ATTACK_TARGET;
4549 }
4550 }
4551
4552 flightYaw = 0.0;
4553
4554 // probably only useful for Thargoids, except for the occasional opportunist
4555 [self fireMainWeapon:[self rangeToPrimaryTarget]];
4556
4557}

◆ behaviour_face_destination:

- (void) behaviour_face_destination: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5699 :(double) delta_t
5700{
5701 double max_cos = MAX_COS;
5702 double distance = [self rangeToDestination];
5703 double old_pitch = flightPitch;
5704 desired_speed = 0.0;
5705 if (desired_range > 1.0 && distance > desired_range)
5706 {
5707 max_cos = sqrt(1 - 0.90 * desired_range*desired_range/(distance * distance)); // Head for a point within 95% of desired_range (must match the value in trackDestination)
5708 }
5709 double confidenceFactor = [self trackDestination:delta_t:NO];
5710 if (confidenceFactor >= max_cos && flightPitch == 0.0)
5711 {
5712 // desired facing achieved and movement stabilised.
5713 [shipAI message:@"FACING_DESTINATION"];
5714 [self doScriptEvent:OOJSID("shipNowFacingDestination")];
5715 frustration = 0.0;
5716 if(docking_match_rotation) // IDLE stops rotating while docking
5717 {
5718 behaviour = BEHAVIOUR_FLY_TO_DESTINATION;
5719 }
5720 else
5721 {
5722 behaviour = BEHAVIOUR_IDLE;
5723 }
5724 }
5725
5726 if(flightSpeed == 0) frustration += delta_t;
5727 if (frustration > 15.0 / max_flight_pitch) // allow more time for slow ships.
5728 {
5729 frustration = 0.0;
5730 [self noteFrustration:@"BEHAVIOUR_FACE_DESTINATION"];
5731 if(flightPitch == old_pitch) flightPitch = 0.5 * max_flight_pitch; // hack to get out of frustration.
5732 }
5733
5734 /* 2009-7-18 Eric: the condition check below is intended to eliminate the flippering between two positions for fast turning ships
5735 during low FPS conditions. This flippering is particular frustrating on slow computers during docking. But with my current computer I can't
5736 induce those low FPS conditions so I can't properly test if it helps.
5737 I did try with the TAF time acceleration that also generated larger frame jumps and than it seemed to help.
5738 */
5739 if(flightSpeed == 0 && frustration > 5 && confidenceFactor > 0.5 && ((flightPitch > 0 && old_pitch < 0) || (flightPitch < 0 && old_pitch > 0)))
5740 {
5741 flightPitch += 0.5 * old_pitch; // damping with last pitch value.
5742 }
5743
5744 if ([self hasProximityAlertIgnoringTarget:YES])
5745 {
5746 [self avoidCollision];
5747 }
5748
5749
5750}
#define MAX_COS
Definition ShipEntity.h:143
unsigned docking_match_rotation
Definition ShipEntity.h:251

◆ behaviour_flee_target:

- (void) behaviour_flee_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5602 :(double) delta_t
5603{
5604 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
5605 float max_available_speed = maxFlightSpeed;
5606 double range = [self rangeToPrimaryTarget];
5607 if ([self primaryTarget] == nil)
5608 {
5609 [self noteLostTargetAndGoIdle];
5610 return;
5611 }
5612 if (canBurn) max_available_speed *= [self afterburnerFactor];
5613
5614 double last_range = success_factor;
5615 success_factor = range;
5616
5617 if (range > desired_range || range == 0)
5618 [shipAI message:@"REACHED_SAFETY"];
5619 else
5620 desired_speed = max_available_speed;
5621
5622 if (range > last_range) // improvement
5623 {
5624 frustration -= 0.25 * delta_t;
5625 if (frustration < 0.0)
5626 frustration = 0.0;
5627 }
5628 else
5629 {
5630 frustration += delta_t;
5631 if (frustration > 15.0) // 15s of frustration
5632 {
5633 [self noteFrustration:@"BEHAVIOUR_FLEE_TARGET"];
5634 frustration = 0.0;
5635 }
5636 }
5637
5638 [self trackPrimaryTarget:delta_t:YES];
5639
5640 Entity *target = [self primaryTarget];
5641
5642 if (missiles && [target isShip] && [(ShipEntity *)target primaryTarget] == self)
5643 {
5644 [self considerFiringMissile:delta_t];
5645 }
5646
5647 if (([self hasCascadeMine]) && (range < 10000.0) && canBurn)
5648 {
5649 float qbomb_chance = 0.01 * delta_t;
5650 if (randf() < qbomb_chance)
5651 {
5652 [self launchCascadeMine];
5653 }
5654 }
5655
5656// thargoids won't normally be fleeing, but if they do, they can still shoot
5657 if ([forward_weapon_type isTurretLaser])
5658 {
5659 [self fireMainWeapon:range];
5660 }
5661
5662 if (cloakAutomatic) [self activateCloakingDevice];
5663
5664 // remember to look where you're going?
5665 if (accuracy >= COMBAT_AI_ISNT_AWFUL && [self hasProximityAlertIgnoringTarget:YES])
5666 {
5667 [self avoidCollision];
5668 }
5669
5670}
BOOL hasCascadeMine()

◆ behaviour_fly_from_destination:

- (void) behaviour_fly_from_destination: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5955 :(double) delta_t
5956{
5957 double distance = [self rangeToDestination];
5958 if (distance > desired_range)
5959 {
5960 // desired range achieved
5961 [shipAI message:@"DESIRED_RANGE_ACHIEVED"];
5962 [self doScriptEvent:OOJSID("shipAchievedDesiredRange")];
5963
5964 behaviour = BEHAVIOUR_IDLE;
5965 frustration = 0.0;
5966 desired_speed = 0.0;
5967 }
5968
5969 [self trackDestination:delta_t:YES];
5970 if ([self hasProximityAlertIgnoringTarget:YES])
5971 {
5972 [self avoidCollision];
5973 }
5974
5975
5976}

◆ behaviour_fly_range_from_destination:

- (void) behaviour_fly_range_from_destination: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5673 :(double) delta_t
5674{
5675 double distance = [self rangeToDestination];
5676 if (distance < desired_range)
5677 {
5678 behaviour = BEHAVIOUR_FLY_FROM_DESTINATION;
5680 {
5681 desired_speed = maxFlightSpeed; // Not all AI define speed when flying away. Start with max speed to stay compatible with such AI's, but allow faster flight if it's (e.g.) used to flee from coordinates rather than entity
5682 }
5683 }
5684 else
5685 {
5686 behaviour = BEHAVIOUR_FLY_TO_DESTINATION;
5687 }
5688 if ([self hasProximityAlertIgnoringTarget:YES])
5689 {
5690 [self avoidCollision];
5691 }
5692 frustration = 0.0;
5693
5694
5695
5696}

◆ behaviour_fly_thru_navpoints:

- (void) behaviour_fly_thru_navpoints: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

6067 :(double) delta_t
6068{
6069 int navpoint_plus_index = (next_navpoint_index + 1) % number_of_navpoints;
6070 HPVector d1 = navpoints[next_navpoint_index]; // head for this one
6071 HPVector d2 = navpoints[navpoint_plus_index]; // but be facing this one
6072
6073 HPVector rel = HPvector_between(d1, position); // vector from d1 to position
6074 HPVector ref = HPvector_between(d2, d1); // vector from d2 to d1
6075 ref = HPvector_normal(ref);
6076
6077 HPVector xp = make_HPvector(ref.y * rel.z - ref.z * rel.y, ref.z * rel.x - ref.x * rel.z, ref.x * rel.y - ref.y * rel.x);
6078
6079 GLfloat v0 = 0.0;
6080
6081 GLfloat r0 = HPdot_product(rel, ref); // proportion of rel in direction ref
6082
6083 // if r0 is negative then we're the wrong side of things
6084
6085 GLfloat r1 = HPmagnitude(xp); // distance of position from line
6086
6087 BOOL in_cone = (r0 > 0.5 * r1);
6088
6089 if (!in_cone) // are we in the approach cone ?
6090 r1 = 25.0 * flightSpeed; // aim a few km out!
6091 else
6092 r1 *= 2.0;
6093
6094 GLfloat dist2 = HPmagnitude2(rel);
6095
6096 if (dist2 < desired_range * desired_range)
6097 {
6098 // desired range achieved
6099 [self doScriptEvent:OOJSID("shipReachedNavPoint") andReactToAIMessage:@"NAVPOINT_REACHED"];
6100 if (navpoint_plus_index == 0)
6101 {
6102 [self doScriptEvent:OOJSID("shipReachedEndPoint") andReactToAIMessage:@"ENDPOINT_REACHED"];
6103 behaviour = BEHAVIOUR_IDLE;
6104 }
6105 next_navpoint_index = navpoint_plus_index; // loop as required
6106 }
6107 else
6108 {
6109 double last_success_factor = success_factor;
6110 double last_dist2 = last_success_factor;
6111 success_factor = dist2;
6112
6113 // set destination spline point from r1 and ref
6114 _destination = make_HPvector(d1.x + r1 * ref.x, d1.y + r1 * ref.y, d1.z + r1 * ref.z);
6115
6116 // do the actual piloting!!
6117 //
6118 // aim to within 1m
6119 GLfloat temp = desired_range;
6120 if (in_cone)
6121 desired_range = 1.0;
6122 else
6123 desired_range = 100.0;
6124 v0 = [self trackDestination:delta_t: NO];
6125 desired_range = temp;
6126
6127 if (dist2 < last_dist2) // improvement
6128 {
6129 frustration -= 0.25 * delta_t;
6130 if (frustration < 0.0)
6131 frustration = 0.0;
6132 }
6133 else
6134 {
6135 frustration += delta_t;
6136 if (frustration > 15.0) // 15s of frustration
6137 {
6138 [self noteFrustration:@"BEHAVIOUR_FLY_THRU_NAVPOINTS"];
6139 frustration -= 15.0; //repeat after another 15s of frustration
6140 }
6141 }
6142 }
6143
6144
6145
6146 GLfloat temp = desired_speed;
6147 desired_speed *= v0 * v0;
6148
6149 desired_speed = temp;
6150}
unsigned number_of_navpoints
Definition ShipEntity.h:420
HPVector navpoints[32]
Definition ShipEntity.h:418
unsigned next_navpoint_index
Definition ShipEntity.h:419

◆ behaviour_fly_to_destination:

- (void) behaviour_fly_to_destination: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5850 :(double) delta_t
5851{
5852 double distance = [self rangeToDestination];
5853 // double desiredRange = (dockingInstructions != nil) ? 1.2 * desired_range : desired_range; // stop a bit earlyer when docking.
5854 if (distance < desired_range) // + collision_radius)
5855 {
5856 // desired range achieved
5857 [shipAI message:@"DESIRED_RANGE_ACHIEVED"];
5858 [self doScriptEvent:OOJSID("shipAchievedDesiredRange")];
5859
5860 if(!docking_match_rotation) // IDLE stops rotating while docking
5861 {
5862 behaviour = BEHAVIOUR_IDLE;
5863 desired_speed = 0.0;
5864 }
5865 frustration = 0.0;
5866 }
5867 else
5868 {
5869 double last_distance = success_factor;
5870 success_factor = distance;
5871
5872 // do the actual piloting!!
5873 double confidenceFactor = [self trackDestination:delta_t: NO];
5874 if(confidenceFactor < 0.2) confidenceFactor = 0.2; // don't allow small or negative values.
5875
5876 /* 2009-07-19 Eric: Estimated Time of Arrival (eta) should also take the "angle to target" into account (confidenceFactor = cos(angle to target))
5877 and should not fuss about that last meter and use "distance + 1" instead of just "distance".
5878 trackDestination already did pitch regulation, use confidence here only for cutting down to high speeds.
5879 This should prevent ships crawling to their destination when they try to pull up close to their destination.
5880
5881 To prevent ships circling around their target without reaching destination I added a limitation based on turnrate,
5882 speed and distance to target. Formula based on satelite orbit:
5883 orbitspeed = turnrate (rad/sec) * radius (m) or flightSpeed = max_flight_pitch * 2 Pi * distance
5884 Speed must be significant lower when not flying in direction of target (low confidenceFactor) or it can never approach its destination
5885 and the ships runs the risk flying in circles around the target. (exclude active escorts)
5886 */
5887 GLfloat eta = ((distance + 1) - desired_range) / (0.51 * flightSpeed * confidenceFactor); // 2% safety margin assuming an average of half current speed
5888 GLfloat slowdownTime = (thrust > 0.0)? flightSpeed / (thrust) : 4.0;
5889 GLfloat minTurnSpeedFactor = 0.05 * max_flight_pitch * max_flight_roll; // faster turning implies higher speeds
5890 if (dockingInstructions != nil)
5891 {
5892 minTurnSpeedFactor /= 10.0;
5893 if (minTurnSpeedFactor * maxFlightSpeed > 20.0)
5894 {
5895 minTurnSpeedFactor /= 10.0;
5896 }
5897 }
5898
5899
5900 if (((eta < slowdownTime)&&(flightSpeed > maxFlightSpeed * minTurnSpeedFactor)) || (flightSpeed > max_flight_pitch * 5 * confidenceFactor * distance))
5901 {
5902 desired_speed = flightSpeed * 0.50; // cut speed by 50% to a minimum minTurnSpeedFactor of speed
5903 }
5904
5905 /* Flight correction block to prevent one possible form of
5906 * crashes in late docking process */
5907 if (docking_match_rotation && confidenceFactor >= MAX_COS && dockingInstructions != nil && [dockingInstructions oo_intForKey:@"docking_stage"] >= 7)
5908 {
5909 // then at this point should be rotating to match the station
5910 StationEntity* station_for_docking = (StationEntity*)[self targetStation];
5911
5912 if ((station_for_docking)&&(station_for_docking->isStation))
5913 {
5914 float rollMatch = dot_product([station_for_docking portUpVectorForShip:self],[self upVector]);
5915 if (rollMatch < MAX_COS && rollMatch > -MAX_COS)
5916 {
5917 // not matching rotating - stop until corrected
5918 desired_speed = 0.1;
5919 }
5920 else if (desired_speed <= 0.2)
5921 {
5922 // had previously paused, so return to normal speed
5923 desired_speed = [dockingInstructions oo_floatForKey:@"speed"];
5924 }
5925 }
5926 }
5927
5928
5929
5930 if (distance < last_distance) // improvement
5931 {
5932 frustration -= 0.25 * delta_t;
5933 if (frustration < 0.0)
5934 frustration = 0.0;
5935 }
5936 else
5937 {
5938 frustration += delta_t;
5939 if ((frustration > slowdownTime * 10.0 && slowdownTime > 0)||(frustration > 15.0)) // 10x slowdownTime or 15s of frustration
5940 {
5941 [self noteFrustration:@"BEHAVIOUR_FLY_TO_DESTINATION"];
5942 frustration -= slowdownTime * 5.0; //repeat after another five units of frustration
5943 }
5944 }
5945 }
5946 if ([self hasProximityAlertIgnoringTarget:YES])
5947 {
5948 [self avoidCollision];
5949 }
5950
5951
5952}
unsigned isStation
Definition Entity.h:92
Vector upVector()
NSDictionary * dockingInstructions
Definition ShipEntity.h:227
StationEntity * targetStation()

◆ behaviour_fly_to_target_six:

- (void) behaviour_fly_to_target_six: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5116 :(double) delta_t
5117{
5118 BOOL canBurn = [self hasFuelInjection] && (fuel > MIN_FUEL);
5119 float max_available_speed = maxFlightSpeed;
5120 double range = [self rangeToPrimaryTarget];
5121 if (canBurn) max_available_speed *= [self afterburnerFactor];
5122
5123 // deal with collisions and lost targets
5124 if ([self proximityAlert] != nil)
5125 {
5126 if ([self proximityAlert] == [self primaryTarget])
5127 {
5128 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET; // this behaviour will handle proximity_alert.
5129 [self behaviour_attack_fly_from_target: delta_t]; // do it now.
5130 }
5131 else
5132 {
5133 [self avoidCollision];
5134 }
5135 return;
5136 }
5137 if (![self canStillTrackPrimaryTarget])
5138 {
5139 [self noteLostTargetAndGoIdle];
5140 return;
5141 }
5142
5143 // control speed
5144 BOOL isUsingAfterburner = canBurn && (flightSpeed > maxFlightSpeed);
5145 BOOL closeQuickly = (canBurn && range > weaponRange);
5146 double slow_down_range = weaponRange * COMBAT_WEAPON_RANGE_FACTOR * ((isUsingAfterburner)? 3.0 * [self afterburnerFactor] : 1.0);
5147 if (closeQuickly)
5148 {
5149 slow_down_range = weaponRange * COMBAT_OUT_RANGE_FACTOR;
5150 }
5151 double back_off_range = weaponRange * COMBAT_OUT_RANGE_FACTOR * ((isUsingAfterburner)? 3.0 * [self afterburnerFactor] : 1.0);
5152 Entity* rawTarget = [self primaryTarget];
5153 if (![rawTarget isShip])
5154 {
5155 [self noteLostTargetAndGoIdle];
5156 return;
5157 }
5158 ShipEntity* target = (ShipEntity *)rawTarget;
5159 double target_speed = [target speed];
5160 double last_success_factor = success_factor;
5161 double distance = [self rangeToDestination];
5162 success_factor = distance;
5163
5164 if (range < slow_down_range && (behaviour == BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX))
5165 {
5166 if (range < back_off_range)
5167 {
5168 desired_speed = fmax(0.9 * target_speed, 0.4 * maxFlightSpeed);
5169 }
5170 else
5171 {
5172 desired_speed = fmax(target_speed * 1.2, maxFlightSpeed);
5173 }
5174
5175 // avoid head-on collision
5176 if ((range < 0.5 * distance)&&(behaviour == BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX))
5177 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
5178 }
5179 else
5180 {
5181 if (range < back_off_range)
5182 {
5183 desired_speed = fmax(0.9 * target_speed, 0.8 * maxFlightSpeed);
5184 }
5185 else
5186 {
5187 desired_speed = max_available_speed; // use afterburner to approach
5188 }
5189 }
5190
5191
5192 // if within 0.75km of the target's six or twelve, or if target almost at standstill for 62.5% of non-thargoid ships (!),
5193 // then vector in attack.
5194 if (distance < 750.0 || (target_speed < 0.2 && ![self isThargoid] && ([self universalID] & 14) > 4))
5195 {
5196 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
5197 frustration = 0.0;
5198 desired_speed = fmax(target_speed, 0.4 * maxFlightSpeed); // within the weapon's range don't use afterburner
5199 }
5200
5201 // target-six
5202 if (behaviour == BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX)
5203 {
5204 // head for a point weapon-range * 0.5 to the six of the target
5205 //
5206 _destination = [target distance_six:0.5 * weaponRange];
5207 }
5208 // target-twelve
5209 if (behaviour == BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE)
5210 {
5211 if ([forward_weapon_type isTurretLaser])
5212 {
5213 // head for a point near the target, avoiding common Galcop weapon mount locations
5214 // TODO: this should account for weapon ranges
5215 GLfloat offset = 1000.0;
5216 GLfloat spacing = 2000.0;
5217 if (accuracy > 0.0)
5218 {
5219 offset = accuracy * 750.0;
5220 spacing = 2000.0 + (accuracy * 500.0);
5221 }
5222 if (entity_personality & 1)
5223 { // half at random
5224 offset = -offset;
5225 }
5226 _destination = [target distance_twelve:spacing withOffset:offset];
5227 }
5228 else
5229 {
5230 // head for a point 1.25km above the target
5231 _destination = [target distance_twelve:1250 withOffset:0];
5232 }
5233 }
5234
5235 pitching_over = NO; // in case it's set from elsewhere
5236 double confidenceFactor = [self trackDestination:delta_t :NO];
5237
5238 if(success_factor > last_success_factor || confidenceFactor < 0.85) frustration += delta_t;
5239 else if(frustration > 0.0) frustration -= delta_t * 0.75;
5240
5241 double aspect = [self approachAspectToPrimaryTarget];
5242 if(![forward_weapon_type isTurretLaser] && (frustration > 10 || aspect > 0.75))
5243 {
5244 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
5245 }
5246
5247 // use weaponry
5248 if (missiles) [self considerFiringMissile:delta_t];
5249
5250 if (cloakAutomatic) [self activateCloakingDevice];
5251 [self fireMainWeapon:range];
5252
5253
5254
5256 {
5257 behaviour = BEHAVIOUR_ATTACK_TARGET;
5258 }
5259}
OOUniversalID universalID
Definition Entity.h:89
HPVector distance_twelve:withOffset:(GLfloat dist,[withOffset] GLfloat offset)
uint16_t entity_personality
Definition ShipEntity.h:430
HPVector distance_six:(GLfloat dist)
voidpf uLong offset
Definition ioapi.h:140

◆ behaviour_formation_form_up:

- (void) behaviour_formation_form_up: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5797 :(double) delta_t
5798{
5799 // destination for each escort is set in update() from owner.
5800 ShipEntity* leadShip = [self owner];
5801 double distance = [self rangeToDestination];
5802 double eta = (distance - desired_range) / flightSpeed;
5803 if(eta < 0) eta = 0;
5804 if ((eta < 5.0)&&(leadShip)&&(leadShip->isShip))
5805 desired_speed = [leadShip flightSpeed] * (1 + eta * 0.05);
5806 else
5808
5809 double last_distance = success_factor;
5810 success_factor = distance;
5811
5812 // do the actual piloting!!
5813 [self trackDestination:delta_t: NO];
5814
5815 eta = eta / 0.51; // 2% safety margin assuming an average of half current speed
5816 GLfloat slowdownTime = (thrust > 0.0)? flightSpeed / (thrust) : 4.0;
5817 GLfloat minTurnSpeedFactor = 0.05 * max_flight_pitch * max_flight_roll; // faster turning implies higher speeds
5818
5819 if ((eta < slowdownTime)&&(flightSpeed > maxFlightSpeed * minTurnSpeedFactor))
5820 desired_speed = flightSpeed * 0.50; // cut speed by 50% to a minimum minTurnSpeedFactor of speed
5821
5822 if (distance < last_distance) // improvement
5823 {
5824 frustration -= 0.25 * delta_t;
5825 if (frustration < 0.0)
5826 frustration = 0.0;
5827 }
5828 else
5829 {
5830 frustration += delta_t;
5831 if (frustration > 15.0)
5832 {
5833 if (!leadShip) [self noteFrustration:@"BEHAVIOUR_FORMATION_FORM_UP"]; // escorts never reach their destination when following leader.
5834 else if (distance > 0.5 * scannerRange && !pitching_over)
5835 {
5836 pitching_over = YES; // Force the ship in a 180 degree turn. Do it here to allow escorts to break out formation for some seconds.
5837 }
5838 frustration = 0;
5839 }
5840 }
5841 if ([self hasProximityAlertIgnoringTarget:YES])
5842 {
5843 [self avoidCollision];
5844 }
5845
5846
5847}

◆ behaviour_idle:

- (void) behaviour_idle: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4153 :(double) delta_t
4154{
4155 stick_yaw = 0.0;
4156 if ((!isStation)&&(scanClass != CLASS_BUOY))
4157 {
4158 stick_roll = 0.0;
4159 }
4160 else
4161 {
4163 }
4164 if (scanClass != CLASS_BUOY)
4165 {
4166 stick_pitch = 0.0;
4167 }
4168 else
4169 {
4171 }
4172 [self applySticks:delta_t];
4173
4174
4175}

◆ behaviour_intercept_target:

- (void) behaviour_intercept_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4287 :(double) delta_t
4288{
4289 double range = [self rangeToPrimaryTarget];
4290 if (behaviour == BEHAVIOUR_INTERCEPT_TARGET)
4291 {
4293 if (range < desired_range)
4294 {
4295 [shipAI reactToMessage:@"DESIRED_RANGE_ACHIEVED" context:@"BEHAVIOUR_INTERCEPT_TARGET"];
4296 [self doScriptEvent:OOJSID("shipAchievedDesiredRange")];
4297
4298 }
4299 desired_speed = maxFlightSpeed * [self trackPrimaryTarget:delta_t:NO];
4300 }
4301 else
4302 {
4303 // = BEHAVIOUR_COLLECT_TARGET
4304 ShipEntity* target = [self primaryTarget];
4305// if somehow ended up in this state but target is not cargo, stop
4306// trying to scoop it
4307 if (!target || [target scanClass] != CLASS_CARGO || [target cargoType] == CARGO_NOT_CARGO)
4308 {
4309 [self noteLostTargetAndGoIdle];
4310 return;
4311 }
4312 double target_speed = [target speed];
4313 double eta = range / (flightSpeed - target_speed);
4314 double last_success_factor = success_factor;
4315 double last_distance = last_success_factor;
4316 double distance = [self rangeToDestination];
4317 success_factor = distance;
4318 //
4319 double slowdownTime = 96.0 / (thrust*SHIP_THRUST_FACTOR); // more thrust implies better slowing
4320 double minTurnSpeedFactor = 0.005 * max_flight_pitch * max_flight_roll; // faster turning implies higher speeds
4321
4322 if ((eta < slowdownTime)&&(flightSpeed > maxFlightSpeed * minTurnSpeedFactor))
4323 desired_speed = flightSpeed * 0.75; // cut speed by 50% to a minimum minTurnSpeedFactor of speed
4324 else
4326
4327 if (desired_speed < target_speed)
4328 {
4329 desired_speed += target_speed;
4330 if (target_speed > maxFlightSpeed)
4331 {
4332 [self noteLostTargetAndGoIdle];
4333 return;
4334 }
4335 }
4337 { // never use injectors for scooping
4339 }
4340
4341 _destination = target->position;
4342 desired_range = 0.5 * target->collision_radius;
4343 [self trackDestination: delta_t : NO];
4344
4345 //
4346 if (distance < last_distance) // improvement
4347 {
4348 frustration -= delta_t;
4349 if (frustration < 0.0)
4350 frustration = 0.0;
4351 }
4352 else
4353 {
4354 frustration += delta_t * 0.9;
4355 if (frustration > 10.0) // 10s of frustration
4356 {
4357 [self noteFrustration:@"BEHAVIOUR_INTERCEPT_TARGET"];
4358 frustration -= 5.0; //repeat after another five seconds' frustration
4359 }
4360 }
4361 }
4362 if ([self hasProximityAlertIgnoringTarget:YES])
4363 {
4364 [self avoidCollision];
4365 }
4366
4367
4368}
@ CARGO_NOT_CARGO
Definition OOTypes.h:70
OOCargoType cargoType()

◆ behaviour_land_on_planet:

- (void) behaviour_land_on_planet: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5753 :(double) delta_t
5754{
5755 double max_cos = MAX_COS2; // trackDestination returns the squared confidence in reverse mode.
5756 desired_speed = 0.0;
5757
5758 OOPlanetEntity* planet = [UNIVERSE entityForUniversalID:planetForLanding];
5759
5760 if (![planet isPlanet])
5761 {
5762 behaviour = BEHAVIOUR_IDLE;
5763 aiScriptWakeTime = 1; // reconsider JSAI
5764 [shipAI message:@"NO_PLANET_NEARBY"];
5765 return;
5766 }
5767
5768 if (HPdistance(position, [planet position]) + [self collisionRadius] < [planet radius])
5769 {
5770 // we have landed. (completely disappeared inside planet)
5771 [self landOnPlanet:planet];
5772 return;
5773 }
5774
5775 double confidenceFactor = [self trackDestination:delta_t:YES]; // turn away from destination
5776
5777 if (confidenceFactor >= max_cos && flightSpeed == 0.0)
5778 {
5779 // We are now turned away from planet. Start landing by flying backward.
5780 thrust = 0.0; // stop forward acceleration.
5781 if (magnitude2(velocity) < MAX_LANDING_SPEED2)
5782 {
5783 [self adjustVelocity:vector_multiply_scalar([self forwardVector], -max_thrust * delta_t)];
5784 }
5785 }
5786
5787
5788 if ([self hasProximityAlertIgnoringTarget:YES])
5789 {
5790 [self avoidCollision];
5791 }
5792
5793
5794}
#define MAX_COS2
Definition ShipEntity.h:144
#define MAX_LANDING_SPEED2
Definition ShipEntity.h:141
BOOL isPlanet()
Definition Entity.m:161
OOTimeAbsolute aiScriptWakeTime
Definition ShipEntity.h:224

◆ behaviour_running_defense:

- (void) behaviour_running_defense: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

5553 :(double) delta_t
5554{
5555 if (![self canStillTrackPrimaryTarget])
5556 {
5557 [self noteLostTargetAndGoIdle];
5558 return;
5559 }
5560
5561 double range = [self rangeToPrimaryTarget];
5562 desired_speed = maxFlightSpeed; // not injectors
5563 jink = kZeroVector;
5564 if (range > weaponRange || range > 0.8 * scannerRange || range == 0)
5565 {
5566 behaviour = BEHAVIOUR_CLOSE_WITH_TARGET;
5567 if ([forward_weapon_type isTurretLaser])
5568 {
5569 behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
5570 }
5571 frustration = 0.0;
5572 }
5573 [self trackPrimaryTarget:delta_t:YES];
5574 if ([forward_weapon_type isTurretLaser])
5575 {
5576 // most Thargoids will only have the forward weapon
5577 [self fireMainWeapon:range];
5578 }
5579 else
5580 {
5581 [self fireAftWeapon:range];
5582 }
5583 if (cloakAutomatic) [self activateCloakingDevice];
5584 if ([self hasProximityAlertIgnoringTarget:YES])
5585 [self avoidCollision];
5586
5587 if (behaviour != BEHAVIOUR_CLOSE_WITH_TARGET && weapon_temp > COMBAT_AI_WEAPON_TEMP_USABLE)
5588 {
5589 behaviour = BEHAVIOUR_ATTACK_TARGET;
5590 }
5591
5592 // remember to look where you're going?
5593 if (accuracy >= COMBAT_AI_ISNT_AWFUL && [self hasProximityAlertIgnoringTarget:YES])
5594 {
5595 [self avoidCollision];
5596 }
5597
5598
5599}

◆ behaviour_scripted_ai:

- (void) behaviour_scripted_ai: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

6153 :(double) delta_t
6154{
6155
6156 JSContext *context = OOJSAcquireContext();
6157 jsval rval = JSVAL_VOID;
6158 jsval deltaJS = JSVAL_VOID;
6159 NSDictionary *result = nil;
6160
6161 BOOL OK = JS_NewNumberValue(context, delta_t, &deltaJS);
6162 if (OK)
6163 {
6164 OK = [[self script] callMethod:OOJSID("scriptedAI")
6165 inContext:context
6166 withArguments:&deltaJS
6167 count:1
6168 result:&rval];
6169 }
6170
6171 if (!OK)
6172 {
6173 OOLog(@"ai.error",@"Could not call scriptedAI in ship script of %@, reverting to idle",self);
6174 behaviour = BEHAVIOUR_IDLE;
6175 OOJSRelinquishContext(context);
6176 return;
6177 }
6178
6179 if (!JSVAL_IS_OBJECT(rval))
6180 {
6181 OOLog(@"ai.error",@"Invalid return value of scriptedAI in ship script of %@, reverting to idle",self);
6182 behaviour = BEHAVIOUR_IDLE;
6183 OOJSRelinquishContext(context);
6184 return;
6185 }
6186
6187 result = OOJSNativeObjectFromJSObject(context, JSVAL_TO_OBJECT(rval));
6188 OOJSRelinquishContext(context);
6189
6190 // roll or roll factor
6191 if ([result objectForKey:@"stickRollFactor"] != nil)
6192 {
6193 stick_roll = [result oo_floatForKey:@"stickRollFactor"] * max_flight_roll;
6194 }
6195 else
6196 {
6197 stick_roll = [result oo_floatForKey:@"stickRoll"];
6198 }
6200 {
6202 }
6203 else if (stick_roll < -max_flight_roll)
6204 {
6206 }
6207
6208 // pitch or pitch factor
6209 if ([result objectForKey:@"stickPitchFactor"] != nil)
6210 {
6211 stick_pitch = [result oo_floatForKey:@"stickPitchFactor"] * max_flight_pitch;
6212 }
6213 else
6214 {
6215 stick_pitch = [result oo_floatForKey:@"stickPitch"];
6216 }
6218 {
6220 }
6221 else if (stick_pitch < -max_flight_pitch)
6222 {
6224 }
6225
6226 // yaw or yaw factor
6227 if ([result objectForKey:@"stickYawFactor"] != nil)
6228 {
6229 stick_yaw = [result oo_floatForKey:@"stickYawFactor"] * max_flight_yaw;
6230 }
6231 else
6232 {
6233 stick_yaw = [result oo_floatForKey:@"stickYaw"];
6234 }
6236 {
6238 }
6239 else if (stick_yaw < -max_flight_yaw)
6240 {
6242 }
6243
6244 // apply sticks to current flight profile
6245 [self applySticks:delta_t];
6246
6247 // desired speed
6248 if ([result objectForKey:@"desiredSpeedFactor"] != nil)
6249 {
6250 desired_speed = [result oo_floatForKey:@"desiredSpeedFactor"] * maxFlightSpeed;
6251 }
6252 else
6253 {
6254 desired_speed = [result oo_floatForKey:@"desiredSpeed"];
6255 }
6256
6257 if (desired_speed < 0.0)
6258 {
6259 desired_speed = 0.0;
6260 }
6261 // overspeed and injector use is handled by applyThrust
6262
6263 if (behaviour == BEHAVIOUR_SCRIPTED_ATTACK_AI)
6264 {
6265 NSString* chosen_weapon = [result oo_stringForKey:@"chosenWeapon" defaultValue:@"FORWARD"];
6266 double range = [self rangeToPrimaryTarget];
6267
6268 if ([chosen_weapon isEqualToString:@"FORWARD"])
6269 {
6270 [self fireMainWeapon:range];
6271 }
6272 else if ([chosen_weapon isEqualToString:@"AFT"])
6273 {
6274 [self fireAftWeapon:range];
6275 }
6276 else if ([chosen_weapon isEqualToString:@"PORT"])
6277 {
6278 [self firePortWeapon:range];
6279 }
6280 else if ([chosen_weapon isEqualToString:@"STARBOARD"])
6281 {
6282 [self fireStarboardWeapon:range];
6283 }
6284 }
6285}
id OOJSNativeObjectFromJSObject(JSContext *context, JSObject *object)
OOINLINE JSContext * OOJSAcquireContext(void)
OOINLINE void OOJSRelinquishContext(JSContext *context)
GLfloat max_flight_yaw
Definition ShipEntity.h:242

◆ behaviour_stop_still:

- (void) behaviour_stop_still: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4141 :(double) delta_t
4142{
4143 stick_roll = 0.0;
4144 stick_pitch = 0.0;
4145 stick_yaw = 0.0;
4146 [self applySticks:delta_t];
4147
4148
4149
4150}

◆ behaviour_track_as_turret:

- (void) behaviour_track_as_turret: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

6005 :(double) delta_t
6006{
6007 double aim = -2.0;
6008 ShipEntity *turret_owner = (ShipEntity *)[self owner];
6009 ShipEntity *turret_target = (ShipEntity *)[turret_owner primaryTarget];
6010 if (turret_owner && turret_target && [turret_owner hasHostileTarget])
6011 {
6012 aim = [self ballTrackLeadingTarget:delta_t atTarget:turret_target];
6013 if (aim > -1.0) // potential target
6014 {
6015 HPVector p = HPvector_subtract([turret_target position], [turret_owner position]);
6016 double cr = [turret_owner collisionRadius];
6017
6018 if (aim > .95)
6019 {
6020 [self fireTurretCannon:HPmagnitude(p) - cr];
6021 }
6022 return;
6023 }
6024 }
6025
6026 // can't fire on primary target; track secondary targets instead
6027 NSEnumerator *targetEnum = [turret_owner defenseTargetEnumerator];
6028 Entity *target = nil;
6029 while ((target = [[targetEnum nextObject] weakRefUnderlyingObject]))
6030 {
6031 // defense targets cannot be tracked while cloaked
6032 if ([target scanClass] == CLASS_NO_DRAW || [(ShipEntity *)target isCloaked] || [target energy] <= 0.0)
6033 {
6034 [turret_owner removeDefenseTarget:target];
6035 }
6036 else
6037 {
6038 double range = [turret_owner rangeToSecondaryTarget:target];
6039 if (range < weaponRange)
6040 {
6041 aim = [self ballTrackLeadingTarget:delta_t atTarget:target];
6042 if (aim > -1.0)
6043 { // tracking...
6044 HPVector p = HPvector_subtract([target position], [turret_owner position]);
6045 double cr = [turret_owner collisionRadius];
6046
6047 if (aim > .95)
6048 { // fire!
6049 [self fireTurretCannon:HPmagnitude(p) - cr];
6050 }
6051 return;
6052 }
6053 // else that target is out of range, try the next priority defense target
6054 }
6055 else if (range > scannerRange)
6056 {
6057 [turret_owner removeDefenseTarget:target];
6058 }
6059 }
6060 }
6061
6062 // turrets now don't return to neutral facing if no suitable target
6063 // better for shooting at targets that are on edge of fire arc
6064}
double rangeToSecondaryTarget:(Entity *target)
NSEnumerator * defenseTargetEnumerator()
BOOL isCloaked()

◆ behaviour_track_target:

- (void) behaviour_track_target: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4271 :(double) delta_t
4272{
4273 if ([self primaryTarget] == nil)
4274 {
4275 [self noteLostTargetAndGoIdle];
4276 return;
4277 }
4278 [self trackPrimaryTarget:delta_t:NO]; // applies sticks
4279 if ([self hasProximityAlertIgnoringTarget:YES])
4280 {
4281 [self avoidCollision];
4282 }
4283
4284}

◆ behaviour_tractored:

- (void) behaviour_tractored: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4186 :(double) delta_t
4187{
4189 ShipEntity* hauler = (ShipEntity*)[self owner];
4190 if ((hauler)&&([hauler isShip]))
4191 {
4193 double distance = [self rangeToDestination];
4194 if (distance < desired_range)
4195 {
4196 [self performTumble];
4197 [self setStatus:STATUS_IN_FLIGHT];
4198 [hauler scoopUp:self];
4199 return;
4200 }
4201 GLfloat tf = TRACTOR_FORCE / mass;
4202 // adjust for difference in velocity (spring rule)
4203 Vector dv = vector_between([self velocity], [hauler velocity]);
4204 GLfloat moment = delta_t * 0.25 * tf;
4205 velocity.x += moment * dv.x;
4206 velocity.y += moment * dv.y;
4207 velocity.z += moment * dv.z;
4208 // acceleration = force / mass
4209 // force proportional to distance (spring rule)
4210 HPVector dp = HPvector_between(position, _destination);
4211 moment = delta_t * 0.5 * tf;
4212 velocity.x += moment * dp.x;
4213 velocity.y += moment * dp.y;
4214 velocity.z += moment * dp.z;
4215 // force inversely proportional to distance
4216 GLfloat d2 = HPmagnitude2(dp);
4217 moment = (d2 > 0.0)? delta_t * 5.0 * tf / d2 : 0.0;
4218 if (d2 > 0.0)
4219 {
4220 velocity.x += moment * dp.x;
4221 velocity.y += moment * dp.y;
4222 velocity.z += moment * dp.z;
4223 }
4224 //
4225 if ([self status] == STATUS_BEING_SCOOPED)
4226 {
4227 BOOL lost_contact = (distance > hauler->collision_radius + collision_radius + 250.0f); // 250m range for tractor beam
4228 if ([hauler isPlayer])
4229 {
4230 switch ([(PlayerEntity*)hauler dialFuelScoopStatus])
4231 {
4234 lost_contact = YES; // don't draw
4235 break;
4236
4237 case SCOOP_STATUS_OKAY:
4239 break;
4240 }
4241 }
4242
4243 if (lost_contact) // 250m range for tractor beam
4244 {
4245 // escaped tractor beam
4246 [self setStatus:STATUS_IN_FLIGHT];
4247 behaviour = BEHAVIOUR_IDLE;
4248 [self setThrust:[self maxThrust]]; // restore old thrust.
4249 frustration = 0.0;
4250 [self setOwner:self];
4251 [shipAI exitStateMachineWithMessage:nil]; // exit nullAI.plist
4252 return;
4253 }
4254 else if ([hauler isPlayer])
4255 {
4256 [(PlayerEntity*)hauler setScoopsActive];
4257 }
4258 }
4259 }
4260
4261// being tractored; sticks ignored - CIM
4262 flightYaw = 0.0;
4263
4264 desired_speed = 0.0;
4265 thrust = 25.0; // used to damp velocity (must be less than hauler thrust)
4266
4267 thrust = 0.0; // must reset thrust now
4268}
@ SCOOP_STATUS_FULL_HOLD
@ SCOOP_STATUS_NOT_INSTALLED
@ SCOOP_STATUS_ACTIVE
@ SCOOP_STATUS_OKAY
#define TRACTOR_FORCE
Definition ShipEntity.h:92
HPVector absoluteTractorPosition()
void scoopUp:(ShipEntity *other)

◆ behaviour_tumble:

- (void) behaviour_tumble: (double) delta_t

Definition at line 2093 of file ShipEntity.m.

4178 :(double) delta_t
4179{
4180 [self applySticks:delta_t];
4181
4182
4183}

◆ bounty

- (OOCreditsQuantity) bounty

Reimplemented in PlayerEntity.

◆ broadcastAIMessage:

- (void) broadcastAIMessage: (NSString *) ai_message

Definition at line 14073 of file ShipEntity.m.

14186 :(NSString *) ai_message
14187{
14188 NSString *expandedMessage = OOExpand(ai_message);
14189
14190 [self checkScanner];
14191 unsigned i;
14192 for (i = 0; i < n_scanned_ships ; i++)
14193 {
14194 ShipEntity* ship = scanned_ships[i];
14195 [[ship getAI] message: expandedMessage];
14196 }
14197}
#define OOExpand(string,...)
void message:(NSString *ms)
Definition AI.m:600
ShipEntity * scanned_ships[MAX_SCAN_NUMBER+1]
Definition ShipEntity.h:413
unsigned n_scanned_ships
Definition ShipEntity.h:415

◆ broadcastDistressMessage

- (void) broadcastDistressMessage

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

764{
765 /*-- Locates all the stations, bounty hunters and police ships in range and tells them that you are under attack --*/
766 [self broadcastDistressMessageWithDumping:YES];
767}

◆ broadcastDistressMessageWithDumping:

- (void) broadcastDistressMessageWithDumping: (BOOL) dumpCargo

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

769 :(BOOL)dumpCargo
770{
771 [self checkScannerIgnoringUnpowered];
772 DESTROY(_foundTarget);
773
774 ShipEntity *aggressor_ship = (ShipEntity*)[self primaryAggressor];
775 if (aggressor_ship == nil) return;
776
777 // don't send too many distress messages at once, space them out semi-randomly
778 if (messageTime > 2.0 * randf()) return;
779
780 NSString *distress_message = nil;
781 BOOL is_buoy = (scanClass == CLASS_BUOY);
782 if (is_buoy) distress_message = @"[buoy-distress-call]";
783 else distress_message = @"[distress-call]";
784
785 unsigned i;
786 for (i = 0; i < n_scanned_ships; i++)
787 {
788 ShipEntity* ship = scanned_ships[i];
789
790 // dump cargo if energy is low
791 if (dumpCargo && !is_buoy && [self primaryAggressor] == ship && energy < 0.375 * maxEnergy)
792 {
793 [self ejectCargo];
794 [self performFlee];
795 }
796
797 // tell it! (only plist AIs send comms here; JS AIs are
798 // expected to handle their own)
799 if (ship->isPlayer && ![self hasNewAI])
800 {
801 [ship doScriptEvent:OOJSID("distressMessageReceived") withArgument:aggressor_ship andArgument:self];
802
803 if (!is_buoy && [self primaryAggressor] == ship && energy < 0.375 * maxEnergy)
804 {
805 [self sendExpandedMessage:@"[beg-for-mercy]" toShip:ship];
806 }
807 else if ([self bounty] == 0)
808 {
809 // only send distress message to player if plausibly sending
810 // one more generally
811 [self sendExpandedMessage:distress_message toShip:ship];
812 }
813
814 // reset the thanked_ship_id
815 DESTROY(_thankedShip);
816 }
817 else if ([self bounty] == 0 && [ship crew]) // Only clean ships can have their distress calls accepted
818 {
819 [ship doScriptEvent:OOJSID("distressMessageReceived") withArgument:aggressor_ship andArgument:self];
820
821 // we only can send distressMessages to ships that are known to have a "ACCEPT_DISTRESS_CALL" reaction
822 // in their AI, or they might react wrong on the added found_target.
823
824 // ship must have a plist AI for this next bit. JS AIs
825 // should already have done something sensible on
826 // distressMessageReceived
827 if (![self hasNewAI])
828 {
829 // FIXME: this test only works with core AIs
830 if (ship->isStation || [ship hasPrimaryRole:@"police"] || [ship hasPrimaryRole:@"hunter"])
831 {
832 [ship acceptDistressMessageFrom:self];
833 }
834 }
835 }
836 }
837}
void acceptDistressMessageFrom:(ShipEntity *other)
void doScriptEvent:withArgument:andArgument:(jsid message,[withArgument] id argument1,[andArgument] id argument2)

◆ broadcastEnergyBlastImminent

- (void) broadcastEnergyBlastImminent

Definition at line 7619 of file ShipEntity.m.

9485{
9486 // anyone further away than typical scanner range probably doesn't need to hear
9487 NSArray* targets = [UNIVERSE entitiesWithinRange:SCANNER_MAX_RANGE ofEntity:self];
9488 if ([targets count] > 0)
9489 {
9490 unsigned i;
9491 for (i = 0; i < [targets count]; i++)
9492 {
9493 Entity *e2 = [targets objectAtIndex:i];
9494 if ([e2 isShip])
9495 {
9496 ShipEntity *se = (ShipEntity *)e2;
9497 [se setFoundTarget:self];
9498 [se reactToAIMessage:@"CASCADE_WEAPON_DETECTED" context:@"nearby Q-mine"];
9499 [se doScriptEvent:OOJSID("cascadeWeaponDetected") withArgument:self];
9500 }
9501 }
9502 }
9503}
void doScriptEvent:withArgument:(jsid message,[withArgument] id argument)
void reactToAIMessage:context:(NSString *message,[context] NSString *debugContext)
void setFoundTarget:(Entity *targetEntity)

◆ broadcastHitByLaserFrom:

- (void) broadcastHitByLaserFrom: (ShipEntity*) aggressor_ship

Definition at line 14073 of file ShipEntity.m.

14095 :(ShipEntity *) aggressor_ship
14096{
14097 /*-- If you're clean, locates all police and stations in range and tells them OFFENCE_COMMITTED --*/
14098 if (!UNIVERSE) return;
14099 if ([self bounty]) return;
14100 if (!aggressor_ship) return;
14101
14102 if ( (scanClass == CLASS_NEUTRAL)||
14103 (scanClass == CLASS_STATION)||
14104 (scanClass == CLASS_BUOY)||
14105 (scanClass == CLASS_POLICE)||
14106 (scanClass == CLASS_MILITARY)||
14107 (scanClass == CLASS_PLAYER)) // only for active ships...
14108 {
14109 NSArray *authorities = nil;
14110 NSEnumerator *authEnum = nil;
14111 ShipEntity *auth = nil;
14112
14113 authorities = [UNIVERSE findShipsMatchingPredicate:AuthorityPredicate
14114 parameter:self
14115 inRange:-1
14116 ofEntity:nil];
14117 authEnum = [authorities objectEnumerator];
14118 while ((auth = [authEnum nextObject]))
14119 {
14120 [auth setFoundTarget:aggressor_ship];
14121 [auth doScriptEvent:OOJSID("offenceCommittedNearby") withArgument:aggressor_ship andArgument:self];
14122 [auth reactToAIMessage:@"OFFENCE_COMMITTED" context:@"combat update"];
14123 }
14124 }
14125}
OOCreditsQuantity bounty
Definition ShipEntity.h:300

◆ broadcastMessage:withUnpilotedOverride:

- (void) broadcastMessage: (NSString *) message_text
withUnpilotedOverride: (BOOL) unpilotedOverride 

Definition at line 14073 of file ShipEntity.m.

14200 :(NSString *) message_text withUnpilotedOverride:(BOOL) unpilotedOverride
14201{
14202 NSString *expandedMessage = OOExpand(message_text); // consistent with broadcast message.
14203
14204
14205 if (!crew && !unpilotedOverride)
14206 return; // nobody to send the signal and no override for unpiloted craft is set
14207
14208 [self checkScanner];
14209 unsigned i;
14210 for (i = 0; i < n_scanned_ships ; i++)
14211 {
14212 ShipEntity* ship = scanned_ships[i];
14213 if (![ship isPlayer]) [ship receiveCommsMessage:expandedMessage from:self];
14214 }
14215
14216 PlayerEntity *player = PLAYER; // make sure that the player always receives a message when in range
14217 // SCANNER_MAX_RANGE2 because it's the player's scanner range
14218 // which is important
14219 if (HPdistance2(position, [player position]) < SCANNER_MAX_RANGE2)
14220 {
14221 [self setCommsMessageColor];
14222 [player receiveCommsMessage:expandedMessage from:self];
14223 messageTime = 6.0;
14224 [UNIVERSE resetCommsLogColor];
14225 }
14226}
void receiveCommsMessage:from:(NSString *message_text, [from] ShipEntity *other)
double messageTime
Definition ShipEntity.h:382
NSArray * crew
Definition ShipEntity.h:399

◆ broadcastThargoidDestroyed

- (void) broadcastThargoidDestroyed

Definition at line 9593 of file ShipEntity.m.

14064{
14065 [[UNIVERSE findShipsMatchingPredicate:HasRolePredicate
14066 parameter:@"tharglet"
14067 inRange:SCANNER_MAX_RANGE
14068 ofEntity:self]
14069 makeObjectsPerformSelector:@selector(sendAIMessage:) withObject:@"THARGOID_DESTROYED"];
14070}

◆ calculateTargetPosition

- (HPVector) calculateTargetPosition

Definition at line 2093 of file ShipEntity.m.

6300{
6301 Entity *target = [self primaryTarget];
6302 if (target == nil)
6303 {
6304 return kZeroHPVector;
6305 }
6306 if (reactionTime <= 0.0)
6307 {
6308 return [target position];
6309 }
6310 double t = [UNIVERSE getTime] - trackingCurveTimes[1];
6311 return HPvector_add(HPvector_add(trackingCurveCoeffs[0], HPvector_multiply_scalar(trackingCurveCoeffs[1],t)), HPvector_multiply_scalar(trackingCurveCoeffs[2],t*t));
6312}
const HPVector kZeroHPVector
Definition OOHPVector.m:28
OOTimeAbsolute trackingCurveTimes[4]
Definition ShipEntity.h:451
float reactionTime
Definition ShipEntity.h:449
HPVector trackingCurveCoeffs[3]
Definition ShipEntity.h:452

◆ calculateTrackingCurve

- (void) calculateTrackingCurve

Definition at line 2093 of file ShipEntity.m.

6364{
6365 if (reactionTime <= 0.0)
6366 {
6370 return;
6371 }
6372 double t1 = trackingCurveTimes[2] - trackingCurveTimes[1],
6375 trackingCurveCoeffs[1] = HPvector_add(HPvector_add(
6376 HPvector_multiply_scalar(trackingCurvePositions[1], -(t1+t2)/(t1*t2)),
6377 HPvector_multiply_scalar(trackingCurvePositions[2], -t2/(t1*(t1-t2)))),
6378 HPvector_multiply_scalar(trackingCurvePositions[3], t1/(t2*(t1-t2))));
6379 trackingCurveCoeffs[2] = HPvector_add(HPvector_add(
6380 HPvector_multiply_scalar(trackingCurvePositions[1], 1/(t1*t2)),
6381 HPvector_multiply_scalar(trackingCurvePositions[2], 1/(t1*(t1-t2)))),
6382 HPvector_multiply_scalar(trackingCurvePositions[3], -1/(t2*(t1-t2))));
6383 return;
6384}
HPVector trackingCurvePositions[4]
Definition ShipEntity.h:450

◆ canAcceptEscort:

- (BOOL) canAcceptEscort: (ShipEntity *) potentialEscort

Definition at line 9593 of file ShipEntity.m.

13688 :(ShipEntity *)potentialEscort
13689{
13690 if (dockingInstructions) // we are busy with docking.
13691 {
13692 return NO;
13693 }
13694 if (scanClass != [potentialEscort scanClass]) // this makes sure that wingman can only select police, thargons only thargoids.
13695 {
13696 return NO;
13697 }
13698 if ([self bounty] == 0 && [potentialEscort bounty] != 0) // clean mothers can only accept clean escorts
13699 {
13700 return NO;
13701 }
13702 if (![self isEscort]) // self is NOT wingman or escort or thargon
13703 {
13704 return [potentialEscort isEscort]; // is wingman or escort or thargon
13705 }
13706 return NO;
13707}
BOOL isEscort()

◆ canAddEquipment:inContext:

- (BOOL) canAddEquipment: (NSString *) equipmentKey
inContext: (NSString *) context 

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3225 :(NSString *)equipmentKey inContext:(NSString *)context
3226{
3227 if ([equipmentKey hasSuffix:@"_DAMAGED"])
3228 {
3229 equipmentKey = [equipmentKey substringToIndex:[equipmentKey length] - [@"_DAMAGED" length]];
3230 }
3231
3232 NSString * lcEquipmentKey = [equipmentKey lowercaseString];
3233 if ([equipmentKey hasSuffix:@"MISSILE"]||[equipmentKey hasSuffix:@"MINE"]||([self isThargoid] && ([lcEquipmentKey hasPrefix:@"thargon"] || [lcEquipmentKey hasSuffix:@"thargon"])))
3234 {
3235 if (missiles >= max_missiles) return NO;
3236 }
3237
3239
3240 if (![eqType canCarryMultiple] && [self hasEquipmentItem:equipmentKey]) return NO;
3241 if (![self equipmentValidToAdd:equipmentKey inContext:context]) return NO;
3242
3243 return YES;
3244}

Referenced by ShipCanAwardEquipment().

+ Here is the caller graph for this function:

◆ canCollide

- (BOOL) canCollide
implementation

Reimplemented from Entity.

Reimplemented in PlayerEntity.

Definition at line 14954 of file ShipEntity.m.

2072{
2073 int status = [self status];
2074 if (status == STATUS_COCKPIT_DISPLAY || status == STATUS_DEAD || status == STATUS_BEING_SCOOPED)
2075 {
2076 return NO;
2077 }
2078
2079 if (isWreckage)
2080 {
2081 // wreckage won't collide
2082 return NO;
2083 }
2084
2085 if (isMissile && [self shotTime] < 0.25) // not yet fused
2086 {
2087 return NO;
2088 }
2089
2090 return YES;
2091}
unsigned isMissile
Definition ShipEntity.h:273
OOTimeDelta shotTime()

◆ canScoop:

- (BOOL) canScoop: (ShipEntity *) other

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12861 :(ShipEntity*)other
12862{
12863 if (other == nil) return NO;
12864 if (![self hasCargoScoop]) return NO;
12865 if ([cargo count] >= [self maxAvailableCargoSpace]) return NO;
12866 if (scanClass == CLASS_CARGO) return NO; // we have no power so we can't scoop
12867 if ([other scanClass] != CLASS_CARGO) return NO;
12868 if ([other cargoType] == CARGO_NOT_CARGO) return NO;
12869
12870 if ([other isStation]) return NO;
12871
12872 HPVector loc = HPvector_between(position, [other position]);
12873
12874 if (dot_product(v_forward, HPVectorToVector(loc)) < 0.0f) return NO; // Must be in front of us
12875 if ([self isPlayer] && dot_product(v_up, HPVectorToVector(loc)) > 0.0f) return NO; // player has to scoop on underside, give more flexibility to NPCs
12876
12877 return YES;
12878}
Vector v_up
Definition ShipEntity.h:200
BOOL hasCargoScoop()

◆ canStillTrackPrimaryTarget

- (BOOL) canStillTrackPrimaryTarget

Definition at line 9593 of file ShipEntity.m.

10096{
10098 if (target == nil)
10099 {
10100 return NO;
10101 }
10102 if (![self isValidTarget:target])
10103 {
10104 return NO;
10105 }
10106 double range2 = HPmagnitude2(HPvector_subtract([target position], position));
10107 if (range2 > scannerRange * scannerRange * 1.5625)
10108 {
10109 // 1.5625 = 1.25*1.25
10110 return NO;
10111 }
10112 // 1.81: can retain cloaked ships as a *primary* target now
10113/* if ([target isShip] && [(ShipEntity*)target isCloaked])
10114 {
10115 return NO;
10116 } */
10117 return YES;
10118}
id primaryTargetWithoutValidityCheck()

◆ cargo

- (NSMutableArray *) cargo

◆ cargoFlag

- (OOCargoFlag) cargoFlag

Definition at line 7619 of file ShipEntity.m.

8512{
8513 return cargo_flag;
8514}
OOCargoFlag cargo_flag
Definition ShipEntity.h:299

◆ cargoListForScripting

- (NSArray *) cargoListForScripting

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8412{
8413 NSMutableArray *list = [NSMutableArray array];
8414
8415 OOCommodityType good = nil;
8416 NSArray *goods = [[UNIVERSE commodityMarket] goods];
8417 NSUInteger i, j, commodityCount = [goods count];
8418 OOCargoQuantity quantityInHold[commodityCount];
8419
8420 for (i = 0; i < commodityCount; i++)
8421 {
8422 quantityInHold[i] = 0;
8423 }
8424 for (i = 0; i < [cargo count]; i++)
8425 {
8426 ShipEntity *container = [cargo objectAtIndex:i];
8427 j = [goods indexOfObject:[container commodityType]];
8428 quantityInHold[j] += [container commodityAmount];
8429 }
8430
8431 for (i = 0; i < commodityCount; i++)
8432 {
8433 if (quantityInHold[i] > 0)
8434 {
8435 NSMutableDictionary *commodity = [NSMutableDictionary dictionaryWithCapacity:4];
8436 good = [goods objectAtIndex:i];
8437 // commodity, quantity - keep consistency between .manifest and .contracts
8438 [commodity setObject:good forKey:@"commodity"];
8439 [commodity setObject:[NSNumber numberWithUnsignedInt:quantityInHold[i]] forKey:@"quantity"];
8440 [commodity setObject:[[UNIVERSE commodityMarket] nameForGood:good] forKey:@"displayName"];
8441 [commodity setObject:DisplayStringForMassUnitForCommodity(good) forKey:@"unit"];
8442 [list addObject:commodity];
8443 }
8444 }
8445
8446 return [[list copy] autorelease]; // return an immutable copy
8447}
NSString * OOCommodityType
Definition OOTypes.h:106
uint32_t OOCargoQuantity
Definition OOTypes.h:176
OOCargoQuantity commodityAmount()
OOCommodityType commodityType()

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ cargoQuantityOnBoard

- (OOCargoQuantity) cargoQuantityOnBoard

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8389{
8390 NSUInteger result = [[self cargo] count];
8391 NSAssert(result < UINT32_MAX, @"Cargo quantity out of bounds.");
8392 return (OOCargoQuantity)result;
8393}

◆ cargoType

- (OOCargoType) cargoType

Definition at line 7619 of file ShipEntity.m.

8398{
8399 return cargo_type;
8400}
OOCargoType cargo_type
Definition ShipEntity.h:298

◆ cascadeIfAppropriateWithDamageAmount:cascadeOwner:

- (BOOL) cascadeIfAppropriateWithDamageAmount: (double) amount
cascadeOwner: (Entity *) owner 

Definition at line 9593 of file ShipEntity.m.

13085 :(double)amount cascadeOwner:(Entity *)owner
13086{
13087 BOOL cascade = NO;
13088 switch ([self scanClass])
13089 {
13090 case CLASS_WORMHOLE:
13091 case CLASS_ROCK:
13092 case CLASS_CARGO:
13093 case CLASS_VISUAL_EFFECT:
13094 case CLASS_BUOY:
13095 // does not normally cascade
13096 if ((fuel > MIN_FUEL) || isStation)
13097 {
13098 //we have fuel onboard so we can still go pop, or we are a station which can
13099 }
13100 else break;
13101
13102 case CLASS_STATION:
13103 case CLASS_MINE:
13104 case CLASS_PLAYER:
13105 case CLASS_POLICE:
13106 case CLASS_MILITARY:
13107 case CLASS_THARGOID:
13108 case CLASS_MISSILE:
13109 case CLASS_NOT_SET:
13110 case CLASS_NO_DRAW:
13111 case CLASS_NEUTRAL:
13112 case CLASS_TARGET:
13113 // ...start a chain reaction, if we're dying and have a non-trivial amount of energy.
13115 {
13116 cascade = YES; // confirm we're cascading, then try to add our cascade to UNIVERSE.
13117 [UNIVERSE addEntity:[OOQuiriumCascadeEntity quiriumCascadeFromShip:self]];
13118 }
13119 break;
13120 //no default thanks, we want the compiler to tell us if we missed a case.
13121 }
13122 return cascade;
13123}
BOOL countsAsKill()

◆ checkAegis

- (void) checkAegis
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1467{
1468 switch (aegis_status)
1469 {
1471 [shipAI message:@"AEGIS_CLOSE_TO_MAIN_PLANET"];
1472 // 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
1473 //[shipAI message:@"AEGIS_CLOSE_TO_PLANET"]; // fires only for main planets, kept for compatibility with pre-1.72 AI plists.
1474 return;
1476 {
1477 Entity<OOStellarBody> *nearest = [self findNearestStellarBody];
1478
1479 if([nearest isSun])
1480 {
1481 [shipAI message:@"CLOSE_TO_SUN"];
1482 }
1483 else
1484 {
1485 [shipAI message:@"CLOSE_TO_PLANET"];
1486 if ([nearest planetType] == STELLAR_TYPE_MOON)
1487 {
1488 [shipAI message:@"CLOSE_TO_MOON"];
1489 }
1490 else
1491 {
1492 [shipAI message:@"CLOSE_TO_SECONDARY_PLANET"];
1493 }
1494 }
1495 return;
1496 }
1498 [shipAI message:@"AEGIS_IN_DOCKING_RANGE"];
1499 return;
1500 case AEGIS_NONE:
1501 [shipAI message:@"AEGIS_NONE"];
1502 return;
1503 }
1504
1505 NSLog(@"Aegis status for %@ has taken on invalid value %i. This is an internal error, please report it.", self, aegis_status);
1506 aegis_status = AEGIS_NONE;
1507 [shipAI message:@"AEGIS_NONE"];
1508}
#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

◆ checkCloseCollisionWith:

- (BOOL) checkCloseCollisionWith: (Entity *) other
implementation

Reimplemented from Entity.

Definition at line 2093 of file ShipEntity.m.

2169 :(Entity *)other
2170{
2171 if (other == nil) return NO;
2172 if ([collidingEntities containsObject:other]) return NO; // we know about this already!
2173
2174 ShipEntity *otherShip = nil;
2175 if ([other isShip]) otherShip = (ShipEntity *)other;
2176
2177 if ([self canScoop:otherShip]) return YES; // quick test - could this improve scooping for small ships? I think so!
2178
2179 if (otherShip != nil && trackCloseContacts)
2180 {
2181 // in update we check if close contacts have gone out of touch range (origin within our collision_radius)
2182 // here we check if something has come within that range
2183 HPVector otherPos = [otherShip position];
2184 OOUniversalID otherID = [otherShip universalID];
2185 NSString *other_key = [NSString stringWithFormat:@"%d", otherID];
2186
2187 if (![closeContactsInfo objectForKey:other_key] &&
2188 HPdistance2(position, otherPos) < collision_radius * collision_radius)
2189 {
2190 // calculate position with respect to our own position and orientation
2191 Vector dpos = HPVectorToVector(HPvector_between(position, otherPos));
2192 Vector rpos = make_vector(dot_product(dpos, v_right), dot_product(dpos, v_up), dot_product(dpos, v_forward));
2193 [closeContactsInfo setObject:[NSString stringWithFormat:@"%f %f %f", rpos.x, rpos.y, rpos.z] forKey: other_key];
2194
2195 // send AI a message about the touch
2197 _primaryTarget = [otherShip weakRetain];
2198 [self doScriptEvent:OOJSID("shipCloseContact") withArgument:otherShip andReactToAIMessage:@"CLOSE CONTACT"];
2199 _primaryTarget = temp;
2200 }
2201 }
2202
2203 /* This does not appear to save a significant amount of time in
2204 * most situations. No significant change in frame rate with a
2205 * 350-segment planetary ring at 1400 collision candidates, even
2206 * on old hardware. There are perhaps situations in which it could
2207 * be a significant optimisation, but those are likely to also be
2208 * the situations where the effect of adding hundreds of extra
2209 * false-positive collisions leaves the player returning to a
2210 * mess... So, commented out: CIM 21 Jan 2014
2211 if (zero_distance > CLOSE_COLLISION_CHECK_MAX_RANGE2) // don't work too hard on entities that are far from the player
2212 return YES;
2213 */
2214
2215 if (otherShip != nil)
2216 {
2217 // check hull octree versus other hull octree
2218 collider = doOctreesCollide(self, otherShip);
2219 return (collider != nil);
2220 }
2221
2222 // default at this stage is to say YES they've collided!
2223 collider = other;
2224 return YES;
2225}
uint16_t OOUniversalID
Definition OOTypes.h:189
NSMutableArray * collidingEntities
Definition Entity.h:148
Entity * collider
Definition Entity.h:128
unsigned trackCloseContacts
Definition ShipEntity.h:262
ShipEntity * doOctreesCollide(ShipEntity *prime, ShipEntity *other)
NSMutableDictionary * closeContactsInfo
Definition ShipEntity.h:402
Vector v_right
Definition ShipEntity.h:200

◆ checkCourseToDestination

- (void) checkCourseToDestination
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ checkDistanceTravelled

- (void) checkDistanceTravelled
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1778{
1779 if (distanceTravelled > desired_range)
1780 [shipAI message:@"GONE_BEYOND_RANGE"];
1781}

◆ checkEnergy

- (void) checkEnergy
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1512{
1513 if (energy == maxEnergy)
1514 {
1515 [shipAI message:@"ENERGY_FULL"];
1516 return;
1517 }
1518 if (energy >= maxEnergy * 0.75)
1519 {
1520 [shipAI message:@"ENERGY_HIGH"];
1521 return;
1522 }
1523 if (energy <= maxEnergy * 0.25)
1524 {
1525 [shipAI message:@"ENERGY_LOW"];
1526 return;
1527 }
1528 [shipAI message:@"ENERGY_MEDIUM"];
1529}

◆ checkForAegis

- (OOAegisStatus) checkForAegis

Definition at line 7619 of file ShipEntity.m.

7712{
7713 Entity<OOStellarBody> *nearest = [self findNearestStellarBody];
7714 BOOL sunGoneNova = [[UNIVERSE sun] goneNova];
7715
7716 if (nearest == nil)
7717 {
7718 if (aegis_status != AEGIS_NONE)
7719 {
7720 // Planet disappeared!
7721 [self transitionToAegisNone];
7722 }
7723 return AEGIS_NONE;
7724 }
7725 // check planet
7726 float cr = [nearest radius];
7727 float cr2 = cr * cr;
7728 OOAegisStatus result = AEGIS_NONE;
7729 float d2 = HPmagnitude2(HPvector_subtract([nearest position], [self position]));
7730 // not scannerRange: aegis shouldn't depend on that
7731 float sd2 = SCANNER_MAX_RANGE2 * 10.0f;
7732
7733 // check if nearing a surface
7734 unsigned wasNearPlanetSurface = isNearPlanetSurface; // isNearPlanetSurface is a bit flag, not an actual BOOL
7735 isNearPlanetSurface = (d2 - cr2) < (250000.0f + 1000.0f * cr); //less than 500m from the surface: (a+b)*(a+b) = a*a+b*b +2*a*b
7736
7737
7738 if (EXPECT_NOT((wasNearPlanetSurface != isNearPlanetSurface) && !suppressAegisMessages))
7739 {
7741 {
7742 [self doScriptEvent:OOJSID("shipApproachingPlanetSurface") withArgument:nearest];
7743 [shipAI reactToMessage:@"APPROACHING_SURFACE" context:@"flight update"];
7744 }
7745 else
7746 {
7747 [self doScriptEvent:OOJSID("shipLeavingPlanetSurface") withArgument:nearest];
7748 [shipAI reactToMessage:@"LEAVING_SURFACE" context:@"flight update"];
7749 }
7750 }
7751
7752 // being close to the station takes precedence over planets
7753 StationEntity *the_station = [UNIVERSE station];
7754 if (the_station)
7755 {
7756 sd2 = HPmagnitude2(HPvector_subtract([the_station position], [self position]));
7757 }
7758 // again, notional scanner range is intentional
7759 if (sd2 < SCANNER_MAX_RANGE2 * 4.0f) // double scanner range
7760 {
7761 result = AEGIS_IN_DOCKING_RANGE;
7762 }
7763 else if (EXPECT_NOT(isNearPlanetSurface || d2 < cr2 * 9.0f)) // to 3x radius of any planet/moon - or 500m of tiny ones,
7764 {
7766 if (EXPECT((OOPlanetEntity *)nearest == [UNIVERSE planet]))
7767 {
7769 }
7770 }
7771 // need to do this check separately from above case to avoid oddity where
7772 // main planet and small moon are at just the wrong distance. - CIM
7773 if (result != AEGIS_CLOSE_TO_MAIN_PLANET && result != AEGIS_IN_DOCKING_RANGE && !sunGoneNova)
7774 {
7775 // are we also close to the main planet?
7776 OOPlanetEntity *mainPlanet = [UNIVERSE planet];
7777 d2 = HPmagnitude2(HPvector_subtract([mainPlanet position], [self position]));
7778 cr2 = [mainPlanet radius];
7779 cr2 *= cr2;
7780 if (d2 < cr2 * 9.0f)
7781 {
7782 nearest = mainPlanet;
7784 }
7785 }
7786
7787
7788 /* Rewrote aegis stuff and tested it against redux.oxp that adds multiple planets and moons.
7789 Made sure AI scripts can differentiate between MAIN and NON-MAIN planets so they can decide
7790 if they can dock at the systemStation or just any station.
7791 Added sun detection so route2Patrol can turn before they heat up in the sun.
7792 -- Eric 2009-07-11
7793
7794 More rewriting of the aegis stuff, it's now a bit faster and works properly when moving
7795 from one secondary planet/moon vicinity to another one. -- Kaks 20120917
7796 */
7798 {
7799 // script/AI messages on change in status
7801 {
7802 [self doScriptEvent:OOJSID("shipExitedStationAegis") withArgument:the_station];
7803 [shipAI message:@"AEGIS_LEAVING_DOCKING_RANGE"];
7804 }
7805
7806 if (EXPECT_NOT(result == AEGIS_IN_DOCKING_RANGE && aegis_status != result))
7807 {
7808 [self doScriptEvent:OOJSID("shipEnteredStationAegis") withArgument:the_station];
7809 [shipAI message:@"AEGIS_IN_DOCKING_RANGE"];
7810
7811 if([self lastAegisLock] == nil && !sunGoneNova) // With small main planets the station aegis can come before planet aegis
7812 {
7813 [self doScriptEvent:OOJSID("shipEnteredPlanetaryVicinity") withArgument:[UNIVERSE planet]];
7814 [self setLastAegisLock:[UNIVERSE planet]];
7815 }
7816 }
7817 else if (EXPECT_NOT(result == AEGIS_NONE && aegis_status != result))
7818 {
7819 if([self lastAegisLock] == nil && !sunGoneNova)
7820 {
7821 [self setLastAegisLock:[UNIVERSE planet]]; // in case of a first launch from a near-planet station.
7822 }
7823 [self transitionToAegisNone];
7824 }
7825 // approaching..
7826 else if (EXPECT_NOT((result == AEGIS_CLOSE_TO_ANY_PLANET || result == AEGIS_CLOSE_TO_MAIN_PLANET) && [self lastAegisLock] != nearest))
7827 {
7828 if(aegis_status != AEGIS_NONE && [self lastAegisLock] != nil) // we were close to another stellar body
7829 {
7830 [self doScriptEvent:OOJSID("shipExitedPlanetaryVicinity") withArgument:[self lastAegisLock]];
7831 [shipAI message:@"AWAY_FROM_PLANET"]; // fires for suns, planets and moons.
7832 }
7833 [self doScriptEvent:OOJSID("shipEnteredPlanetaryVicinity") withArgument:nearest];
7834 [self setLastAegisLock:nearest];
7835
7836 if (EXPECT_NOT([nearest isSun]))
7837 {
7838 [shipAI message:@"CLOSE_TO_SUN"];
7839 }
7840 else
7841 {
7842 [shipAI message:@"CLOSE_TO_PLANET"];
7843
7844 if (EXPECT(result == AEGIS_CLOSE_TO_MAIN_PLANET))
7845 {
7846 // It's been years since 1.71 - it should be safe enough to comment out the line below for 1.77/1.78 -- Kaks 20120917
7847 //[shipAI message:@"AEGIS_CLOSE_TO_PLANET"]; // fires only for main planets, kept for compatibility with pre-1.72 AI plists.
7848 [shipAI message:@"AEGIS_CLOSE_TO_MAIN_PLANET"]; // fires only for main planet.
7849 }
7850 else if (EXPECT_NOT([nearest planetType] == STELLAR_TYPE_MOON))
7851 {
7852 [shipAI message:@"CLOSE_TO_MOON"];
7853 }
7854 else
7855 {
7856 [shipAI message:@"CLOSE_TO_SECONDARY_PLANET"];
7857 }
7858 }
7859 }
7860
7861
7862 }
7863 if (result == AEGIS_NONE)
7864 {
7865 [self setLastAegisLock:nil];
7866 }
7867
7868 aegis_status = result; // put this here
7869 return result;
7870}
OOAegisStatus
Definition OOTypes.h:60
BOOL isSun()
Definition Entity.m:167
unsigned isNearPlanetSurface
Definition ShipEntity.h:263
unsigned suppressAegisMessages
Definition ShipEntity.h:272
OOAegisStatus aegis_status
Definition ShipEntity.h:378
Entity< OOStellarBody > * lastAegisLock()

◆ checkForFullHold

- (void) checkForFullHold
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1168{
1169 if (!max_cargo)
1170 {
1171 [shipAI message:@"NO_CARGO_BAY"];
1172 }
1173 else if ([cargo count] >= [self maxAvailableCargoSpace])
1174 {
1175 [shipAI message:@"HOLD_FULL"];
1176 }
1177 else
1178 {
1179 [shipAI message:@"HOLD_NOT_FULL"];
1180 }
1181}

◆ checkForMotherStation

- (void) checkForMotherStation
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2067{
2068 ShipEntity *motherStation = [[self group] leader];
2069 if ((!motherStation) || (!(motherStation->isStation)))
2070 {
2071 [shipAI message:@"NOTHING_FOUND"];
2072 return;
2073 }
2074 double found_d2 = scannerRange * scannerRange;
2075 HPVector v0 = motherStation->position;
2076 if (HPdistance2(v0,position) > found_d2)
2077 {
2078 [shipAI message:@"NOTHING_FOUND"];
2079 return;
2080 }
2081 [shipAI message:@"STATION_FOUND"];
2082}

◆ checkForNormalSpace

- (void) checkForNormalSpace
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2482{
2483 if ([UNIVERSE sun] && [UNIVERSE planet])
2484 [shipAI message:@"NORMAL_SPACE"];
2485 else
2486 [shipAI message:@"INTERSTELLAR_SPACE"];
2487}

◆ checkFoundTarget

- (void) checkFoundTarget
implementation

Provided by category ShipEntity(OOAIPrivate).

Definition at line 1 of file ShipEntityAI.m.

2746{
2747 if ([self foundTarget] != nil)
2748 {
2749 [shipAI message:@"TARGET_FOUND"];
2750 }
2751 else
2752 {
2753 [shipAI message:@"NOTHING_FOUND"];
2754 }
2755}

◆ checkGroupOddsVersusTarget

- (void) checkGroupOddsVersusTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1860{
1861 NSUInteger ownGroupCount = [[self group] count] + (ranrot_rand() & 3); // add a random fudge factor
1862 NSUInteger targetGroupCount = [[[self primaryTarget] group] count] + (ranrot_rand() & 3); // add a random fudge factor
1863
1864 if (ownGroupCount == targetGroupCount)
1865 {
1866 [shipAI message:@"ODDS_LEVEL"];
1867 }
1868 else if (ownGroupCount > targetGroupCount)
1869 {
1870 [shipAI message:@"ODDS_GOOD"];
1871 }
1872 else
1873 {
1874 [shipAI message:@"ODDS_BAD"];
1875 }
1876}

◆ checkHeatInsulation

- (void) checkHeatInsulation
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1532{
1533 float minInsulation = 1000 / [self maxFlightSpeed] + 1;
1534
1535 if ([self heatInsulation] < minInsulation)
1536 {
1537 [shipAI message:@"INSULATION_POOR"];
1538 return;
1539 }
1540 [shipAI message:@"INSULATION_OK"];
1541}

◆ checkOwnLegalStatus

- (void) checkOwnLegalStatus
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ checkScanner

- (void) checkScanner

Definition at line 9593 of file ShipEntity.m.

9820{
9821 Entity* scan;
9822 n_scanned_ships = 0;
9823 //
9824 scan = z_previous; while ((scan)&&(scan->isShip == NO)) scan = scan->z_previous; // skip non-ships
9825 GLfloat scannerRange2 = scannerRange * scannerRange;
9826 while ((scan)&&(scan->position.z > position.z - scannerRange)&&(n_scanned_ships < MAX_SCAN_NUMBER))
9827 {
9828 // can't scan cloaked ships
9829 if (scan->isShip && ![(ShipEntity*)scan isCloaked] && [self isValidTarget:scan])
9830 {
9831 distance2_scanned_ships[n_scanned_ships] = HPdistance2(position, scan->position);
9832 if (distance2_scanned_ships[n_scanned_ships] < scannerRange2)
9833 scanned_ships[n_scanned_ships++] = (ShipEntity*)scan;
9834 }
9835 scan = scan->z_previous; while ((scan)&&(scan->isShip == NO)) scan = scan->z_previous;
9836 }
9837 //
9838 scan = z_next; while ((scan)&&(scan->isShip == NO)) scan = scan->z_next; // skip non-ships
9839 while ((scan)&&(scan->position.z < position.z + scannerRange)&&(n_scanned_ships < MAX_SCAN_NUMBER))
9840 {
9841 if (scan->isShip && ![(ShipEntity*)scan isCloaked] && [self isValidTarget:scan])
9842 {
9843 distance2_scanned_ships[n_scanned_ships] = HPdistance2(position, scan->position);
9844 if (distance2_scanned_ships[n_scanned_ships] < scannerRange2)
9845 scanned_ships[n_scanned_ships++] = (ShipEntity*)scan;
9846 }
9847 scan = scan->z_next; while ((scan)&&(scan->isShip == NO)) scan = scan->z_next; // skip non-ships
9848 }
9849 //
9850 scanned_ships[n_scanned_ships] = nil; // terminate array
9851}
#define MAX_SCAN_NUMBER
Definition ShipEntity.h:97
Entity * z_next
Definition Entity.h:122
Entity * z_previous
Definition Entity.h:122
GLfloat distance2_scanned_ships[MAX_SCAN_NUMBER+1]
Definition ShipEntity.h:414

◆ checkScannerIgnoringUnpowered

- (void) checkScannerIgnoringUnpowered

Definition at line 9593 of file ShipEntity.m.

9855{
9856 Entity* scan;
9857 n_scanned_ships = 0;
9858 //
9859 GLfloat scannerRange2 = scannerRange * scannerRange;
9860 scan = z_previous;
9861 while ((scan)&&((scan->isShip == NO)||(scan->scanClass==CLASS_ROCK)||(scan->scanClass==CLASS_CARGO)))
9862 {
9863 scan = scan->z_previous; // skip non-ships
9864 }
9865 while ((scan)&&(scan->position.z > position.z - scannerRange)&&(n_scanned_ships < MAX_SCAN_NUMBER))
9866 {
9867 if (scan->isShip && ![(ShipEntity*)scan isCloaked])
9868 {
9869 distance2_scanned_ships[n_scanned_ships] = HPdistance2(position, scan->position);
9870 if (distance2_scanned_ships[n_scanned_ships] < scannerRange2)
9871 scanned_ships[n_scanned_ships++] = (ShipEntity*)scan;
9872 }
9873 scan = scan->z_previous;
9874 while ((scan)&&((scan->isShip == NO)||(scan->scanClass==CLASS_ROCK)||(scan->scanClass==CLASS_CARGO)))
9875 {
9876 scan = scan->z_previous; // skip non-ships
9877 }
9878 }
9879 //
9880 scan = z_next;
9881 while ((scan)&&((scan->isShip == NO)||(scan->scanClass==CLASS_ROCK)||(scan->scanClass==CLASS_CARGO)))
9882 {
9883 scan = scan->z_next; // skip non-ships
9884 }
9885
9886 while ((scan)&&(scan->position.z < position.z + scannerRange)&&(n_scanned_ships < MAX_SCAN_NUMBER))
9887 {
9888 if (scan->isShip && ![(ShipEntity*)scan isCloaked])
9889 {
9890 distance2_scanned_ships[n_scanned_ships] = HPdistance2(position, scan->position);
9891 if (distance2_scanned_ships[n_scanned_ships] < scannerRange2)
9892 scanned_ships[n_scanned_ships++] = (ShipEntity*)scan;
9893 }
9894 scan = scan->z_next;
9895 while ((scan)&&((scan->isShip == NO)||(scan->scanClass==CLASS_ROCK)||(scan->scanClass==CLASS_CARGO)))
9896 {
9897 scan = scan->z_next; // skip non-ships
9898 }
9899 }
9900 //
9901 scanned_ships[n_scanned_ships] = nil; // terminate array
9902}
OOScanClass scanClass
Definition Entity.h:106

◆ checkShipsInVicinityForWitchJumpExit

- (int) checkShipsInVicinityForWitchJumpExit

Definition at line 14073 of file ShipEntity.m.

14344{
14345 // checks if there are any large masses close by
14346 // since we want to place the space station at least 10km away
14347 // the formula we'll use is K x m / d2 < 1.0
14348 // (m = mass, d2 = distance squared)
14349 // coriolis station is mass 455,223,200
14350 // 10km is 10,000m,
14351 // 10km squared is 100,000,000
14352 // therefore K is 0.22 (approx)
14353
14354 int result = NO_TARGET;
14355
14356 GLfloat k = 0.1;
14357
14358 int ent_count = UNIVERSE->n_entities;
14359 Entity** uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
14360 ShipEntity* my_entities[ent_count];
14361 int i;
14362
14363 int ship_count = 0;
14364 for (i = 0; i < ent_count; i++)
14365 if ((uni_entities[i]->isShip)&&(uni_entities[i] != self))
14366 my_entities[ship_count++] = (ShipEntity*)[uni_entities[i] retain]; // retained
14367 //
14368 for (i = 0; (i < ship_count)&&(result == NO_TARGET) ; i++)
14369 {
14370 ShipEntity* ship = my_entities[i];
14371 HPVector delta = HPvector_between(position, ship->position);
14372 GLfloat d2 = HPmagnitude2(delta);
14373 if (![ship isPlayer] || ![PLAYER isDocked])
14374 { // player doesn't block if docked
14375 if ((k * [ship mass] > d2)&&(d2 < SCANNER_MAX_RANGE2)) // if you go off (typical) scanner from a blocker - it ceases to block
14376 result = [ship universalID];
14377 }
14378 }
14379 for (i = 0; i < ship_count; i++)
14380 [my_entities[i] release]; // released
14381
14382 return result;
14383}

◆ checkTargetLegalStatus

- (void) checkTargetLegalStatus
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ clearSubEntities

- (void) clearSubEntities

Definition at line 14954 of file ShipEntity.m.

1156{
1157 [subEntities makeObjectsPerformSelector:@selector(setOwner:) withObject:nil]; // Ensure backlinks are broken
1158 [subEntities release];
1159 subEntities = nil;
1160
1161 // reset size & mass!
1162 collision_radius = [self findCollisionRadius];
1164 float density = [[self shipInfoDictionary] oo_floatForKey:@"density" defaultValue:1.0f];
1165 if (octree) mass = (GLfloat)(density * 20.0f * [octree volume]);
1166}
float volume()
Octree * octree
Definition ShipEntity.h:423

Referenced by ShipRestoreSubEntities().

+ Here is the caller graph for this function:

◆ collectBountyFor:

- (void) collectBountyFor: (ShipEntity *) other

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

9687 :(ShipEntity *)other
9688{
9689 if ([other isPolice]) // oops, we shot a copper!
9690 {
9691 [self markAsOffender:64 withReason:kOOLegalStatusReasonAttackedPolice];
9692 }
9693}
BOOL isPolice()

◆ collideWithShip:

- (BOOL) collideWithShip: (ShipEntity *) other

Reimplemented in StationEntity.

Definition at line 9593 of file ShipEntity.m.

12676 :(ShipEntity *)other
12677{
12678 HPVector hploc;
12679 Vector loc;
12680 double dam1, dam2;
12681
12682 if (!other)
12683 return NO;
12684
12685 ShipEntity* otherParent = [other parentEntity];
12686 BOOL otherIsStation = other == [UNIVERSE station];
12687 // calculate line of centers using centres
12688 hploc = HPvector_normal_or_zbasis(HPvector_subtract([other absolutePositionForSubentity], position));
12689 loc = HPVectorToVector(hploc);
12690
12691
12692 if ([self canScoop:other])
12693 {
12694 [self scoopIn:other];
12695 return NO;
12696 }
12697 if ([other canScoop:self])
12698 {
12699 [other scoopIn:self];
12700 return NO;
12701 }
12702 if (universalID == NO_TARGET)
12703 return NO;
12704 if (other->universalID == NO_TARGET)
12705 return NO;
12706
12707 // find velocity along line of centers
12708 //
12709 // momentum = mass x velocity
12710 // ke = mass x velocity x velocity
12711 //
12712 GLfloat m1 = mass; // mass of self
12713 GLfloat m2 = [other mass]; // mass of other
12714
12715 // starting velocities:
12716 Vector v, vel1b = [self velocity];
12717
12718 if (otherParent != nil)
12719 {
12720 // Subentity
12721 /* TODO: if the subentity is rotating (subentityRotationalVelocity is
12722 not 1 0 0 0) we should calculate the tangential velocity from the
12723 other's position relative to our absolute position and add that in.
12724 */
12725 v = [otherParent velocity];
12726 }
12727 else
12728 {
12729 v = [other velocity];
12730 }
12731
12732 v = vector_subtract(vel1b, v);
12733
12734 GLfloat v2b = dot_product(v, loc); // velocity of other along loc before collision
12735
12736 GLfloat v1a = sqrt(v2b * v2b * m2 / m1); // velocity of self along loc after elastic collision
12737 if (v2b < 0.0f) v1a = -v1a; // in same direction as v2b
12738
12739 // are they moving apart at over 1m/s already?
12740 if (v2b < 0.0f)
12741 {
12742 if (v2b < -1.0f) return NO;
12743 else
12744 {
12745 position = HPvector_subtract(position, hploc); // adjust self position
12746 v = kZeroVector; // go for the 1m/s solution
12747 }
12748 }
12749
12750 // convert change in velocity into damage energy (KE)
12751 dam1 = m2 * v2b * v2b / 50000000;
12752 dam2 = m1 * v2b * v2b / 50000000;
12753
12754 // calculate adjustments to velocity after collision
12755 Vector vel1a = vector_multiply_scalar(loc, -v1a);
12756 Vector vel2a = vector_multiply_scalar(loc, v2b);
12757
12758 if (magnitude2(v) <= 0.1) // virtually no relative velocity - we must provide at least 1m/s to avoid conjoined objects
12759 {
12760 vel1a = vector_multiply_scalar(loc, -1);
12761 vel2a = loc;
12762 }
12763
12764 // apply change in velocity
12765 if (otherParent != nil)
12766 {
12767 [otherParent adjustVelocity:vel2a]; // move the otherParent not the subentity
12768 }
12769 else
12770 {
12771 [other adjustVelocity:vel2a];
12772 }
12773
12774 [self adjustVelocity:vel1a];
12775
12776 BOOL selfDestroyed = (dam1 > energy);
12777 BOOL otherDestroyed = (dam2 > [other energy]) && !otherIsStation;
12778
12779 if (dam1 > 0.05)
12780 {
12781 [self takeScrapeDamage: dam1 from:other];
12782 if (selfDestroyed) // inelastic! - take xplosion velocity damage instead
12783 {
12784 vel2a = vector_multiply_scalar(vel2a, -1);
12785 [other adjustVelocity:vel2a];
12786 }
12787 }
12788
12789 if (dam2 > 0.05)
12790 {
12791 if (otherParent != nil && ![otherParent isFrangible])
12792 {
12793 [otherParent takeScrapeDamage: dam2 from:self];
12794 }
12795 else
12796 {
12797 [other takeScrapeDamage: dam2 from:self];
12798 }
12799
12800 if (otherDestroyed) // inelastic! - take explosion velocity damage instead
12801 {
12802 vel1a = vector_multiply_scalar(vel1a, -1);
12803 [self adjustVelocity:vel1a];
12804 }
12805 }
12806
12807 if (!selfDestroyed && !otherDestroyed)
12808 {
12809 float t = 10.0 * [UNIVERSE getTimeDelta]; // 10 ticks
12810
12811 HPVector pos1a = HPvector_add([self position], vectorToHPVector(vector_multiply_scalar(loc, t * v1a)));
12812 [self setPosition:pos1a];
12813
12814 if (!otherIsStation)
12815 {
12816 HPVector pos2a = HPvector_add([other position], vectorToHPVector(vector_multiply_scalar(loc, t * v2b)));
12817 [other setPosition:pos2a];
12818 }
12819 }
12820
12821 // remove self from other's collision list
12822 [[other collisionArray] removeObject:self];
12823
12824 [self doScriptEvent:OOJSID("shipCollided") withArgument:other andReactToAIMessage:@"COLLISION"];
12825 [other doScriptEvent:OOJSID("shipCollided") withArgument:self andReactToAIMessage:@"COLLISION"];
12826
12827 return YES;
12828}
HPVector absolutePositionForSubentity()
Definition Entity.m:669
ShipEntity * parentEntity()
Definition Entity.m:589
unsigned isFrangible
Definition ShipEntity.h:264
void takeScrapeDamage:from:(double amount,[from] Entity *ent)
void adjustVelocity:(Vector xVel)

◆ collisionExceptedFor:

- (BOOL) collisionExceptedFor: (ShipEntity *) ship

Definition at line 9593 of file ShipEntity.m.

11148 :(ShipEntity *)ship
11149{
11151 {
11152 return NO;
11153 }
11154 return [_collisionExceptions containsObject:ship];
11155}

◆ collisionExceptions

- (NSArray *) collisionExceptions

Definition at line 9593 of file ShipEntity.m.

11119{
11121 {
11122 return [NSArray array];
11123 }
11124 return [_collisionExceptions allObjects];
11125}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ commodityAmount

- (OOCargoQuantity) commodityAmount

Definition at line 7619 of file ShipEntity.m.

8363{
8364 return commodity_amount;
8365}
OOCargoQuantity commodity_amount
Definition ShipEntity.h:364

◆ commodityType

- (OOCommodityType) commodityType

Definition at line 7619 of file ShipEntity.m.

8357{
8358 return commodity_type;
8359}
OOCommodityType commodity_type
Definition ShipEntity.h:363

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ commsMessage:

- (void) commsMessage: (NSString *) valueString
implementation

Reimplemented in PlayerEntity.

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ commsMessage:withUnpilotedOverride:

- (void) commsMessage: (NSString *) valueString
withUnpilotedOverride: (BOOL) unpilotedOverride 

Definition at line 14073 of file ShipEntity.m.

14247 :(NSString *)valueString withUnpilotedOverride:(BOOL)unpilotedOverride
14248{
14249 Random_Seed very_random_seed;
14250 very_random_seed.a = rand() & 255;
14251 very_random_seed.b = rand() & 255;
14252 very_random_seed.c = rand() & 255;
14253 very_random_seed.d = rand() & 255;
14254 very_random_seed.e = rand() & 255;
14255 very_random_seed.f = rand() & 255;
14256 seed_RNG_only_for_planet_description(very_random_seed);
14257
14258 [self broadcastMessage:valueString withUnpilotedOverride:unpilotedOverride];
14259}
void seed_RNG_only_for_planet_description(Random_Seed s_seed)

Referenced by ShipCommsMessage().

+ Here is the caller graph for this function:

◆ commsMessageByUnpiloted:

- (void) commsMessageByUnpiloted: (NSString *) valueString
implementation

Reimplemented in PlayerEntity.

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1671 :(NSString *)valueString
1672{
1673 [self commsMessage:valueString withUnpilotedOverride:YES];
1674}

◆ compareBeaconCodeWith:

- (NSComparisonResult) compareBeaconCodeWith: (Entity<OOBeaconEntity> *) other
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 9593 of file ShipEntity.m.

9696 :(Entity<OOBeaconEntity> *) other
9697{
9698 return [[self beaconCode] compare:[other beaconCode] options: NSCaseInsensitiveSearch];
9699}

◆ ComparePlanetsBySurfaceDistance

- (NSComparisonResult) ComparePlanetsBySurfaceDistance (id) i1
(id) i2
(void *) context 
implementation

Definition at line 7619 of file ShipEntity.m.

7620{
7621 HPVector p = [(ShipEntity*) context position];
7622 OOPlanetEntity* e1 = i1;
7623 OOPlanetEntity* e2 = i2;
7624
7625 float p1 = SurfaceDistanceSqaredV(p, e1);
7626 float p2 = SurfaceDistanceSqaredV(p, e2);
7627
7628 if (p1 < p2) return NSOrderedAscending;
7629 if (p1 > p2) return NSOrderedDescending;
7630
7631 return NSOrderedSame;
7632}
static float SurfaceDistanceSqaredV(HPVector reference, Entity< OOStellarBody > *stellar)

◆ considerFiringMissile:

- (void) considerFiringMissile: (double) delta_t

Definition at line 9593 of file ShipEntity.m.

12132 :(double)delta_t
12133{
12134 int missile_chance = 0;
12135 int rhs = 3.2 / delta_t;
12136 if (rhs) missile_chance = 1 + (ranrot_rand() % rhs);
12137
12138 double hurt_factor = 16 * pow(energy/maxEnergy, 4.0);
12139 if (missiles > missile_chance * hurt_factor)
12140 {
12141 [self fireMissile];
12142 }
12143}

◆ contractListForScripting

- (NSArray *) contractListForScripting

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3323{
3324 return [NSArray array];
3325}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ coordinates

- (HPVector) coordinates

◆ coordinatesForEscortPosition:

- (HPVector) coordinatesForEscortPosition: (unsigned) idx
implementation

Provided by category ShipEntity(Private).

Definition at line 9593 of file ShipEntity.m.

13821 :(unsigned)idx
13822{
13823 /*
13824 This function causes problems with Thargoids: their missiles (aka Thargons) are automatically
13825 added to the escorts group, and when a mother ship dies all thargons will attach themselves
13826 as escorts to the surviving battleships. This can lead to huge escort groups.
13827 TODO: better handling of Thargoid groups:
13828 - put thargons (& all other thargon missiles) in their own non-escort group perhaps?
13829 */
13830
13831 // The _escortPositions array is always MAX_ESCORTS long.
13832 // Kludge: return the same last escort position if we have escorts above MAX_ESCORTS...
13833 idx = MIN(idx, (unsigned)(MAX_ESCORTS - 1));
13834
13835 return HPvector_add(self->position, vectorToHPVector(quaternion_rotate_vector([self normalOrientation], _escortPositions[idx])));
13836}
#define MIN(A, B)
Definition OOMaths.h:111
Vector _escortPositions[MAX_ESCORTS]
Definition ShipEntity.h:471

◆ countEquipmentItem:

- (NSUInteger) countEquipmentItem: (NSString *) eqkey

Definition at line 2093 of file ShipEntity.m.

3092 :(NSString *)eqkey
3093{
3094 NSString *eq = nil;
3095 NSUInteger count = 0;
3096 foreach (eq, _equipment)
3097 {
3098 if ([eqkey isEqualToString:eq])
3099 {
3100 ++count;
3101 }
3102 }
3103 return count;
3104}

Referenced by ShipEquipmentStatus().

+ Here is the caller graph for this function:

◆ countsAsKill

- (BOOL) countsAsKill

Definition at line 14954 of file ShipEntity.m.

1686{
1687 return [[self shipInfoDictionary] oo_boolForKey:@"counts_as_kill" defaultValue:YES];
1688}

◆ crew

- (NSArray *) crew

◆ crewForScripting

- (NSArray *) crewForScripting

Definition at line 7619 of file ShipEntity.m.

7979{
7980 if (crew == nil)
7981 {
7982 return nil;
7983 }
7984 OOCharacter *crewMember = nil;
7985 NSMutableArray *result = [NSMutableArray arrayWithCapacity:4];
7986 foreach (crewMember, crew)
7987 {
7988 NSDictionary *crewDict = [crewMember infoForScripting];
7989 [result addObject:crewDict];
7990 }
7991 return result;
7992}
NSDictionary * infoForScripting()

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ cruiseSpeed

- (double) cruiseSpeed

◆ currentAimTolerance

- (GLfloat) currentAimTolerance

Definition at line 9593 of file ShipEntity.m.

11286{
11287 GLfloat basic_aim = aim_tolerance;
11288 GLfloat best_cos = 0.99999; // ~45m in 10km (track won't go better than 40)
11290 {
11291 // better general targeting
11292 best_cos = 0.999999; // ~14m in 10km (track won't go better than 10)
11293 // if missing, aim better!
11294 basic_aim /= 1.0 + ((GLfloat)[self missedShots] / 4.0);
11295 }
11297 {
11298 // deadly shots
11299 best_cos = 0.9999999; // ~4m in 10km (track won't go better than 4)
11300 // and start with extremely good aim circle
11301 basic_aim /= 5.0;
11302 }
11304 { // bad shots with aft lasers
11305 basic_aim *= 1.3;
11306 }
11308 { // everyone a bit worse with side lasers
11310 { // especially these
11311 basic_aim *= 1.3 + randf();
11312 }
11313 else
11314 {
11315 basic_aim *= 1.3;
11316 }
11317 }
11318 // only apply glare if ship is not shadowed
11319 if (isSunlit) {
11320 OOSunEntity *sun = [UNIVERSE sun];
11321 if (sun)
11322 {
11323 GLfloat sunGlareAngularSize = atan([sun radius]/HPdistance([self position], [sun position])) * SUN_GLARE_MULT_FACTOR + (SUN_GLARE_ADD_FACTOR);
11324 GLfloat glareLevel = [self lookingAtSunWithThresholdAngleCos:cos(sunGlareAngularSize)] * (1.0f - [self sunGlareFilter]);
11325 if (glareLevel > 0.1f)
11326 {
11327 // looking towards sun can seriously mess up aim (glareLevel 0..1)
11328 basic_aim *= (1.0 + glareLevel*3.0);
11329// OOLog(@"aim.debug",@"Sun glare affecting aim: %f for %@",glareLevel,self);
11330 if (glareLevel > 0.5f)
11331 {
11332 // strong glare makes precise targeting impossible
11333 best_cos = 0.99999;
11334 }
11335 }
11336 }
11337 }
11338
11339
11340 GLfloat max_cos = sqrt(1-(basic_aim * basic_aim / 100000000.0));
11341
11342 if (max_cos < best_cos)
11343 {
11344 return max_cos;
11345 }
11346 return best_cos;
11347}
@ WEAPON_FACING_PORT
Definition OOTypes.h:231
@ WEAPON_FACING_STARBOARD
Definition OOTypes.h:232
unsigned isSunlit
Definition Entity.h:99
OOWeaponFacing currentWeaponFacing
Definition ShipEntity.h:312
GLfloat sunGlareFilter
Definition ShipEntity.h:286

◆ currentWeaponFacing

- (OOWeaponFacing) currentWeaponFacing

◆ damage

- (int) damage

Definition at line 7619 of file ShipEntity.m.

8834{
8835 return (int)(100 - (100 * energy / maxEnergy));
8836}

◆ deactivateCloakingDevice

- (void) deactivateCloakingDevice

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12376{
12378 {
12380 [self doScriptEvent:OOJSID("shipCloakDeactivated")];
12381 }
12382}

◆ dealEnergyDamage:atRange:withBias:

- (void) dealEnergyDamage: (GLfloat) baseDamage
atRange: (GLfloat) range
withBias: (GLfloat) velocityBias 

Definition at line 7619 of file ShipEntity.m.

8839 :(GLfloat) baseDamage atRange:(GLfloat) range withBias:(GLfloat) velocityBias
8840{
8841 // this is limited to the player's scanner range
8842 GLfloat maxRange = fmin(range * sqrt(baseDamage), SCANNER_MAX_RANGE);
8843
8844 OOLog(@"missile.damage.calc", @"Range: %f | Damage: %f | MaxRange: %f",range,baseDamage,maxRange);
8845
8846 NSArray *targets = [UNIVERSE entitiesWithinRange:maxRange ofEntity:self];
8847 if ([targets count] > 0)
8848 {
8849 unsigned i;
8850 for (i = 0; i < [targets count]; i++)
8851 {
8852 Entity *e2 = [targets objectAtIndex:i];
8853 Vector p2 = [self vectorTo:e2];
8854 double ecr = [e2 collisionRadius];
8855 double d = (magnitude(p2) - ecr) / range;
8856 // base damage within defined range, inverse-square falloff outside
8857 double localDamage = baseDamage;
8858 OOLog(@"missile.damage.calc", @"Base damage: %f",baseDamage);
8859 if (velocityBias > 0)
8860 {
8861 Vector v2 = vector_subtract([self velocity], [e2 velocity]);
8862 double vSign = dot_product(vector_normal([self velocity]), vector_normal(p2));
8863 // vSign should always be positive for the missile's actual target
8864 // but might be negative for other nearby ships which are
8865 // actually moving further away from the missile
8866// double vMag = vSign > 0.0 ? magnitude(v2) : -magnitude(v2);
8867 double vMag = vSign * magnitude(v2);
8868 if (vMag > 1000.0) {
8869 vMag = 1000.0;
8870// cap effective closing speed to 1.0LM or injector-collisions can still do
8871// ridiculous damage
8872 }
8873
8874 localDamage += vMag * velocityBias;
8875 OOLog(@"missile.damage.calc",@"Velocity magnitude + sign: %f , %f",magnitude(v2),vSign);
8876 OOLog(@"missile.damage.calc",@"Velocity magnitude factor: %f",vMag);
8877 OOLog(@"missile.damage.calc",@"Velocity corrected damage: %f",localDamage);
8878 }
8879 double damage = (d > 1) ? localDamage / (d * d) : localDamage;
8880 OOLog(@"missile.damage.calc",@"%f at range %f (d=%f)",damage,magnitude(p2)-ecr,d);
8881 if (damage > 0.0)
8882 {
8883 if ([self owner])
8884 {
8885 [e2 takeEnergyDamage:damage from:self becauseOf:[self owner] weaponIdentifier:[self primaryRole]];
8886 }
8887 else
8888 {
8889 [e2 takeEnergyDamage:damage from:self becauseOf:self weaponIdentifier:[self primaryRole]];
8890 }
8891 }
8892 }
8893 }
8894
8895 /* the actual damage can't go more than S_M_R, so cap the range
8896 * for exploding purposes so that the visual appearance isn't
8897 * larger than that */
8898 if (range > SCANNER_MAX_RANGE / 4.0)
8899 {
8900 range = SCANNER_MAX_RANGE / 4.0;
8901 }
8902 // and a visual sign of the explosion
8903 // "fireball" explosion effect
8904 NSDictionary *explosion = [UNIVERSE explosionSetting:@"oolite-default-ship-explosion"];
8905 [UNIVERSE addEntity:[OOExplosionCloudEntity explosionCloudFromEntity:self withSize:range*3.0 andSettings:explosion]];
8906
8907}
#define SCANNER_MAX_RANGE
Definition Entity.h:51
void takeEnergyDamage:from:becauseOf:weaponIdentifier:(double amount,[from] Entity *ent,[becauseOf] Entity *other,[weaponIdentifier] NSString *weaponIdentifier)
Definition Entity.m:990
instancetype explosionCloudFromEntity:withSize:andSettings:(Entity *entity,[withSize] float size,[andSettings] NSDictionary *settings)

Referenced by ShipDealEnergyDamage().

+ Here is the caller graph for this function:

◆ dealEnergyDamageWithinDesiredRange

- (void) dealEnergyDamageWithinDesiredRange

Definition at line 7619 of file ShipEntity.m.

8913{
8914 OOStandardsDeprecated([NSString stringWithFormat:@"dealEnergyDamageWithinDesiredRange is deprecated for %@",self]);
8915 // not over scannerRange
8916 NSArray* targets = [UNIVERSE entitiesWithinRange:(desired_range < SCANNER_MAX_RANGE ? desired_range : SCANNER_MAX_RANGE) ofEntity:self];
8917 if ([targets count] > 0)
8918 {
8919 unsigned i;
8920 for (i = 0; i < [targets count]; i++)
8921 {
8922 Entity *e2 = [targets objectAtIndex:i];
8923 Vector p2 = [self vectorTo:e2];
8924 double ecr = [e2 collisionRadius];
8925 double d = (magnitude(p2) - ecr) * 2.6; // 2.6 is a correction constant to stay in limits of the old code.
8926 double damage = (d > 0) ? weapon_damage * desired_range / (d * d) : weapon_damage;
8927 [e2 takeEnergyDamage:damage from:self becauseOf:[self owner] weaponIdentifier:[self primaryRole]];
8928 }
8929 }
8930}
void OOStandardsDeprecated(NSString *message)

◆ dealloc

- (void) dealloc
implementation

Reimplemented from OOEntityWithDrawable.

Reimplemented in DockEntity, PlayerEntity, and StationEntity.

Definition at line 14954 of file ShipEntity.m.

1074{
1075 /* NOTE: we guarantee that entityDestroyed is sent immediately after the
1076 JS ship becomes invalid (as a result of dropping the weakref), i.e.
1077 with no intervening script activity.
1078 It has to be after the invalidation so that scripts can't directly or
1079 indirectly cause the ship to become strong-referenced. (Actually, we
1080 could handle that situation by breaking out of dealloc, but that's a
1081 nasty abuse of framework semantics and would require special-casing in
1082 subclasses.)
1083 -- Ahruman 2011-02-27
1084 */
1085 [weakSelf weakRefDrop];
1086 weakSelf = nil;
1087 ShipScriptEventNoCx(self, "entityDestroyed");
1088
1089 [self setTrackCloseContacts:NO]; // deallocs tracking dictionary
1090 [[self parentEntity] subEntityReallyDied:self]; // Will do nothing if we're not really a subentity
1091 [self clearSubEntities];
1092
1095 DESTROY(shipAI);
1096 DESTROY(cargo);
1097 DESTROY(name);
1111 DESTROY(script);
1115 DESTROY(crew);
1117 DESTROY(octree);
1120
1125
1127
1128 [self setSubEntityTakingDamage:nil];
1129 [self removeAllEquipment];
1130
1131 [_group removeShip:self];
1132 DESTROY(_group);
1133 [_escortGroup removeShip:self];
1135
1137
1141
1143
1144 [super dealloc];
1145}
#define ShipScriptEventNoCx(ship, event,...)
OOWeakReference * weakSelf
OOColor * laser_color
Definition ShipEntity.h:229
OOColor * scanner_display_color_hostile2
Definition ShipEntity.h:235
NSDictionary * shipinfoDictionary
Definition ShipEntity.h:217
NSString * primaryRole
Definition ShipEntity.h:333
OOColor * scanner_display_color2
Definition ShipEntity.h:233
NSString * name
Definition ShipEntity.h:327
NSArray * portWeaponOffset
Definition ShipEntity.h:395
NSString * shipClassName
Definition ShipEntity.h:329
OOShipGroup * _group
Definition ShipEntity.h:466
OOWeakReference * _lastAegisLock
Definition ShipEntity.h:464
NSArray * starboardWeaponOffset
Definition ShipEntity.h:396
NSString * scan_description
Definition ShipEntity.h:331
NSString * shipUniqueName
Definition ShipEntity.h:328
OOColor * exhaust_emissive_color
Definition ShipEntity.h:231
NSArray * aftWeaponOffset
Definition ShipEntity.h:394
NSArray * forwardWeaponOffset
Definition ShipEntity.h:393
OOColor * scanner_display_color1
Definition ShipEntity.h:232
OOJSScript * script
Definition ShipEntity.h:222
OOColor * default_laser_color
Definition ShipEntity.h:230
OOJSScript * aiScript
Definition ShipEntity.h:223
OOColor * scanner_display_color_hostile1
Definition ShipEntity.h:234
NSString * displayName
Definition ShipEntity.h:330
NSString * lastRadioMessage
Definition ShipEntity.h:404
NSString * _shipKey
Definition ShipEntity.h:459

◆ dealMomentumWithinDesiredRange:

- (void) dealMomentumWithinDesiredRange: (double) amount

Definition at line 7619 of file ShipEntity.m.

8933 :(double)amount
8934{
8935 NSArray* targets = [UNIVERSE entitiesWithinRange:desired_range ofEntity:self];
8936 if ([targets count] > 0)
8937 {
8938 unsigned i;
8939 for (i = 0; i < [targets count]; i++)
8940 {
8941 ShipEntity *e2 = (ShipEntity*)[targets objectAtIndex:i];
8942 if ([e2 isShip] && [e2 isInSpace])
8943 {
8944 Vector p2 = [self vectorTo:e2];
8945 double ecr = [e2 collisionRadius];
8946 double d2 = magnitude2(p2) - ecr * ecr;
8947 // limit momentum transfer to relatively sensible levels
8948 if (d2 < 0.1)
8949 {
8950 d2 = 0.1;
8951 }
8952 double moment = amount*desired_range/d2;
8953 [e2 addImpactMoment:vector_normal(p2) fraction:moment];
8954 }
8955 }
8956 }
8957}
BOOL isInSpace()
Definition Entity.m:1120
void addImpactMoment:fraction:(Vector moment,[fraction] GLfloat howmuch)

◆ debugDumpPendingMessages

- (void) debugDumpPendingMessages
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

891{
892 [shipAI debugDumpPendingMessages];
893}

◆ debugInspectorModules

- (NSArray *) debugInspectorModules
implementation

Reimplemented from Entity.

Provided by category ShipEntity(OOShipDebugInspectorModule).

Definition at line 1 of file OOShipDebugInspectorModule.m.

159{
160 return [[super debugInspectorModules] arrayByAddingInspectorModuleOfClass:[OOShipDebugInspectorModule class]
161 forObject:(id)self];
162}

◆ decrease_flight_pitch:

- (void) decrease_flight_pitch: (double) delta

Definition at line 7619 of file ShipEntity.m.

8675 :(double) delta
8676{
8677 flightPitch -= delta;
8680 else if (flightPitch < -max_flight_pitch)
8682}

Referenced by PlayerShipSetProperty().

+ Here is the caller graph for this function:

◆ decrease_flight_roll:

- (void) decrease_flight_roll: (double) delta

Definition at line 7619 of file ShipEntity.m.

8655 :(double) delta
8656{
8657 flightRoll -= delta;
8660 else if (flightRoll < -max_flight_roll)
8662}

Referenced by PlayerShipSetProperty().

+ Here is the caller graph for this function:

◆ decrease_flight_speed:

- (void) decrease_flight_speed: (double) delta

Definition at line 7619 of file ShipEntity.m.

8626 :(double) delta
8627{
8628 double factor = 1.0;
8630 {
8631 factor = MIN_HYPERSPEED_FACTOR;
8632 }
8633
8634 if (flightSpeed > factor * delta)
8635 {
8636 flightSpeed -= factor * delta;
8637 }
8638 else
8639 {
8640 flightSpeed = 0;
8641 }
8642}
#define MIN_HYPERSPEED_FACTOR

◆ decrease_flight_yaw:

- (void) decrease_flight_yaw: (double) delta

Definition at line 7619 of file ShipEntity.m.

8695 :(double) delta
8696{
8697 flightYaw -= delta;
8700 else if (flightYaw < -max_flight_yaw)
8702}

Referenced by PlayerShipSetProperty().

+ Here is the caller graph for this function:

◆ defenseTargetCount

- (NSUInteger) defenseTargetCount

Definition at line 9593 of file ShipEntity.m.

11160{
11161 return [_defenseTargets count];
11162}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ defenseTargetEnumerator

- (NSEnumerator *) defenseTargetEnumerator

Definition at line 9593 of file ShipEntity.m.

11172{
11173 return [_defenseTargets objectEnumerator];
11174}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ deployEscorts

- (void) deployEscorts

Definition at line 9593 of file ShipEntity.m.

13841{
13842 NSEnumerator *escortEnum = nil;
13843 ShipEntity *escort = nil;
13844 ShipEntity *target = nil;
13845 NSMutableSet *idleEscorts = nil;
13846 unsigned deployCount;
13847
13848 if ([self primaryTarget] == nil || _escortGroup == nil) return;
13849
13850 OOShipGroup *escortGroup = [self escortGroup];
13851 NSUInteger escortCount = [escortGroup count] - 1; // escorts minus leader.
13852 if (escortCount == 0) return;
13853
13854 if ([self group] == nil) [self setGroup:escortGroup];
13855
13856 if ([self primaryTarget] == [self lastEscortTarget])
13857 {
13858 // already deployed escorts onto this target!
13859 return;
13860 }
13861
13862 [self setLastEscortTarget:[self primaryTarget]];
13863
13864 // Find idle escorts
13865 idleEscorts = [NSMutableSet set];
13866 for (escortEnum = [self escortEnumerator]; (escort = [escortEnum nextObject]); )
13867 {
13868 if (![[[escort getAI] name] isEqualToString:@"interceptAI.plist"] && ![escort hasNewAI])
13869 {
13870 [idleEscorts addObject:escort];
13871 }
13872 else if ([escort hasNewAI])
13873 {
13874 // JS-based escorts get a help request
13875 [escort doScriptEvent:OOJSID("helpRequestReceived") withArgument:self andArgument:[self primaryTarget]];
13876 }
13877 }
13878
13879 escortCount = [idleEscorts count];
13880 if (escortCount == 0) return;
13881
13882 deployCount = ranrot_rand() % escortCount + 1;
13883
13884 // Deploy deployCount idle escorts.
13885 target = [self primaryTarget];
13886 for (escortEnum = [idleEscorts objectEnumerator]; (escort = [escortEnum nextObject]); )
13887 {
13888 [escort addTarget:target];
13889 [escort setAITo:@"interceptAI.plist"];
13890 [escort doScriptEvent:OOJSID("escortAttack") withArgument:target];
13891
13892 if (--deployCount == 0) break;
13893 }
13894
13895 [self updateEscortFormation];
13896}
void addTarget:(Entity *targetEntity)
NSEnumerator * escortEnumerator()
BOOL hasNewAI()
void setAITo:(NSString *aiString)
Entity * lastEscortTarget()

Referenced by ShipDeployEscorts().

+ Here is the caller graph for this function:

◆ descriptionComponents

- (NSString *) descriptionComponents
implementation

Reimplemented from Entity.

Reimplemented in StationEntity.

Definition at line 14954 of file ShipEntity.m.

1182{
1183 if (![self isSubEntity])
1184 {
1185 return [NSString stringWithFormat:@"\"%@\" %@", [self name], [super descriptionComponents]];
1186 }
1187 else
1188 {
1189 // ID, scanClass and status are of no interest for subentities.
1190 NSString *subtype = nil;
1191 if ([self behaviour] == BEHAVIOUR_TRACK_AS_TURRET) subtype = @"(turret)";
1192 else subtype = @"(subentity)";
1193
1194 return [NSString stringWithFormat:@"\"%@\" position: %@ %@", [self name], HPVectorDescription([self position]), subtype];
1195 }
1196}

◆ descriptionForObjDump

- (NSString *) descriptionForObjDump
implementation

Reimplemented from Entity.

Definition at line 14073 of file ShipEntity.m.

14842{
14843 NSString *desc = [super descriptionForObjDump];
14844 desc = [NSString stringWithFormat:@"%@ mass %g", desc, [self mass]];
14845 if (![self isPlayer])
14846 {
14847 desc = [NSString stringWithFormat:@"%@ AI: %@", desc, [[self getAI] shortDescriptionComponents]];
14848 }
14849 return desc;
14850}

◆ deserializeShipSubEntitiesFrom:

- (void) deserializeShipSubEntitiesFrom: (NSString *) string

Definition at line 14954 of file ShipEntity.m.

833 :(NSString *)string
834{
835 NSArray *subEnts = [[self shipSubEntityEnumerator] allObjects];
836 NSInteger i,idx, start = [subEnts count] - 1;
837 NSInteger strMaxIdx = [string length] - 1;
838
839 ShipEntity *se = nil;
840
841 for (i = start; i >= 0; i--)
842 {
843 se = (ShipEntity *)[subEnts objectAtIndex:i];
844 idx = [se subIdx]; // should be identical to i, but better safe than sorry...
845 if (idx <= strMaxIdx && [[string substringWithRange:NSMakeRange(idx, 1)] isEqualToString:@"0"])
846 {
847 [se setSuppressExplosion:NO];
848 [se setEnergy:1];
849 [se takeEnergyDamage:500000000.0 from:nil becauseOf:nil weaponIdentifier:@""];
850 }
851 }
852}
void setEnergy:(GLfloat amount)
Definition Entity.m:811
void takeEnergyDamage:from:becauseOf:weaponIdentifier:(double amount, [from] Entity *ent, [becauseOf] Entity *other, [weaponIdentifier] NSString *weaponIdentifier)
NSUInteger subIdx()
Definition ShipEntity.m:786

◆ desiredRange

- (double) desiredRange

Definition at line 7619 of file ShipEntity.m.

8597{
8598 return desired_range;
8599}

◆ desiredSpeed

- (double) desiredSpeed

Definition at line 7619 of file ShipEntity.m.

8591{
8592 return desired_speed;
8593}

◆ destination

- (HPVector) destination

Definition at line 9593 of file ShipEntity.m.

10261{
10262 return _destination;
10263}

◆ destinationSystem

- (OOSystemID) destinationSystem

Definition at line 7619 of file ShipEntity.m.

7912{
7913 return destination_system;
7914}
OOSystemID destination_system
Definition ShipEntity.h:380

◆ disengageAutopilot

- (void) disengageAutopilot
implementation

Reimplemented in PlayerEntity.

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ displayName

- (NSString *) displayName

◆ distance_six:

- (HPVector) distance_six: (GLfloat) dist

Definition at line 9593 of file ShipEntity.m.

10275 : (GLfloat) dist
10276{
10277 HPVector six = position;
10278 six.x -= dist * v_forward.x; six.y -= dist * v_forward.y; six.z -= dist * v_forward.z;
10279 return six;
10280}

◆ distance_twelve:withOffset:

- (HPVector) distance_twelve: (GLfloat) dist
withOffset: (GLfloat) offset 

Definition at line 9593 of file ShipEntity.m.

10283 : (GLfloat) dist withOffset:(GLfloat)offset
10284{
10285 HPVector twelve = position;
10286 twelve.x += dist * v_up.x; twelve.y += dist * v_up.y; twelve.z += dist * v_up.z;
10287 twelve.x += offset * v_right.x; twelve.y += offset * v_right.y; twelve.z += offset * v_right.z;
10288 return twelve;
10289}

◆ dockEscorts

- (void) dockEscorts

Definition at line 9593 of file ShipEntity.m.

13901{
13902 if (![self hasEscorts]) return;
13903
13904 OOShipGroup *escortGroup = [self escortGroup];
13905 NSEnumerator *escortEnum = nil;
13906 ShipEntity *escort = nil;
13907 ShipEntity *target = [self primaryTarget];
13908 unsigned i = 0;
13909 // Note: works on escortArray rather than escortEnumerator because escorts may be mutated.
13910 for (escortEnum = [[self escortArray] objectEnumerator]; (escort = [escortEnum nextObject]); )
13911 {
13912 float delay = i++ * 3.0 + 1.5; // send them off at three second intervals
13913 AI *ai = [escort getAI];
13914
13915 // act individually now!
13916 if ([escort group] == escortGroup) [escort setGroup:nil];
13917 if ([escort owner] == self) [escort setOwner:escort];
13918 if(target && [target isStation]) [escort setTargetStation:target];
13919 // JSAI: handles own delay
13920 if (![escort hasNewAI])
13921 {
13922 [escort setAITo:@"dockingAI.plist"];
13923 [ai setState:@"ABORT" afterDelay:delay + 0.25];
13924 }
13925 [escort doScriptEvent:OOJSID("escortDock") withArgument:[NSNumber numberWithFloat:delay]];
13926 }
13927
13928 // We now have no escorts.
13929 [_escortGroup release];
13930 _escortGroup = nil;
13931}
Definition AI.h:38
void setState:afterDelay:(NSString *stateName,[afterDelay] NSTimeInterval delay)
Definition AI.m:358
void setTargetStation:(Entity *targetEntity)

Referenced by ShipDockEscorts().

+ Here is the caller graph for this function:

◆ dockingInstructions

- (NSDictionary *) dockingInstructions

◆ doesHitLine:v0:

- (GLfloat) doesHitLine: (HPVector)
v0: (HPVector) v1 

Definition at line 14954 of file ShipEntity.m.

1442 :(HPVector)v0 :(HPVector)v1
1443{
1444 Vector u0 = HPVectorToVector(HPvector_between(position, v0)); // relative to origin of model / octree
1445 Vector u1 = HPVectorToVector(HPvector_between(position, v1));
1446 Vector w0 = make_vector(dot_product(u0, v_right), dot_product(u0, v_up), dot_product(u0, v_forward)); // in ijk vectors
1447 Vector w1 = make_vector(dot_product(u1, v_right), dot_product(u1, v_up), dot_product(u1, v_forward));
1448 return [octree isHitByLine:w0 :w1];
1449}

◆ doesHitLine:v0:v1:

- (GLfloat) doesHitLine: (HPVector)
v0: (HPVector)
v1: (ShipEntity**) hitEntity 

Reimplemented in PlayerEntity.

Definition at line 14954 of file ShipEntity.m.

1452 :(HPVector)v0 :(HPVector)v1 :(ShipEntity **)hitEntity
1453{
1454 if (hitEntity)
1455 hitEntity[0] = (ShipEntity*)nil;
1456 Vector u0 = HPVectorToVector(HPvector_between(position, v0)); // relative to origin of model / octree
1457 Vector u1 = HPVectorToVector(HPvector_between(position, v1));
1458 Vector w0 = make_vector(dot_product(u0, v_right), dot_product(u0, v_up), dot_product(u0, v_forward)); // in ijk vectors
1459 Vector w1 = make_vector(dot_product(u1, v_right), dot_product(u1, v_up), dot_product(u1, v_forward));
1460 GLfloat hit_distance = [octree isHitByLine:w0 :w1];
1461 if (hit_distance)
1462 {
1463 if (hitEntity)
1464 hitEntity[0] = self;
1465 }
1466
1467 NSEnumerator *subEnum = nil;
1468 ShipEntity *se = nil;
1469 for (subEnum = [self shipSubEntityEnumerator]; (se = [subEnum nextObject]); )
1470 {
1471 HPVector p0 = [se absolutePositionForSubentity];
1472 Triangle ijk = [se absoluteIJKForSubentity];
1473 u0 = HPVectorToVector(HPvector_between(p0, v0));
1474 u1 = HPVectorToVector(HPvector_between(p0, v1));
1475 w0 = resolveVectorInIJK(u0, ijk);
1476 w1 = resolveVectorInIJK(u1, ijk);
1477
1478 GLfloat hitSub = [se->octree isHitByLine:w0 :w1];
1479 if (hitSub && (hit_distance == 0 || hit_distance > hitSub))
1480 {
1481 hit_distance = hitSub;
1482 if (hitEntity)
1483 {
1484 *hitEntity = se;
1485 }
1486 }
1487 }
1488
1489 return hit_distance;
1490}
Triangle absoluteIJKForSubentity()

◆ doesHitLine:v0:withPosition:andIJK:i:j:

- (GLfloat) doesHitLine: (HPVector)
v0: (HPVector) v1
withPosition: (HPVector) o
andIJK: (Vector)
i: (Vector)
j: (Vector) k 

Definition at line 14954 of file ShipEntity.m.

1493 :(HPVector)v0 :(HPVector)v1 withPosition:(HPVector)o andIJK:(Vector)i :(Vector)j :(Vector)k
1494{
1495 Vector u0 = HPVectorToVector(HPvector_between(o, v0)); // relative to origin of model / octree
1496 Vector u1 = HPVectorToVector(HPvector_between(o, v1));
1497 Vector w0 = make_vector(dot_product(u0, i), dot_product(u0, j), dot_product(u0, k)); // in ijk vectors
1498 Vector w1 = make_vector(dot_product(u1, j), dot_product(u1, j), dot_product(u1, k));
1499 return [octree isHitByLine:w0 :w1];
1500}

◆ doNothing

- (void) doNothing
implementation

Definition at line 14073 of file ShipEntity.m.

14835{
14836
14837}

◆ doOctreesCollide

- (ShipEntity *) doOctreesCollide (ShipEntity *) prime
(ShipEntity *) other 
implementation

Definition at line 2093 of file ShipEntity.m.

2094{
2095 // octree check
2096 Octree *prime_octree = prime->octree;
2097 Octree *other_octree = other->octree;
2098
2099 HPVector prime_position = [prime absolutePositionForSubentity];
2100 Triangle prime_ijk = [prime absoluteIJKForSubentity];
2101 HPVector other_position = [other absolutePositionForSubentity];
2102 Triangle other_ijk = [other absoluteIJKForSubentity];
2103
2104 Vector relative_position_of_other = resolveVectorInIJK(HPVectorToVector(HPvector_between(prime_position, other_position)), prime_ijk);
2105 Triangle relative_ijk_of_other;
2106 relative_ijk_of_other.v[0] = resolveVectorInIJK(other_ijk.v[0], prime_ijk);
2107 relative_ijk_of_other.v[1] = resolveVectorInIJK(other_ijk.v[1], prime_ijk);
2108 relative_ijk_of_other.v[2] = resolveVectorInIJK(other_ijk.v[2], prime_ijk);
2109
2110 // check hull octree against other hull octree
2111 if ([prime_octree isHitByOctree:other_octree
2112 withOrigin:relative_position_of_other
2113 andIJK:relative_ijk_of_other])
2114 {
2115 return other;
2116 }
2117
2118 // check prime subentities against the other's hull
2119 NSArray *prime_subs = prime->subEntities;
2120 if (prime_subs)
2121 {
2122 NSUInteger i, n_subs = [prime_subs count];
2123 for (i = 0; i < n_subs; i++)
2124 {
2125 Entity* se = [prime_subs objectAtIndex:i];
2126 if ([se isShip] && [se canCollide] && doOctreesCollide((ShipEntity*)se, other))
2127 return other;
2128 }
2129 }
2130
2131 // check prime hull against the other's subentities
2132 NSArray *other_subs = other->subEntities;
2133 if (other_subs)
2134 {
2135 NSUInteger i, n_subs = [other_subs count];
2136 for (i = 0; i < n_subs; i++)
2137 {
2138 Entity* se = [other_subs objectAtIndex:i];
2139 if ([se isShip] && [se canCollide] && doOctreesCollide(prime, (ShipEntity*)se))
2140 return (ShipEntity*)se;
2141 }
2142 }
2143
2144 // check prime subenties against the other's subentities
2145 if ((prime_subs)&&(other_subs))
2146 {
2147 NSUInteger i, n_osubs = [other_subs count];
2148 for (i = 0; i < n_osubs; i++)
2149 {
2150 Entity* oe = [other_subs objectAtIndex:i];
2151 if ([oe isShip] && [oe canCollide])
2152 {
2153 NSUInteger j, n_psubs = [prime_subs count];
2154 for (j = 0; j < n_psubs; j++)
2155 {
2156 Entity* pe = [prime_subs objectAtIndex:j];
2157 if ([pe isShip] && [pe canCollide] && doOctreesCollide((ShipEntity*)pe, (ShipEntity*)oe))
2158 return (ShipEntity*)oe;
2159 }
2160 }
2161 }
2162 }
2163
2164 // fall through => no collision
2165 return nil;
2166}
static BOOL isHitByOctree(Octree_details axialDetails, Octree_details otherDetails, Vector delta, Triangle other_ijk)
BOOL canCollide()

◆ doScriptEvent:

- (void) doScriptEvent: (jsid) message

Definition at line 14073 of file ShipEntity.m.

14631 :(jsid)message
14632{
14633 JSContext *context = OOJSAcquireContext();
14634 [self doScriptEvent:message inContext:context withArguments:NULL count:0];
14635 OOJSRelinquishContext(context);
14636}

◆ doScriptEvent:andReactToAIMessage:

- (void) doScriptEvent: (jsid) scriptEvent
andReactToAIMessage: (NSString *) aiMessage 

Definition at line 14073 of file ShipEntity.m.

14729 :(jsid)scriptEvent andReactToAIMessage:(NSString *)aiMessage
14730{
14731 [self doScriptEvent:scriptEvent];
14732 [self reactToAIMessage:aiMessage context:nil];
14733}

◆ doScriptEvent:inContext:withArguments:count:

- (void) doScriptEvent: (jsid) message
inContext: (JSContext *) context
withArguments: (jsval *) argv
count: (uintN) argc 

Reimplemented in PlayerEntity.

Definition at line 14073 of file ShipEntity.m.

14709 :(jsid)message inContext:(JSContext *)context withArguments:(jsval *)argv count:(uintN)argc
14710{
14711 // This method is a bottleneck so that PlayerEntity can override at one point.
14712 [script callMethod:message inContext:context withArguments:argv count:argc result:NULL];
14713 [aiScript callMethod:message inContext:context withArguments:argv count:argc result:NULL];
14714}

◆ doScriptEvent:withArgument:

- (void) doScriptEvent: (jsid) message
withArgument: (id) argument 

Definition at line 14073 of file ShipEntity.m.

14639 :(jsid)message withArgument:(id)argument
14640{
14641 JSContext *context = OOJSAcquireContext();
14642
14643 jsval value = OOJSValueFromNativeObject(context, argument);
14644 [self doScriptEvent:message inContext:context withArguments:&value count:1];
14645
14646 OOJSRelinquishContext(context);
14647}
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)

Referenced by PlayerReplaceShip(), PlayerShipSetProperty(), ShipAwardEquipment(), ShipRemove(), and ShipSetEquipmentStatus().

+ Here is the caller graph for this function:

◆ doScriptEvent:withArgument:andArgument:

- (void) doScriptEvent: (jsid) message
withArgument: (id) argument1
andArgument: (id) argument2 

Definition at line 14073 of file ShipEntity.m.

14650 :(jsid)message
14651 withArgument:(id)argument1
14652 andArgument:(id)argument2
14653{
14654 JSContext *context = OOJSAcquireContext();
14655
14656 jsval argv[2] = { OOJSValueFromNativeObject(context, argument1), OOJSValueFromNativeObject(context, argument2) };
14657 [self doScriptEvent:message inContext:context withArguments:argv count:2];
14658
14659 OOJSRelinquishContext(context);
14660}

Referenced by PlayerReplaceShip().

+ Here is the caller graph for this function:

◆ doScriptEvent:withArgument:andReactToAIMessage:

- (void) doScriptEvent: (jsid) scriptEvent
withArgument: (id) argument
andReactToAIMessage: (NSString *) aiMessage 

Definition at line 14073 of file ShipEntity.m.

14736 :(jsid)scriptEvent withArgument:(id)argument andReactToAIMessage:(NSString *)aiMessage
14737{
14738 [self doScriptEvent:scriptEvent withArgument:argument];
14739 [self reactToAIMessage:aiMessage context:nil];
14740}

◆ doScriptEvent:withArguments:

- (void) doScriptEvent: (jsid) message
withArguments: (NSArray *) arguments 

Definition at line 14073 of file ShipEntity.m.

14663 :(jsid)message withArguments:(NSArray *)arguments
14664{
14665 JSContext *context = OOJSAcquireContext();
14666 uintN i, argc;
14667 jsval *argv = NULL;
14668
14669 // Convert arguments to JS values and make them temporarily un-garbage-collectable.
14670 argc = (uintN)[arguments count];
14671 if (argc != 0)
14672 {
14673 argv = malloc(sizeof *argv * argc);
14674 if (argv != NULL)
14675 {
14676 for (i = 0; i != argc; ++i)
14677 {
14678 argv[i] = [[arguments objectAtIndex:i] oo_jsValueInContext:context];
14679 OOJSAddGCValueRoot(context, &argv[i], "event parameter");
14680 }
14681 }
14682 else argc = 0;
14683 }
14684
14685 [self doScriptEvent:message inContext:context withArguments:argv count:argc];
14686
14687 // Re-garbage-collectibalize the arguments and free the array.
14688 if (argv != NULL)
14689 {
14690 for (i = 0; i != argc; ++i)
14691 {
14692 JS_RemoveValueRoot(context, &argv[i]);
14693 }
14694 free(argv);
14695 }
14696
14697 OOJSRelinquishContext(context);
14698}
#define OOJSAddGCValueRoot(context, root, name)

◆ doScriptEvent:withArguments:count:

- (void) doScriptEvent: (jsid) message
withArguments: (jsval *) argv
count: (uintN) argc 

Definition at line 14073 of file ShipEntity.m.

14701 :(jsid)message withArguments:(jsval *)argv count:(uintN)argc
14702{
14703 JSContext *context = OOJSAcquireContext();
14704 [self doScriptEvent:message inContext:context withArguments:argv count:argc];
14705 OOJSRelinquishContext(context);
14706}

◆ drawDebugStuff

- (void) drawDebugStuff
implementation

Provided by category ShipEntity(Private).

Definition at line 2093 of file ShipEntity.m.

6428{
6429 // HPVect: imprecise here - needs camera relative
6430 if (0 && reportAIMessages)
6431 {
6432 OODebugDrawPoint(HPVectorToVector(_destination), [OOColor blueColor]);
6433 OODebugDrawColoredLine(HPVectorToVector([self position]), HPVectorToVector(_destination), [OOColor colorWithWhite:0.15 alpha:1.0]);
6434
6435 Entity *pTarget = [self primaryTarget];
6436 if (pTarget != nil)
6437 {
6438 OODebugDrawPoint(HPVectorToVector([pTarget position]), [OOColor redColor]);
6439 OODebugDrawColoredLine(HPVectorToVector([self position]), HPVectorToVector([pTarget position]), [OOColor colorWithRed:0.2 green:0.0 blue:0.0 alpha:1.0]);
6440 }
6441
6442 Entity *sTarget = [self targetStation];
6443 if (sTarget != pTarget && [sTarget isStation])
6444 {
6445 OODebugDrawPoint(HPVectorToVector([sTarget position]), [OOColor cyanColor]);
6446 }
6447
6448 Entity *fTarget = [self foundTarget];
6449 if (fTarget != nil && fTarget != pTarget && fTarget != sTarget)
6450 {
6451 OODebugDrawPoint(HPVectorToVector([fTarget position]), [OOColor magentaColor]);
6452 }
6453 }
6454}
void OODebugDrawColoredLine(Vector start, Vector end, OOColor *color)
void OODebugDrawPoint(Vector position, OOColor *color)
unsigned reportAIMessages
Definition ShipEntity.h:255

◆ drawImmediate:translucent:

- (void) drawImmediate: (bool) immediate
translucent: (bool) translucent 
implementation

Reimplemented from OOEntityWithDrawable.

Reimplemented in DockEntity, and PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

6386 :(bool)immediate translucent:(bool)translucent
6387{
6388 if ((no_draw_distance < cam_zero_distance) || // Done redundantly to skip subentities
6389 (cloaking_device_active && randf() > 0.10))
6390 {
6391 // Don't draw.
6392 return;
6393 }
6394
6395 // Draw self.
6396 [super drawImmediate:immediate translucent:translucent];
6397
6398#ifndef NDEBUG
6399 // Draw bounding boxes if we have to before going for the subentities.
6400 // TODO: the translucent flag here makes very little sense. Something's wrong with the matrices.
6401 if (translucent) [self drawDebugStuff];
6402 else if (gDebugFlags & DEBUG_BOUNDING_BOXES && ![self isSubEntity])
6403 {
6406 }
6407#endif
6408
6409 // Draw subentities.
6410 if (!immediate) // TODO: is this relevant any longer?
6411 {
6412 // save time by not copying the subentity array if it's empty - CIM
6413 if ([self subEntityCount] > 0)
6414 {
6415 Entity<OOSubEntity> *subEntity = nil;
6416 foreach (subEntity, [self subEntities])
6417 {
6418 NSAssert3([subEntity owner] == self, @"Subentity ownership broke - %@ should be owned by %@ but is owned by %@.", subEntity, self, [subEntity owner]);
6419 [subEntity drawSubEntityImmediate:immediate translucent:translucent];
6420 }
6421 }
6422 }
6423}
NSUInteger gDebugFlags
Definition main.m:7
@ DEBUG_BOUNDING_BOXES
OOINLINE void OODebugDrawColoredBoundingBox(BoundingBox box, OOColor *color)
OOINLINE void OODebugDrawBoundingBox(BoundingBox box)
void drawSubEntityImmediate:translucent:(bool immediate, [translucent] bool translucent)
GLfloat cam_zero_distance
Definition Entity.h:109
GLfloat no_draw_distance
Definition Entity.h:110
BoundingBox totalBoundingBox
Definition ShipEntity.h:213
void drawDebugStuff()
NSUInteger subEntityCount()

◆ drawSubEntityImmediate:translucent:

- (void) drawSubEntityImmediate: (bool) immediate
translucent: (bool) translucent 
implementation

Reimplemented from Entity.

Definition at line 2093 of file ShipEntity.m.

6458 :(bool)immediate translucent:(bool)translucent
6459{
6461
6462 if (cam_zero_distance > no_draw_distance) // this test provides an opportunity to do simple LoD culling
6463 {
6464 return; // TOO FAR AWAY
6465 }
6467
6468 // HPVect: need to make camera-relative
6469 OOGLTranslateModelView(HPVectorToVector(position));
6471 [self drawImmediate:immediate translucent:translucent];
6472
6473#ifndef NDEBUG
6475 {
6477 }
6478#endif
6479
6481
6483}
void OOGLPushModelView(void)
void OOGLTranslateModelView(Vector vector)
void OOGLMultModelView(OOMatrix matrix)
OOMatrix OOGLPopModelView(void)
#define OOVerifyOpenGLState()
Definition OOOpenGL.h:136
OOMatrix rotMatrix
Definition Entity.h:138

◆ dropMessages:

- (void) dropMessages: (NSString *) messageString
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

875 :(NSString *)messageString
876{
877 NSArray *messages = nil;
878 NSEnumerator *messageEnum = nil;
879 NSString *message = nil;
880 NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceCharacterSet];
881
882 messages = [messageString componentsSeparatedByString:@","];
883 for (messageEnum = [messages objectEnumerator]; (message = [messageEnum nextObject]); )
884 {
885 [shipAI dropMessage:[message stringByTrimmingCharactersInSet:whiteSpace]];
886 }
887}

◆ dumpCargo

- (OOCommodityType) dumpCargo

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12488{
12489 ShipEntity *jetto = [self dumpCargoItem:nil];
12490 if (jetto != nil)
12491 {
12492 return [jetto commodityType];
12493 }
12494 else
12495 {
12496 return nil;
12497 }
12498}

◆ dumpCargoItem:

- (ShipEntity *) dumpCargoItem: (OOCommodityType) preferred

Definition at line 9593 of file ShipEntity.m.

12501 :(OOCommodityType)preferred
12502{
12503 ShipEntity *jetto = nil;
12504 NSUInteger i = 0;
12505
12506 if (([cargo count] > 0)&&([UNIVERSE getTime] - cargo_dump_time > 0.5)) // space them 0.5s or 10m apart
12507 {
12508 if (preferred == nil)
12509 {
12510 jetto = [[[cargo objectAtIndex:0] retain] autorelease];
12511 }
12512 else
12513 {
12514 BOOL found = NO;
12515 for (i=0;i<[cargo count];i++)
12516 {
12517 if ([[[cargo objectAtIndex:i] commodityType] isEqualToString:preferred])
12518 {
12519 jetto = [[[cargo objectAtIndex:i] retain] autorelease];
12520 found = YES;
12521 break;
12522 }
12523 }
12524 if (found == NO)
12525 {
12526 // dump anything
12527 jetto = [[[cargo objectAtIndex:0] retain] autorelease];
12528 i = 0;
12529 }
12530 }
12531 if (jetto != nil)
12532 {
12533 [self dumpItem:jetto]; // CLASS_CARGO, STATUS_IN_FLIGHT, AI state GLOBAL
12534 [cargo removeObjectAtIndex:i];
12535 [self broadcastAIMessage:@"CARGO_DUMPED"]; // goes only to 16 nearby ships in range, but that should be enough.
12536 unsigned i;
12537 // only send script event to powered entities
12538 [self checkScannerIgnoringUnpowered];
12539 for (i = 0; i < n_scanned_ships ; i++)
12540 {
12541 ShipEntity* other = scanned_ships[i];
12542 [other doScriptEvent:OOJSID("cargoDumpedNearby") withArgument:jetto andArgument:self];
12543
12544 }
12545 }
12546 }
12547
12548 return jetto;
12549}
OOTimeAbsolute cargo_dump_time
Definition ShipEntity.h:358

◆ dumpItem:

- (OOCargoType) dumpItem: (ShipEntity*) jetto

Definition at line 9593 of file ShipEntity.m.

12552 : (ShipEntity*) cargoObj
12553{
12554 if (!cargoObj)
12555 return 0;
12556
12557 ShipEntity* jetto = [UNIVERSE reifyCargoPod:cargoObj];
12558
12559 int result = [jetto cargoType];
12560 AI *jettoAI = nil;
12561 Vector start;
12562
12563 // players get to see their old ship sailing forth, while NPCs run away more efficiently!
12564 // cargo is ejected at higher speed from any ship
12565 double eject_speed = EXPECT_NOT([jetto crew] && [jetto isPlayer]) ? 20.0 : 100.0;
12566 double eject_reaction = -eject_speed * [jetto mass] / [self mass];
12567 double jcr = jetto->collision_radius;
12568
12569 Quaternion jetto_orientation = kIdentityQuaternion;
12570 Vector vel, v_eject, v_eject_normal;
12571 HPVector rpos = [self absolutePositionForSubentity];
12572 double jetto_roll = 0;
12573 double jetto_pitch = 0;
12574
12575 // default launching position
12576 start.x = 0.0; // in the middle
12577 start.y = 0.0; //
12578 start.z = boundingBox.min.z - jcr; // 1m behind of bounding box
12579
12580 // custom launching position
12581 start = [shipinfoDictionary oo_vectorForKey:@"aft_eject_position" defaultValue:start];
12582
12583 v_eject = vector_normal(start);
12584
12585 // check if start is within bounding box...
12586 while ( (start.x > boundingBox.min.x - jcr)&&(start.x < boundingBox.max.x + jcr)&&
12587 (start.y > boundingBox.min.y - jcr)&&(start.y < boundingBox.max.y + jcr)&&
12588 (start.z > boundingBox.min.z - jcr)&&(start.z < boundingBox.max.z + jcr))
12589 {
12590 start = vector_add(start, vector_multiply_scalar(v_eject, jcr));
12591 }
12592
12593 v_eject = quaternion_rotate_vector([self normalOrientation], start);
12594 rpos = HPvector_add(rpos, vectorToHPVector(v_eject));
12595 v_eject = vector_normal(v_eject);
12596 v_eject_normal = v_eject;
12597
12598 v_eject.x += (randf() - randf())/eject_speed;
12599 v_eject.y += (randf() - randf())/eject_speed;
12600 v_eject.z += (randf() - randf())/eject_speed;
12601
12602 vel = vector_add(vector_multiply_scalar(v_forward, flightSpeed), vector_multiply_scalar(v_eject, eject_speed));
12603 velocity = vector_add(velocity, vector_multiply_scalar(v_eject, eject_reaction));
12604
12605 [jetto setPosition:rpos];
12606 if ([jetto crew]) // jetto has a crew, so assume it is an escape pod.
12607 {
12608 // orient the pod away from the ship to avoid colliding with it.
12609 jetto_orientation = quaternion_rotation_between(v_eject_normal, kBasisZVector);
12610 }
12611 else
12612 {
12613 // It is true cargo, let it tumble.
12614 jetto_roll = ((ranrot_rand() % 1024) - 512.0)/1024.0; // -0.5 to +0.5
12615 jetto_pitch = ((ranrot_rand() % 1024) - 512.0)/1024.0; // -0.5 to +0.5
12616 quaternion_set_random(&jetto_orientation);
12617 }
12618
12619 [jetto setOrientation:jetto_orientation];
12620 [jetto setRoll:jetto_roll];
12621 [jetto setPitch:jetto_pitch];
12622 [jetto setVelocity:vel];
12623 [jetto setScanClass: CLASS_CARGO];
12624 [jetto setTemperature:[self randomEjectaTemperature]];
12625 [UNIVERSE addEntity:jetto]; // STATUS_IN_FLIGHT, AI state GLOBAL
12626
12627 jettoAI = [jetto getAI];
12628 if ([jettoAI hasSuspendedStateMachines]) // check if this was previous scooped cargo.
12629 {
12630 [jetto setThrust:[jetto maxThrust]]; // restore old thrust.
12631 [jetto setOwner:jetto];
12632 [jettoAI exitStateMachineWithMessage:nil]; // exit nullAI.
12633 }
12634 [jetto doScriptEvent:OOJSID("shipWasDumped") withArgument:self];
12635 [self doScriptEvent:OOJSID("shipDumpedCargo") withArgument:jetto];
12636
12637 cargo_dump_time = [UNIVERSE getTime];
12638 return result;
12639}
Quaternion quaternion_rotation_between(Vector v0, Vector v1)
float maxThrust()
void setRoll:(double amount)
void setThrust:(double amount)
void setPitch:(double amount)

Referenced by ShipEntity(ScriptMethods)::ejectShipOfRole:.

+ Here is the caller graph for this function:

◆ dumpSelfState

- (void) dumpSelfState
implementation

Reimplemented from Entity.

Reimplemented in PlayerEntity, and StationEntity.

Definition at line 14073 of file ShipEntity.m.

14502{
14503 NSMutableArray *flags = nil;
14504 NSString *flagsString = nil;
14505
14506 [super dumpSelfState];
14507
14508 OOLog(@"dumpState.shipEntity", @"Type: %@", [self shipDataKey]);
14509 OOLog(@"dumpState.shipEntity", @"Name: %@", name);
14510 OOLog(@"dumpState.shipEntity", @"Display Name: %@", [self displayName]);
14511 OOLog(@"dumpState.shipEntity", @"Roles: %@", [self roleSet]);
14512 OOLog(@"dumpState.shipEntity", @"Primary role: %@", primaryRole);
14513 OOLog(@"dumpState.shipEntity", @"Script: %@", script);
14514 OOLog(@"dumpState.shipEntity", @"Subentity count: %lu", [self subEntityCount]);
14515 OOLog(@"dumpState.shipEntity", @"Behaviour: %@", OOStringFromBehaviour(behaviour));
14516 id target = [self primaryTarget];
14517 if (target == nil) target = @"<none>";
14518 OOLog(@"dumpState.shipEntity", @"Target: %@", target);
14519 OOLog(@"dumpState.shipEntity", @"Destination: %@", HPVectorDescription(_destination));
14520 OOLog(@"dumpState.shipEntity", @"Other destination: %@", HPVectorDescription(coordinates));
14521 OOLog(@"dumpState.shipEntity", @"Waypoint count: %u", number_of_navpoints);
14522 OOLog(@"dumpState.shipEntity", @"Desired speed: %g", desired_speed);
14523 OOLog(@"dumpState.shipEntity", @"Thrust: %g", thrust);
14524 if ([self escortCount] != 0) OOLog(@"dumpState.shipEntity", @"Escort count: %u", [self escortCount]);
14525 OOLog(@"dumpState.shipEntity", @"Fuel: %i", fuel);
14526 OOLog(@"dumpState.shipEntity", @"Fuel accumulator: %g", fuel_accumulator);
14527 OOLog(@"dumpState.shipEntity", @"Missile count: %u", missiles);
14528
14529 if (shipAI != nil && OOLogWillDisplayMessagesInClass(@"dumpState.shipEntity.ai"))
14530 {
14531 OOLog(@"dumpState.shipEntity.ai", @"%@", @"AI:");
14533 OOLogIndent();
14534 @try
14535 {
14536 [shipAI dumpState];
14537 }
14538 @catch (id exception) {}
14540 }
14541 OOLog(@"dumpState.shipEntity", @"Accuracy: %g", accuracy);
14542 OOLog(@"dumpState.shipEntity", @"Jink position: %@", VectorDescription(jink));
14543 OOLog(@"dumpState.shipEntity", @"Frustration: %g", frustration);
14544 OOLog(@"dumpState.shipEntity", @"Success factor: %g", success_factor);
14545 OOLog(@"dumpState.shipEntity", @"Shots fired: %u", shot_counter);
14546 OOLog(@"dumpState.shipEntity", @"Time since shot: %g", [self shotTime]);
14547 OOLog(@"dumpState.shipEntity", @"Spawn time: %g (%g seconds ago)", [self spawnTime], [self timeElapsedSinceSpawn]);
14548 if ([self isBeacon])
14549 {
14550 OOLog(@"dumpState.shipEntity", @"Beacon code: %@", [self beaconCode]);
14551 }
14552 OOLog(@"dumpState.shipEntity", @"Hull temperature: %g", ship_temperature);
14553 OOLog(@"dumpState.shipEntity", @"Heat insulation: %g", [self heatInsulation]);
14554
14555 flags = [NSMutableArray array];
14556 #define ADD_FLAG_IF_SET(x) if (x) { [flags addObject:@#x]; }
14570 flagsString = [flags count] ? [flags componentsJoinedByString:@", "] : (NSString *)@"none";
14571 OOLog(@"dumpState.shipEntity", @"Flags: %@", flagsString);
14572}
#define ADD_FLAG_IF_SET(x)
void OOLogPushIndent(void)
Definition OOLogging.m:316
void OOLogPopIndent(void)
Definition OOLogging.m:340
BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
Definition OOLogging.m:144
void OOLogIndent(void)
Definition OOLogging.m:366
NSString * OOStringFromBehaviour(OOBehaviour behaviour) CONST_FUNC
GLfloat timeElapsedSinceSpawn()
Definition Entity.m:1069
OOTimeAbsolute spawnTime
Definition Entity.h:150
NSString * shipDataKey()
unsigned being_fined
Definition ShipEntity.h:259
HPVector coordinates
Definition ShipEntity.h:339
BOOL isBeacon()
float ship_temperature
Definition ShipEntity.h:410
GLfloat heatInsulation()
unsigned military_jammer_active
Definition ShipEntity.h:249
int shot_counter
Definition ShipEntity.h:357
unsigned isHulk
Definition ShipEntity.h:261

◆ ejectCargo

- (void) ejectCargo
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1678{
1679 OOCargoQuantity i, cargo_to_go = 0.1 * [self maxAvailableCargoSpace];
1680 while (cargo_to_go > 15)
1681 {
1682 cargo_to_go = ranrot_rand() % cargo_to_go;
1683 }
1684 [self dumpCargo];
1685 for (i = 1; i < cargo_to_go; i++)
1686 {
1687 [self performSelector:@selector(dumpCargo) withObject:nil afterDelay:0.75 * i]; // drop 3 canisters per 2 seconds
1688 }
1689}

◆ ejectShipOfRole:

- (ShipEntity *) ejectShipOfRole: (NSString *) role

Provided by category ShipEntity(ScriptMethods).

Definition at line 31 of file ShipEntityScriptMethods.m.

50 :(NSString *)role
51{
52 ShipEntity *item = nil;
53
54 if (role != nil)
55 {
56 item = [[UNIVERSE newShipWithRole:role] autorelease];
57 if (item != nil) [self dumpItem:item];
58 }
59
60 return item;
61}

◆ ejectShipOfType:

- (ShipEntity *) ejectShipOfType: (NSString *) shipKey

Provided by category ShipEntity(ScriptMethods).

Definition at line 31 of file ShipEntityScriptMethods.m.

36 :(NSString *)shipKey
37{
38 ShipEntity *item = nil;
39
40 if (shipKey != nil)
41 {
42 item = [[UNIVERSE newShipWithName:shipKey] autorelease];
43 if (item != nil) [self dumpItem:item];
44 }
45
46 return item;
47}

◆ energyRechargeRate

- (float) energyRechargeRate

Definition at line 7411 of file ShipEntity.m.

7503{
7504 return energy_recharge_rate;
7505}

Referenced by OOShipLibraryGenerator().

+ Here is the caller graph for this function:

◆ enterDock:

- (void) enterDock: (StationEntity *) station

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

13458 :(StationEntity *)station
13459{
13460 // throw these away now we're docked...
13461 if (dockingInstructions != nil)
13462 {
13463 [dockingInstructions autorelease];
13465 }
13466
13467 [self doScriptEvent:OOJSID("shipWillDockWithStation") withArgument:station];
13468 [self doScriptEvent:OOJSID("shipDockedWithStation") withArgument:station];
13469 [shipAI message:@"DOCKED"];
13470 [station noteDockedShip:self];
13471 [UNIVERSE removeEntity:self];
13472}
void noteDockedShip:(ShipEntity *ship)

◆ enterPlayerWormhole

- (void) enterPlayerWormhole

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

635{
636 [self enterWormhole:[PLAYER wormhole] replacing:NO];
637}

◆ enterTargetWormhole

- (void) enterTargetWormhole

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

640{
641 WormholeEntity *whole = nil;
642 ShipEntity *targEnt = [self primaryTarget];
643 double found_d2 = scannerRange * scannerRange;
644
645 if (targEnt && (HPdistance2(position, [targEnt position]) < found_d2))
646 {
647 if ([targEnt isWormhole])
648 whole = (WormholeEntity *)targEnt;
649 else if ([targEnt isPlayer])
650 whole = [PLAYER wormhole];
651 }
652
653 if (!whole)
654 {
655 // locate nearest wormhole
656 int ent_count = UNIVERSE->n_entities;
657 Entity** uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
658 WormholeEntity* wormholes[ent_count];
659 int i;
660 int wh_count = 0;
661 for (i = 0; i < ent_count; i++)
662 if (uni_entities[i]->isWormhole)
663 wormholes[wh_count++] = [(WormholeEntity *)uni_entities[i] retain];
664 //
665 //double found_d2 = scannerRange * scannerRange;
666 for (i = 0; i < wh_count ; i++)
667 {
668 WormholeEntity *wh = wormholes[i];
669 double d2 = HPdistance2(position, wh->position);
670 if (d2 < found_d2)
671 {
672 whole = wh;
673 found_d2 = d2;
674 }
675 [wh release];
676 }
677 }
678
679 [self enterWormhole:whole replacing:NO];
680}

◆ enterWitchspace

- (void) enterWitchspace

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

13525{
13526 [UNIVERSE addWitchspaceJumpEffectForShip:self];
13527 [shipAI message:@"ENTERED_WITCHSPACE"];
13528
13529 if (![[UNIVERSE sun] willGoNova])
13530 {
13531 // if the sun's not going nova, add a new ship like this one leaving.
13532 [UNIVERSE witchspaceShipWithPrimaryRole:[self primaryRole]];
13533 }
13534
13535 [UNIVERSE removeEntity:self];
13536}

◆ enterWormhole:

- (void) enterWormhole: (WormholeEntity *) w_hole

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

13485 :(WormholeEntity *) w_hole
13486{
13487 [self enterWormhole:w_hole replacing:YES];
13488}

◆ enterWormhole:replacing:

- (void) enterWormhole: (WormholeEntity *) w_hole
replacing: (BOOL) replacing 

Definition at line 9593 of file ShipEntity.m.

13491 :(WormholeEntity *) w_hole replacing:(BOOL)replacing
13492{
13493 if (w_hole == nil) return;
13494 if ([self status] == STATUS_ENTERING_WITCHSPACE)
13495 {
13496 return; // has already entered a different wormhole
13497 }
13498 // Replacement ships now handled by system repopulator
13499
13500 // MKW 2011.02.27 - Moved here from ShipEntityAI so escorts reliably follow
13501 // mother in all wormhole cases, not just when the ship
13502 // creates the wormhole.
13503 [self addTarget:w_hole];
13504 [self setFoundTarget:w_hole];
13505 [shipAI reactToMessage:@"WITCHSPACE OKAY" context:@"performHyperSpaceExit"]; // must be a reaction, the ship is about to disappear
13506
13507 // CIM 2012.07.22 above only covers those cases where ship expected to leave
13508 if ([[self escortArray] count] > 1)
13509 {
13510 // so wormhole escorts anyway if it leaves unexpectedly.
13511 [self wormholeEscorts];
13512 }
13513
13514 if ([self scriptedMisjump])
13515 {
13516 [self setScriptedMisjump:NO];
13517 [w_hole setMisjumpWithRange:[self scriptedMisjumpRange]];
13518 [self setScriptedMisjumpRange:0.5];
13519 }
13520 [w_hole suckInShip: self]; // removes ship from universe
13521}
BOOL scriptedMisjump()
BOOL suckInShip:(ShipEntity *ship)
void setMisjumpWithRange:(GLfloat range)

◆ entityForShaderProperties

- (Entity *) entityForShaderProperties

Definition at line 14073 of file ShipEntity.m.

14602{
14603 return [self rootShipEntity];
14604}

◆ entityPersonality

- (GLfloat) entityPersonality

Definition at line 9593 of file ShipEntity.m.

9767{
9769}
#define ENTITY_PERSONALITY_MAX
Definition ShipEntity.h:110

◆ entityPersonalityInt

- (GLint) entityPersonalityInt

Definition at line 9593 of file ShipEntity.m.

9773{
9774 return entity_personality;
9775}

◆ equipmentCount

- (NSUInteger) equipmentCount

Definition at line 2093 of file ShipEntity.m.

3637{
3638 return [_equipment count];
3639}

◆ equipmentEnumerator

- (NSEnumerator *) equipmentEnumerator

Definition at line 2093 of file ShipEntity.m.

3631{
3632 return [_equipment objectEnumerator];
3633}

◆ equipmentItemProviding:

- (NSString *) equipmentItemProviding: (NSString *) equipmentType

Definition at line 2093 of file ShipEntity.m.

3159 :(NSString *)equipmentType
3160{
3161 NSString *key = nil;
3162 foreach (key, _equipment) {
3163 if ([key isEqualToString:equipmentType])
3164 {
3165 // equipment always provides itself
3166 return [[key copy] autorelease];
3167 }
3168 else
3169 {
3171 if (et != nil && [et provides:equipmentType])
3172 {
3173 return [[key copy] autorelease];
3174 }
3175 }
3176 }
3177 return nil;
3178}

◆ equipmentListForScripting

- (NSArray *) equipmentListForScripting

Definition at line 2093 of file ShipEntity.m.

3352{
3353 NSArray *eqTypes = [OOEquipmentType allEquipmentTypes];
3354 NSMutableArray *quip = [NSMutableArray arrayWithCapacity:[eqTypes count]];
3355 NSEnumerator *eqTypeEnum = nil;
3356 OOEquipmentType *eqType = nil;
3357 BOOL isDamaged;
3358
3359 for (eqTypeEnum = [eqTypes objectEnumerator]; (eqType = [eqTypeEnum nextObject]); )
3360 {
3361 // Equipment list, consistent with the rest of the API - Kaks
3362 if ([eqType canCarryMultiple])
3363 {
3364 NSString *damagedIdentifier = [[eqType identifier] stringByAppendingString:@"_DAMAGED"];
3365 NSUInteger i, count = 0;
3366 count += [self countEquipmentItem:[eqType identifier]];
3367 count += [self countEquipmentItem:damagedIdentifier];
3368 for (i=0;i<count;i++)
3369 {
3370 [quip addObject:eqType];
3371 }
3372 }
3373 else
3374 {
3375 isDamaged = [self hasEquipmentItem:[[eqType identifier] stringByAppendingString:@"_DAMAGED"]];
3376 if ([self hasEquipmentItem:[eqType identifier]] || isDamaged)
3377 {
3378 [quip addObject:eqType];
3379 }
3380 }
3381 }
3382
3383 // Passengers - not supported yet for NPCs, but it's here for genericity.
3384 if ([self passengerCapacity] > 0)
3385 {
3386 eqType = [OOEquipmentType equipmentTypeWithIdentifier:@"EQ_PASSENGER_BERTH"];
3387 //[quip addObject:[self eqDictionaryWithType:eqType isDamaged:NO]];
3388 [quip addObject:eqType];
3389 }
3390
3391 return [[quip copy] autorelease];
3392}
NSArray * allEquipmentTypes()
NSString * identifier()
NSUInteger passengerCapacity()

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ equipmentValidToAdd:inContext:

- (BOOL) equipmentValidToAdd: (NSString *) equipmentKey
inContext: (NSString *) context 

Definition at line 2093 of file ShipEntity.m.

3395 :(NSString *)equipmentKey inContext:(NSString *)context
3396{
3397 return [self equipmentValidToAdd:equipmentKey whileLoading:NO inContext:context];
3398}

◆ equipmentValidToAdd:whileLoading:inContext:

- (BOOL) equipmentValidToAdd: (NSString *) equipmentKey
whileLoading: (BOOL) loading
inContext: (NSString *) context 

Definition at line 2093 of file ShipEntity.m.

3401 :(NSString *)equipmentKey whileLoading:(BOOL)loading inContext:(NSString *)context
3402{
3403 OOEquipmentType *eqType = nil;
3404 BOOL validationForDamagedEquipment = NO;
3405
3406 if ([equipmentKey hasSuffix:@"_DAMAGED"])
3407 {
3408 equipmentKey = [equipmentKey substringToIndex:[equipmentKey length] - [@"_DAMAGED" length]];
3409 }
3410
3411 eqType = [OOEquipmentType equipmentTypeWithIdentifier:equipmentKey];
3412 if (eqType == nil) return NO;
3413
3414 // need to know if we are trying to add a Repair version of the equipment. In some cases
3415 // (e.g. available cargo space required), it makes sense to deny installation of equipment
3416 // if the condition is not satisfied, but it doesn't make sense to deny repair when the
3417 // equipment is already installed. For now, we are checking only the cargo space condition,
3418 // but other conditions might need to be revised too. - Nikos, 20151115
3419 if ([self hasEquipmentItem:[eqType damagedIdentifier]])
3420 {
3421 validationForDamagedEquipment = YES;
3422 }
3423
3424 // not all conditions make sence checking while loading a game with already purchaged equipment.
3425 // while loading, we mainly need to catch changes when the installed oxps set has changed since saving.
3426 if ([eqType requiresEmptyPylon] && [self missileCount] >= [self missileCapacity] && !loading) return NO;
3427 if ([eqType requiresMountedPylon] && [self missileCount] == 0 && !loading) return NO;
3428 if ([self availableCargoSpace] < [eqType requiredCargoSpace] && !validationForDamagedEquipment && !loading) return NO;
3429 if ([eqType requiresEquipment] != nil && ![self hasAllEquipment:[eqType requiresEquipment] includeWeapons:YES whileLoading:loading]) return NO;
3430 if ([eqType requiresAnyEquipment] != nil && ![self hasEquipmentItem:[eqType requiresAnyEquipment] includeWeapons:YES whileLoading:loading]) return NO;
3431 if ([eqType incompatibleEquipment] != nil && [self hasEquipmentItem:[eqType incompatibleEquipment] includeWeapons:YES whileLoading:loading]) return NO;
3432 if ([eqType requiresCleanLegalRecord] && [self legalStatus] != 0 && !loading) return NO;
3433 if ([eqType requiresNonCleanLegalRecord] && [self legalStatus] == 0 && !loading) return NO;
3434 if ([eqType requiresFreePassengerBerth] && [self passengerCount] >= [self passengerCapacity]) return NO;
3435 if ([eqType requiresFullFuel] && [self fuel] < [self fuelCapacity] && !loading) return NO;
3436 if ([eqType requiresNonFullFuel] && [self fuel] >= [self fuelCapacity] && !loading) return NO;
3437
3438 if (!loading)
3439 {
3440 NSString *condition_script = [eqType conditionScript];
3441 if (condition_script != nil)
3442 {
3443 OOJSScript *condScript = [UNIVERSE getConditionScript:condition_script];
3444 if (condScript != nil) // should always be non-nil, but just in case
3445 {
3446 JSContext *JScontext = OOJSAcquireContext();
3447 BOOL OK;
3448 JSBool allow_addition = false;
3449 jsval result;
3450 jsval args[] = { OOJSValueFromNativeObject(JScontext, equipmentKey) , OOJSValueFromNativeObject(JScontext, self) , OOJSValueFromNativeObject(JScontext, context)};
3451
3452 OK = [condScript callMethod:OOJSID("allowAwardEquipment")
3453 inContext:JScontext
3454 withArguments:args count:sizeof args / sizeof *args
3455 result:&result];
3456
3457 if (OK) OK = JS_ValueToBoolean(JScontext, result, &allow_addition);
3458
3459 OOJSRelinquishContext(JScontext);
3460
3461 if (OK && !allow_addition)
3462 {
3463 /* if the script exists, the function exists, the function
3464 * returns a bool, and that bool is false, block
3465 * addition. Otherwise allow it as default */
3466 return NO;
3467 }
3468 }
3469 }
3470 }
3471
3472 if ([self isPlayer])
3473 {
3474 if (![eqType isAvailableToPlayer]) return NO;
3475 if (![eqType isAvailableToAll])
3476 {
3477 // find options that agree with this ship. Only player ships have these options.
3479 NSDictionary *shipyardInfo = [registry shipyardInfoForKey:[self shipDataKey]];
3480 NSMutableSet *options = [NSMutableSet setWithArray:[shipyardInfo oo_arrayForKey:KEY_OPTIONAL_EQUIPMENT]];
3481 [options addObjectsFromArray:[[shipyardInfo oo_dictionaryForKey:KEY_STANDARD_EQUIPMENT] oo_arrayForKey:KEY_EQUIPMENT_EXTRAS]];
3482 if (![options containsObject:equipmentKey]) return NO;
3483 }
3484 }
3485 else
3486 {
3487 if (![eqType isAvailableToNPCs]) return NO;
3488 }
3489
3490 return YES;
3491}
NSString * conditionScript()
BOOL callMethod:inContext:withArguments:count:result:(jsid methodID,[inContext] JSContext *context,[withArguments] jsval *argv,[count] intN argc,[result] jsval *outResult)
Definition OOJSScript.m:395
NSDictionary * shipyardInfoForKey:(NSString *key)
OOShipRegistry * sharedRegistry()
NSUInteger passengerCount()
NSUInteger missileCount()
OOCargoQuantity availableCargoSpace()
OOFuelQuantity fuelCapacity()
NSUInteger missileCapacity()

◆ escortArray

- (NSArray *) escortArray

Definition at line 6496 of file ShipEntity.m.

6991{
6992 if (_escortGroup == nil) return [NSArray array];
6993 return [[self escortEnumerator] allObjects];
6994}

◆ escortCheckMother

- (void) escortCheckMother
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1841{
1842 ShipEntity *mother = [self owner];
1843
1844 if ([mother acceptAsEscort:self])
1845 {
1846 [self setOwner:mother];
1847 [self setGroup:[mother escortGroup]];
1848 [shipAI message:@"ESCORTING"];
1849 }
1850 else
1851 {
1852 [self setOwner:self];
1853 if ([self group] == [mother escortGroup]) [self setGroup:nil];
1854 [shipAI message:@"NOT_ESCORTING"];
1855 }
1856}

◆ escortCount

- (uint8_t) escortCount

Definition at line 6496 of file ShipEntity.m.

6998{
6999 if (_escortGroup == nil) return 0;
7000 return [_escortGroup count] - 1;
7001}

◆ escortEnumerator

- (NSEnumerator *) escortEnumerator

Definition at line 6496 of file ShipEntity.m.

6984{
6985 if (_escortGroup == nil) return [[NSArray array] objectEnumerator];
6986 return [[_escortGroup mutationSafeEnumerator] ooExcludingObject:self];
6987}

◆ escortGroup

- (OOShipGroup *) escortGroup

Definition at line 6496 of file ShipEntity.m.

6933{
6934 if (_escortGroup == nil)
6935 {
6936 _escortGroup = [[OOShipGroup alloc] initWithName:@"escort group"];
6937 [_escortGroup setLeader:self];
6938 }
6939
6940 return _escortGroup;
6941}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ evasiveAction:

- (void) evasiveAction: (double) delta_t

Definition at line 9593 of file ShipEntity.m.

10442 :(double) delta_t
10443{
10444 stick_roll = flightRoll; //desired roll and pitch
10446
10447 ShipEntity* target = [self primaryTarget];
10448 if (!target) // leave now!
10449 {
10450 [self noteLostTargetAndGoIdle]; // NOTE: was AI message: rather than reactToMessage:
10451 return;
10452 }
10453
10454 double agreement = dot_product(v_right,target->v_right);
10455 if (agreement > -0.3 && agreement < 0.3)
10456 {
10457 stick_roll = 0.0;
10458 }
10459 else
10460 {
10461 if (stick_roll >= 0.0) {
10463 } else {
10465 }
10466 }
10467 if (stick_pitch >= 0.0) {
10469 } else {
10471 }
10472
10473 [self applySticks:delta_t];
10474}

◆ exhaustEmissiveColor

- (OOColor *) exhaustEmissiveColor

Definition at line 9593 of file ShipEntity.m.

11724{
11725 return [[exhaust_emissive_color retain] autorelease];
11726}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ exhaustEnumerator

- (NSEnumerator *) exhaustEnumerator

Definition at line 14954 of file ShipEntity.m.

1350{
1351 return [[self subEntities] objectEnumeratorFilteredWithSelector:@selector(isExhaust)];
1352}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ exitAIWithMessage:

- (void) exitAIWithMessage: (NSString *) message
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1418 :(NSString *)message
1419{
1420 if ([message length] == 0) message = @"RESTARTED";
1421 [shipAI exitStateMachineWithMessage:message];
1422}

◆ explodeSelf

- (void) explodeSelf
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2645{
2646 [self getDestroyedBy:nil damageType:kOODamageTypeEnergy];
2647}

◆ extraCargo

- (NSUInteger) extraCargo

Definition at line 2093 of file ShipEntity.m.

3942{
3943 return extra_cargo;
3944}

◆ fightOrFleeHostiles

- (void) fightOrFleeHostiles
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ fightOrFleeMissile

- (void) fightOrFleeMissile
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ findBoundingBoxRelativeTo:InVectors:_i:_j:

- (BoundingBox) findBoundingBoxRelativeTo: (Entity *) other
InVectors: (Vector)
_i: (Vector)
_j: (Vector) _k 
implementation

Definition at line 14073 of file ShipEntity.m.

14313 :(Entity *)other InVectors:(Vector) _i :(Vector) _j :(Vector) _k
14314{
14315 HPVector opv = other ? other->position : position;
14316 return [self findBoundingBoxRelativeToPosition:opv InVectors:_i :_j :_k];
14317}

◆ findBoundingBoxRelativeToPosition:InVectors:_i:_j:

- (BoundingBox) findBoundingBoxRelativeToPosition: (HPVector) opv
InVectors: (Vector)
_i: (Vector)
_j: (Vector) _k 
implementation

Definition at line 14954 of file ShipEntity.m.

1420 :(HPVector)opv InVectors:(Vector) _i :(Vector) _j :(Vector) _k
1421{
1422 // HPVect: check that this conversion doesn't lose needed precision
1423 return [[self mesh] findBoundingBoxRelativeToPosition:HPVectorToVector(opv)
1424 basis:_i :_j :_k
1425 selfPosition:HPVectorToVector(position)
1426 selfBasis:v_right :v_up :v_forward];
1427}

◆ findBoundingBoxRelativeToPosition:InVectors:i:j:

- (BoundingBox) findBoundingBoxRelativeToPosition: (HPVector) opv
InVectors: (Vector)
i: (Vector)
j: (Vector) k 

Referenced by abandonShip.

+ Here is the caller graph for this function:

◆ findNearestPlanet

- (OOPlanetEntity *) findNearestPlanet

Definition at line 7619 of file ShipEntity.m.

7636{
7637 /*
7638 Performance note: this method is called every frame by every ship, and
7639 has a significant profiler presence.
7640 -- Ahruman 2012-09-13
7641 */
7642 OOPlanetEntity *planet = nil, *bestPlanet = nil;
7643 float bestRange = INFINITY;
7644 HPVector myPosition = [self position];
7645
7646 // valgrind complains about this line here. Might be compiler/GNUstep bug?
7647 // should we go back to a traditional enumerator? - CIM
7648 // similar complaints about the other foreach() in this file
7649 foreach (planet, [UNIVERSE planets])
7650 {
7651 // Ignore miniature planets.
7652 if ([planet planetType] == STELLAR_TYPE_MINIATURE) continue;
7653
7654 float range = SurfaceDistanceSqaredV(myPosition, planet);
7655 if (range < bestRange)
7656 {
7657 bestPlanet = planet;
7658 bestRange = range;
7659 }
7660 }
7661
7662 return bestPlanet;
7663}
@ STELLAR_TYPE_MINIATURE

◆ findNearestPlanetExcludingMoons

- (OOPlanetEntity *) findNearestPlanetExcludingMoons

Definition at line 7619 of file ShipEntity.m.

7685{
7686 OOPlanetEntity *result = nil;
7687 OOPlanetEntity *planet = nil;
7688 NSArray *bodies = nil;
7689 NSArray *planets = nil;
7690 unsigned i;
7691
7692 bodies = [UNIVERSE planets];
7693 planets = [NSMutableArray arrayWithCapacity:[bodies count]];
7694
7695 for (i=0; i < [bodies count]; i++)
7696 {
7697 planet = [bodies objectAtIndex:i];
7698 if([planet planetType] == STELLAR_TYPE_NORMAL_PLANET)
7699 planets = [planets arrayByAddingObject:planet];
7700 }
7701
7702 if ([planets count] == 0) return nil;
7703
7704 planets = [planets sortedArrayUsingFunction:ComparePlanetsBySurfaceDistance context:self];
7705 result = [planets objectAtIndex:0];
7706
7707 return result;
7708}
@ STELLAR_TYPE_NORMAL_PLANET

◆ findNearestStellarBody

- (Entity< OOStellarBody > *) findNearestStellarBody

Definition at line 7619 of file ShipEntity.m.

7667{
7668 Entity<OOStellarBody> *match = [self findNearestPlanet];
7669 OOSunEntity *sun = [UNIVERSE sun];
7670
7671 if (sun != nil)
7672 {
7673 if (match == nil ||
7674 SurfaceDistanceSqared(self, sun) < SurfaceDistanceSqared(self, match))
7675 {
7676 match = sun;
7677 }
7678 }
7679
7680 return match;
7681}
static float SurfaceDistanceSqared(Entity *reference, Entity< OOStellarBody > *stellar)

◆ findNewDefenseTarget

- (void) findNewDefenseTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1545{
1546 [self checkScanner];
1547 unsigned i;
1548 for (i = 0; i < n_scanned_ships ; i++)
1549 {
1550 ShipEntity *ship = scanned_ships[i];
1551 if (![ship isCloaked] && (([ship primaryTarget] == self && [ship hasHostileTarget]) || [ship isMine] || ([ship isThargoid] != [self isThargoid])))
1552 {
1553 if (![self isDefenseTarget:ship])
1554 {
1555 [self addDefenseTarget:ship];
1556 return;
1557 }
1558 }
1559 }
1560}

◆ findSubentityBoundingBox

- (BoundingBox) findSubentityBoundingBox

Definition at line 2093 of file ShipEntity.m.

2229{
2230 return [[self mesh] findSubentityBoundingBoxWithPosition:HPVectorToVector(position) rotMatrix:rotMatrix];
2231}

◆ fireAftWeapon:

- (BOOL) fireAftWeapon: (double) range

Definition at line 9593 of file ShipEntity.m.

11602 :(double)range
11603{
11604 // set the values from aft_weapon_type.
11606 [self setWeaponDataFromType:aft_weapon_type];
11607
11608 return [self fireWeapon:aft_weapon_type direction:WEAPON_FACING_AFT range:range];
11609}

◆ fireDirectLaserDefensiveShot

- (BOOL) fireDirectLaserDefensiveShot

Definition at line 9593 of file ShipEntity.m.

11828{
11829 NSEnumerator *targetEnum = [self defenseTargetEnumerator];
11830 Entity *target = nil;
11831 while ((target = [[targetEnum nextObject] weakRefUnderlyingObject]))
11832 {
11833 // can't fire defensively at cloaked ships
11834 if ([target scanClass] == CLASS_NO_DRAW || [(ShipEntity *)target isCloaked] || [target energy] <= 0.0)
11835 {
11836 [self removeDefenseTarget:target];
11837 }
11838 else
11839 {
11840 double range = [self rangeToSecondaryTarget:target];
11841 if (range < weaponRange)
11842 {
11843 return [self fireDirectLaserShotAt:target];
11844 }
11845 else if (range > scannerRange)
11846 {
11847 [self removeDefenseTarget:target];
11848 }
11849 }
11850 }
11851 return NO;
11852}

◆ fireDirectLaserShot:

- (BOOL) fireDirectLaserShot: (double) range

Definition at line 9593 of file ShipEntity.m.

11817 :(double)range
11818{
11819 Entity *my_target = [self primaryTarget];
11820 if (my_target == nil) return [self fireDirectLaserDefensiveShot];
11821 if (range > randf() * weaponRange * (accuracy+5.5)) return [self fireDirectLaserDefensiveShot];
11822 if (range > weaponRange) return [self fireDirectLaserDefensiveShot];
11823 return [self fireDirectLaserShotAt:my_target];
11824}

◆ fireDirectLaserShotAt:

- (BOOL) fireDirectLaserShotAt: (Entity *) my_target

Definition at line 9593 of file ShipEntity.m.

11855 :(Entity *)my_target
11856{
11857 GLfloat hit_at_range;
11858 double range_limit2 = weaponRange*weaponRange;
11859 Vector r_pos;
11860
11861 r_pos = vector_normal_or_zbasis([self vectorTo:my_target]);
11862
11863 Quaternion q_laser = quaternion_rotation_between(r_pos, kBasisZVector);
11864
11865 GLfloat acc_factor = (10.0 - accuracy) * 0.001;
11866
11867 q_laser.x += acc_factor * (randf() - 0.5); // randomise aim a little (+/- 0.005 at accuracy 0, never miss at accuracy 10)
11868 q_laser.y += acc_factor * (randf() - 0.5);
11869 q_laser.z += acc_factor * (randf() - 0.5);
11870 quaternion_normalize(&q_laser);
11871
11872 Quaternion q_save = orientation; // save rotation
11873 orientation = q_laser; // face in direction of laser
11874 // weapon offset for thargoid lasers is always zero
11875 ShipEntity *victim = [UNIVERSE firstShipHitByLaserFromShip:self inDirection:WEAPON_FACING_FORWARD offset:kZeroVector gettingRangeFound:&hit_at_range];
11876 [self setShipHitByLaser:victim];
11877 orientation = q_save; // restore rotation
11878
11879 Vector vel = vector_multiply_scalar(v_forward, flightSpeed);
11880
11881 // do special effects laser line
11882 OOLaserShotEntity *shot = [OOLaserShotEntity laserFromShip:self direction:WEAPON_FACING_FORWARD offset:kZeroVector];
11883 [shot setColor:laser_color];
11884 [shot setScanClass: CLASS_NO_DRAW];
11885 [shot setPosition: position];
11886 [shot setOrientation: q_laser];
11887 [shot setVelocity: vel];
11888
11889 if (victim != nil)
11890 {
11891 ShipEntity *subent = [victim subEntityTakingDamage];
11892 if (subent != nil && [victim isFrangible])
11893 {
11894 // do 1% bleed-through damage...
11895 [victim takeEnergyDamage: 0.01 * weapon_damage from:self becauseOf:self weaponIdentifier:[[self weaponTypeForFacing:WEAPON_FACING_FORWARD strict:YES] identifier]];
11896 victim = subent;
11897 }
11898
11899 if (hit_at_range * hit_at_range < range_limit2)
11900 {
11901 [victim takeEnergyDamage:weapon_damage from:self becauseOf:self weaponIdentifier:[[self weaponTypeForFacing:WEAPON_FACING_FORWARD strict:YES] identifier]]; // a very palpable hit
11902
11903 [shot setRange:hit_at_range];
11904 Vector vd = vector_forward_from_quaternion([shot orientation]);
11905 HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hit_at_range)));
11906 [UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:weapon_damage color:laser_color];
11907 }
11908 }
11909
11910 [UNIVERSE addEntity:shot];
11911
11912 [self resetShotTime];
11913
11914 return YES;
11915}
void setRange:(GLfloat range)
void setColor:(OOColor *color)
instancetype laserFromShip:direction:offset:(ShipEntity *ship,[direction] OOWeaponFacing direction,[offset] Vector offset)
ShipEntity * subEntityTakingDamage()

◆ fireECM

- (BOOL) fireECM

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12355{
12356 if (![self hasECM]) return NO;
12357
12358 OOECMBlastEntity *ecmDevice = [[OOECMBlastEntity alloc] initFromShip:self];
12359 [UNIVERSE addEntity:ecmDevice];
12360 [ecmDevice release];
12361 return YES;
12362}

Referenced by ShipFireECM().

+ Here is the caller graph for this function:

◆ fireLaserShotInDirection:weaponIdentifier:

- (BOOL) fireLaserShotInDirection: (OOWeaponFacing) direction
weaponIdentifier: (NSString *) weaponIdentifier 

Definition at line 9593 of file ShipEntity.m.

11944 :(OOWeaponFacing)direction weaponIdentifier:(NSString *)weaponIdentifier
11945{
11946 double range_limit2 = weaponRange * weaponRange;
11947 GLfloat hit_at_range;
11948 NSUInteger i, barrels;
11949 Vector vel = vector_multiply_scalar(v_forward, flightSpeed);
11950 NSArray *laserPortOffsets = [self laserPortOffset:direction];
11951 OOLaserShotEntity *shot = nil;
11952
11953 barrels = [laserPortOffsets count];
11954 NSMutableArray *shotEntities = [NSMutableArray arrayWithCapacity:barrels];
11955
11956
11957 GLfloat effective_damage = weapon_damage;
11958 if (barrels > 1 && !_multiplyWeapons)
11959 {
11960 // then divide the shot power between the shots
11961 effective_damage /= (GLfloat)barrels;
11962 }
11963
11964 for (i=0;i<barrels;i++)
11965 {
11966 Vector laserPortOffset = [laserPortOffsets oo_vectorAtIndex:i];
11967
11968 last_shot_time = [UNIVERSE getTime];
11969
11970 ShipEntity *victim = [UNIVERSE firstShipHitByLaserFromShip:self inDirection:direction offset:laserPortOffset gettingRangeFound:&hit_at_range];
11971 [self setShipHitByLaser:victim];
11972
11973 shot = [OOLaserShotEntity laserFromShip:self direction:direction offset:laserPortOffset];
11974 if ([self isPlayer])
11975 {
11976 [shotEntities addObject:shot];
11977 }
11978
11979 [shot setColor:laser_color];
11980 [shot setScanClass: CLASS_NO_DRAW];
11981 [shot setVelocity: vel];
11982
11983 if (victim != nil)
11984 {
11985 [self adjustMissedShots:-1];
11986 if ([self isPlayer])
11987 {
11988 [PLAYER addRoleForAggression:victim];
11989 }
11990
11991 /* CRASH in [victim->sub_entities containsObject:subent] here (1.69, OS X/x86).
11992 Analysis: Crash is in _freedHandler called from CFEqual, indicating either a dead
11993 object in victim->sub_entities or dead victim->subentity_taking_damage. I suspect
11994 the latter. Probable solution: dying subentities must cause parent to clean up
11995 properly. This was probably obscured by the entity recycling scheme in the past.
11996 Fix: made subentity_taking_damage a weak reference accessed via a method.
11997 -- Ahruman 20070706, 20080304
11998 */
11999 ShipEntity *subent = [victim subEntityTakingDamage];
12000 if (subent != nil && [victim isFrangible])
12001 {
12002 // do 1% bleed-through damage...
12003 [victim takeEnergyDamage: 0.01 * effective_damage from:self becauseOf:self weaponIdentifier:weaponIdentifier];
12004 victim = subent;
12005 }
12006
12007 if (hit_at_range * hit_at_range < range_limit2)
12008 {
12009 [victim takeEnergyDamage:effective_damage from:self becauseOf:self weaponIdentifier:weaponIdentifier]; // a very palpable hit
12010
12011 [shot setRange:hit_at_range];
12012 Vector vd = vector_forward_from_quaternion([shot orientation]);
12013 HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hit_at_range)));
12014 [UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:effective_damage color:laser_color];
12015 }
12016 }
12017 else
12018 {
12019 [self adjustMissedShots:+1];
12020
12021 // shot missed
12022 if (![self isCloaked])
12023 {
12024 victim = [self primaryTarget];
12025 if ([victim isShip]) // it might not be - fixes crash bug
12026 {
12027
12028 /* player currently gets a bit of an advantage here if
12029 * they ambush without having their target actually
12030 * targeted. Though in those circumstances they
12031 * shouldn't be missing their first shot anyway. */
12032 if (dot_product(vector_forward_from_quaternion([shot orientation]),vector_normal([self vectorTo:victim])) > 0.995)
12033 {
12034 /* plausibly aimed at target. Allows reaction
12035 * before attacker actually hits. But we need to
12036 * be able to distinguish in AI from ATTACKED so
12037 * that ships in combat aren't bothered by
12038 * amateurs. So should only respond to
12039 * ATTACKER_MISSED if not already fighting */
12040 if ([self isPlayer])
12041 {
12042 [PLAYER addRoleForAggression:victim];
12043 }
12044 [victim setPrimaryAggressor:self];
12045 [victim setFoundTarget:self];
12046 [victim reactToAIMessage:@"ATTACKER_MISSED" context:@"attacker narrowly misses"];
12047 [victim doScriptEvent:OOJSID("shipBeingAttackedUnsuccessfully") withArgument:self];
12048 }
12049 }
12050 }
12051 }
12052
12053 [UNIVERSE addEntity:shot];
12054
12055 }
12056
12057 if ([self isPlayer])
12058 {
12059 [(PlayerEntity *)self setLastShot:shotEntities];
12060 }
12061
12062 [self resetShotTime];
12063
12064 return YES;
12065}
OOWeaponFacing
Definition OOTypes.h:228
OOTimeAbsolute last_shot_time
Definition ShipEntity.h:359
BOOL _multiplyWeapons
Definition ShipEntity.h:391

◆ fireMainWeapon:

- (BOOL) fireMainWeapon: (double) range

Definition at line 9593 of file ShipEntity.m.

11556 :(double)range
11557{
11558 // set the values from forward_weapon_type.
11559 // OXPs can override the default front laser energy damage.
11561 [self setWeaponDataFromType:forward_weapon_type];
11562
11563// weapon damage override no longer effective
11564// weapon_damage = weapon_damage_override;
11565
11566 BOOL result = [self fireWeapon:forward_weapon_type direction:WEAPON_FACING_FORWARD range:range];
11568 {
11569 // need to check subentities to avoid AI oddities
11570 // will already have fired them by now, though
11571 NSEnumerator *subEnum = [self shipSubEntityEnumerator];
11572 ShipEntity *se = nil;
11573 OOWeaponType weapon_type = nil;
11574 BOOL hasTurrets = NO;
11575 while (isWeaponNone(weapon_type) && (se = [subEnum nextObject]))
11576 {
11577 weapon_type = se->forward_weapon_type;
11579 if (se->behaviour == BEHAVIOUR_TRACK_AS_TURRET)
11580 {
11581 hasTurrets = YES;
11582 }
11583 }
11584 if (isWeaponNone(weapon_type) && hasTurrets)
11585 { /* no forward weapon but has turrets, so set up range calculations accordingly
11586 note: this was hard-coded to 10000.0, although turrets have a notably
11587 shorter range. We are using a multiplier of 1.667 in order to not change
11588 something that already works, but probably it would be best to use
11589 TURRET_SHOT_RANGE * COMBAT_WEAPON_RANGE_FACTOR here
11590 */
11592 }
11593 else
11594 {
11595 [self setWeaponDataFromType:weapon_type];
11596 }
11597 }
11598 return result;
11599}
#define TURRET_SHOT_RANGE
Definition ShipEntity.h:82

◆ fireMissile

- (ShipEntity *) fireMissile

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12173{
12174 return [self fireMissileWithIdentifier:nil andTarget:[self primaryTarget]];
12175}

Referenced by ShipFireMissile().

+ Here is the caller graph for this function:

◆ fireMissileWithIdentifier:andTarget:

- (ShipEntity *) fireMissileWithIdentifier: (NSString *) identifier
andTarget: (Entity *) target 

Definition at line 9593 of file ShipEntity.m.

12178 :(NSString *) identifier andTarget:(Entity *) target
12179{
12180 // both players and NPCs!
12181 //
12182 ShipEntity *missile = nil;
12183 ShipEntity *target_ship = nil;
12184
12185 Vector vel;
12186 Vector start, v_eject;
12187
12188 if ([UNIVERSE getTime] < missile_launch_time) return nil;
12189
12190 start = [self missileLaunchPosition];
12191
12192 double throw_speed = 250.0f;
12193
12194 if ((missiles <= 0)||(target == nil)||([target scanClass] == CLASS_NO_DRAW)) // no missile lock!
12195 return nil;
12196
12197 if ([target isShip])
12198 {
12199 target_ship = (ShipEntity*)target;
12200 if ([target_ship isCloaked])
12201 {
12202 return nil;
12203 }
12204 // missile fire requires being in scanner range
12205 if (HPmagnitude2(HPvector_subtract([target_ship position], position)) > scannerRange * scannerRange)
12206 {
12207 return nil;
12208 }
12209 if (![self hasMilitaryScannerFilter] && [target_ship isJammingScanning])
12210 {
12211 return nil;
12212 }
12213 }
12214
12215 unsigned i;
12216 if (identifier == nil)
12217 {
12218 // use a random missile from the list
12219 i = floor(randf()*(double)missiles);
12220 identifier = [missile_list[i] identifier];
12221 missile = [UNIVERSE newShipWithRole:identifier];
12222 if (EXPECT_NOT(missile == nil)) // invalid missile role.
12223 {
12224 // remove that invalid missile role from the missiles list.
12225 while ( ++i < missiles ) missile_list[i - 1] = missile_list[i];
12226 missiles--;
12227 }
12228 }
12229 else
12230 missile = [UNIVERSE newShipWithRole:identifier];
12231
12232 if (EXPECT_NOT(missile == nil)) return nil;
12233
12234 // By definition, the player will always have the specified missile.
12235 // What if the NPC didn't actually have the specified missile to begin with?
12236 if (!isPlayer && ![self removeExternalStore:[OOEquipmentType equipmentTypeWithIdentifier:identifier]])
12237 {
12238 [missile release];
12239 return nil;
12240 }
12241
12242 double mcr = missile->collision_radius;
12243 v_eject = vector_normal(start);
12244 vel = kZeroVector; // starting velocity
12245
12246 // check if start is within bounding box...
12247 while ( (start.x > boundingBox.min.x - mcr)&&(start.x < boundingBox.max.x + mcr)&&
12248 (start.y > boundingBox.min.y - mcr)&&(start.y < boundingBox.max.y + mcr)&&
12249 (start.z > boundingBox.min.z - mcr)&&(start.z < boundingBox.max.z + mcr) )
12250 {
12251 start = vector_add(start, vector_multiply_scalar(v_eject, mcr));
12252 }
12253
12254 vel = vector_add(vel, vector_multiply_scalar(v_forward, flightSpeed + throw_speed));
12255
12256 Quaternion q1 = [self normalOrientation];
12257 HPVector origin = HPvector_add(position, vectorToHPVector(quaternion_rotate_vector(q1, start)));
12258
12259 if (isPlayer) [missile setScanClass: CLASS_MISSILE];
12260
12261// special cases
12262
12263 //We don't want real missiles in a group. Missiles could become escorts when the group is also used as escortGroup.
12264 if ([missile scanClass] == CLASS_THARGOID)
12265 {
12266 if([self group] == nil) [self setGroup:[OOShipGroup groupWithName:@"thargoid group"]];
12267
12268 ShipEntity *thisGroupLeader = [_group leader];
12269
12270 if ([thisGroupLeader escortGroup] != _group) // avoid adding tharons to escort groups
12271 {
12272 [missile setGroup:[self group]];
12273 }
12274 }
12275
12276 // is this a submunition?
12277 if (![self isMissileFlagSet]) [missile setOwner:self];
12278 else [missile setOwner:[self owner]];
12279
12280// end special cases
12281
12282 [missile setPosition:origin];
12283 [missile addTarget:target];
12284 [missile setOrientation:q1];
12285 [missile setIsMissileFlag:YES];
12286 [missile setVelocity:vel];
12287 [missile setSpeed:150.0f];
12288 [missile setDistanceTravelled:0.0f];
12289 [missile resetShotTime];
12290 missile_launch_time = [UNIVERSE getTime] + missile_load_time; // set minimum launchtime for the next missile.
12291
12292 [UNIVERSE addEntity:missile]; // STATUS_IN_FLIGHT, AI state GLOBAL
12293 [missile release]; //release
12294
12295 // missile lives on after UNIVERSE addEntity
12296 if ([missile isMissile] && [target isShip])
12297 {
12298 [self doScriptEvent:OOJSID("shipFiredMissile") withArgument:missile andArgument:target_ship];
12299 [target_ship setPrimaryAggressor:self];
12300 [target_ship doScriptEvent:OOJSID("shipAttackedWithMissile") withArgument:missile andArgument:self];
12301 [target_ship reactToAIMessage:@"INCOMING_MISSILE" context:@"someone's shooting at me!"];
12303 {
12304 // parity between player &NPCs, only deactivate cloak for missiles
12305 [self deactivateCloakingDevice];
12306 }
12307 }
12308 else
12309 {
12310 [self doScriptEvent:OOJSID("shipReleasedEquipment") withArgument:missile];
12311 }
12312
12313 return missile;
12314}
void setDistanceTravelled:(GLfloat value)
Definition Entity.m:781
instancetype groupWithName:(NSString *name)
BOOL isJammingScanning()
void setSpeed:(double amount)
OOTimeDelta missile_load_time
Definition ShipEntity.h:322
BOOL hasMilitaryScannerFilter()
OOTimeAbsolute missile_launch_time
Definition ShipEntity.h:323
BOOL isMissileFlagSet()
unsigned cloakPassive
Definition ShipEntity.h:266
void resetShotTime()
void setIsMissileFlag:(BOOL newValue)
voidpf uLong int origin
Definition ioapi.h:140

Referenced by ShipFireMissile().

+ Here is the caller graph for this function:

◆ firePortWeapon:

- (BOOL) firePortWeapon: (double) range

Definition at line 9593 of file ShipEntity.m.

11612 :(double)range
11613{
11614 // set the values from port_weapon_type.
11616 [self setWeaponDataFromType:port_weapon_type];
11617
11618 return [self fireWeapon:port_weapon_type direction:WEAPON_FACING_PORT range:range];
11619}

◆ fireStarboardWeapon:

- (BOOL) fireStarboardWeapon: (double) range

Definition at line 9593 of file ShipEntity.m.

11622 :(double)range
11623{
11624 // set the values from starboard_weapon_type.
11626 [self setWeaponDataFromType:starboard_weapon_type];
11627
11628 return [self fireWeapon:starboard_weapon_type direction:WEAPON_FACING_STARBOARD range:range];
11629}

◆ fireSubentityLaserShot:

- (BOOL) fireSubentityLaserShot: (double) range

Definition at line 9593 of file ShipEntity.m.

11729 :(double)range
11730{
11731 [self setShipHitByLaser:nil];
11732
11733 if (isWeaponNone(forward_weapon_type)) return NO;
11734 [self setWeaponDataFromType:forward_weapon_type];
11735
11736 ShipEntity *parent = [self owner];
11737 NSAssert([parent isShipWithSubEntityShip:self], @"-fireSubentityLaserShot: called on ship which is not a subentity.");
11738
11739 // subentity lasers still draw power from the main entity
11740 if ([parent energy] <= weapon_energy_use) return NO;
11741 if ([self shotTime] < weapon_recharge_rate) return NO;
11743 if (range > weaponRange) return NO;
11744
11746 [parent setEnergy:([parent energy] - weapon_energy_use)];
11747
11748 GLfloat hitAtRange = weaponRange;
11750 ShipEntity *victim = [UNIVERSE firstShipHitByLaserFromShip:self inDirection:direction offset:kZeroVector gettingRangeFound:&hitAtRange];
11751 [self setShipHitByLaser:victim];
11752
11753 OOLaserShotEntity *shot = [OOLaserShotEntity laserFromShip:self direction:direction offset:kZeroVector];
11754 [shot setColor:laser_color];
11755 [shot setScanClass:CLASS_NO_DRAW];
11756
11757 if (victim != nil)
11758 {
11759 [self adjustMissedShots:-1];
11760
11761 if ([self isPlayer])
11762 {
11763 [PLAYER addRoleForAggression:victim];
11764 }
11765
11766 ShipEntity *subent = [victim subEntityTakingDamage];
11767 if (subent != nil && [victim isFrangible])
11768 {
11769 // do 1% bleed-through damage...
11770 [victim takeEnergyDamage:0.01 * weapon_damage from:self becauseOf:parent weaponIdentifier:[[self weaponTypeForFacing:WEAPON_FACING_FORWARD strict:YES] identifier]];
11771 victim = subent;
11772 }
11773
11774 if (hitAtRange < weaponRange)
11775 {
11776 [victim takeEnergyDamage:weapon_damage from:self becauseOf:parent weaponIdentifier:[[self weaponTypeForFacing:WEAPON_FACING_FORWARD strict:YES] identifier]]; // a very palpable hit
11777
11778 [shot setRange:hitAtRange];
11779 Vector vd = vector_forward_from_quaternion([shot orientation]);
11780 HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hitAtRange)));
11781 [UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:weapon_damage color:laser_color];
11782 }
11783 }
11784 else
11785 {
11786 [self adjustMissedShots:+1];
11787
11788 // see ATTACKER_MISSED section of main entity laser routine
11789 if (![parent isCloaked])
11790 {
11791 victim = [parent primaryTarget];
11792
11793 Vector shotDirection = vector_forward_from_quaternion([shot orientation]);
11794 Vector victimDirection = vector_normal(HPVectorToVector(HPvector_subtract([victim position], [parent position])));
11795 if (dot_product(shotDirection, victimDirection) > 0.995) // Within 84.26 degrees
11796 {
11797 if ([self isPlayer])
11798 {
11799 [PLAYER addRoleForAggression:victim];
11800 }
11801 [victim setPrimaryAggressor:parent];
11802 [victim setFoundTarget:parent];
11803 [victim reactToAIMessage:@"ATTACKER_MISSED" context:@"attacker narrowly misses"];
11804 [victim doScriptEvent:OOJSID("shipBeingAttackedUnsuccessfully") withArgument:parent];
11805
11806 }
11807 }
11808 }
11809
11810 [UNIVERSE addEntity:shot];
11811 [self resetShotTime];
11812
11813 return YES;
11814}
#define NPC_MAX_WEAPON_TEMP
Definition ShipEntity.h:115
#define WEAPON_COOLING_CUTOUT
Definition ShipEntity.h:116
GLfloat weapon_energy_use
Definition ShipEntity.h:314
GLfloat weapon_shot_temperature
Definition ShipEntity.h:314
float weapon_recharge_rate
Definition ShipEntity.h:356

◆ fireTurretCannon:

- (BOOL) fireTurretCannon: (double) range

Definition at line 9593 of file ShipEntity.m.

11644 :(double) range
11645{
11646 if ([self shotTime] < weapon_recharge_rate)
11647 return NO;
11648 if (range > weaponRange * 1.01) // 1% more than max range - open up just slightly early
11649 return NO;
11650 ShipEntity *root = [self rootShipEntity];
11651 if ([root isPlayer] && ![PLAYER weaponsOnline])
11652 return NO;
11653
11654 if ([root isCloaked] && [root cloakPassive])
11655 {
11656 // can't fire turrets while cloaked
11657 return NO;
11658 }
11659
11660 Vector vel;
11661 HPVector origin = [self position];
11662
11663 Entity *last = nil;
11664 Entity *father = [self parentEntity];
11665 OOMatrix r_mat;
11666
11668 // adjust velocity and position vectors to absolute coordinates
11669 while ((father)&&(father != last) && (father != NO_TARGET))
11670 {
11671 r_mat = [father drawRotationMatrix];
11672 origin = HPvector_add(OOHPVectorMultiplyMatrix(origin, r_mat), [father position]);
11673 vel = OOVectorMultiplyMatrix(vel, r_mat);
11674 last = father;
11675 if (![last isSubEntity]) break;
11676 father = [father owner];
11677 }
11678
11679 origin = HPvector_add(origin, vectorToHPVector(vector_multiply_scalar(vel, collision_radius + 0.5))); // Start just outside collision sphere
11680 vel = vector_multiply_scalar(vel, TURRET_SHOT_SPEED); // Shot velocity
11681
11682 OOPlasmaShotEntity *shot = [[OOPlasmaShotEntity alloc] initWithPosition:origin
11683 velocity:vel
11684 energy:weapon_damage
11685 duration:weaponRange/TURRET_SHOT_SPEED
11686 color:laser_color];
11687
11688 [shot autorelease];
11689 [UNIVERSE addEntity:shot];
11690 [shot setOwner:[self rootShipEntity]]; // has to be done AFTER adding shot to the UNIVERSE
11691
11692 [self resetShotTime];
11693 return YES;
11694}
HPVector OOHPVectorMultiplyMatrix(HPVector v, OOMatrix m)
Definition OOMatrix.m:145

◆ fireWeapon:direction:range:

- (BOOL) fireWeapon: (OOWeaponType) weapon_type
direction: (OOWeaponFacing) direction
range: (double) range 
implementation

Definition at line 9593 of file ShipEntity.m.

11450 :(OOWeaponType)weapon_type direction:(OOWeaponFacing)direction range:(double)range
11451{
11452 weapon_temp = 0.0;
11453 switch (direction)
11454 {
11457 break;
11458
11459 case WEAPON_FACING_AFT:
11461 break;
11462
11463 case WEAPON_FACING_PORT:
11465 break;
11466
11469 break;
11470
11471 case WEAPON_FACING_NONE:
11472 break;
11473 }
11475
11476 NSUInteger multiplier = 1;
11477 if (_multiplyWeapons)
11478 {
11479 // multiple fitted
11480 multiplier = [[self laserPortOffset:direction] count];
11481 }
11482
11483 if (energy <= weapon_energy_use * multiplier) return NO;
11484 if ([self shotTime] < weapon_recharge_rate) return NO;
11485 if (![weapon_type isTurretLaser])
11486 { // thargoid laser may just pick secondary target in this case
11487 if (range > randf() * weaponRange * (accuracy+7.5)) return NO;
11488 if (range > weaponRange) return NO;
11489 }
11490 if (![self onTarget:direction withWeapon:weapon_type]) return NO;
11491
11492 BOOL fired = NO;
11493 if (!isWeaponNone(weapon_type))
11494 {
11495 if ([weapon_type isTurretLaser])
11496 {
11497 [self fireDirectLaserShot:range];
11498 fired = YES;
11499 }
11500 else
11501 {
11502 [self fireLaserShotInDirection:direction weaponIdentifier:[weapon_type identifier]];
11503 fired = YES;
11504 }
11505 }
11506
11507 if (fired)
11508 {
11509 energy -= weapon_energy_use * multiplier;
11510 switch (direction)
11511 {
11514 break;
11515
11516 case WEAPON_FACING_AFT:
11518 break;
11519
11520 case WEAPON_FACING_PORT:
11522 break;
11523
11526 break;
11527
11528 case WEAPON_FACING_NONE:
11529 break;
11530 }
11531 }
11532
11533 if (direction == WEAPON_FACING_FORWARD)
11534 {
11535 //can we fire lasers from our subentities?
11536 NSEnumerator *subEnum = nil;
11537 ShipEntity *se = nil;
11538 for (subEnum = [self shipSubEntityEnumerator]; (se = [subEnum nextObject]); )
11539 {
11540 if ([se fireSubentityLaserShot:range])
11541 {
11542 fired = YES;
11543 }
11544 }
11545 }
11546
11547 if (fired && cloaking_device_active && cloakPassive)
11548 {
11549 [self deactivateCloakingDevice];
11550 }
11551
11552 return fired;
11553}
@ WEAPON_FACING_NONE
Definition OOTypes.h:234
OOEquipmentType * OOWeaponType
Definition ShipEntity.h:168

◆ flasherEnumerator

- (NSEnumerator *) flasherEnumerator

Definition at line 14954 of file ShipEntity.m.

1344{
1345 return [[self subEntities] objectEnumeratorFilteredWithSelector:@selector(isFlasher)];
1346}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ flightPitch

- (GLfloat) flightPitch

◆ flightRoll

- (GLfloat) flightRoll

◆ flightSpeed

- (GLfloat) flightSpeed

◆ flightYaw

- (GLfloat) flightYaw

◆ forceAegisCheck

- (void) forceAegisCheck

Definition at line 7619 of file ShipEntity.m.

7874{
7875 _nextAegisCheck = -1.0f;
7876}
double _nextAegisCheck
Definition ShipEntity.h:490

◆ forwardVector

- (Vector) forwardVector

Definition at line 14954 of file ShipEntity.m.

1272{
1273 return v_forward;
1274}

◆ forwardWeaponOffset

- (NSArray *) forwardWeaponOffset

◆ foundTarget

- (Entity *) foundTarget

Definition at line 9593 of file ShipEntity.m.

9919{
9920 Entity *result = [_foundTarget weakRefUnderlyingObject];
9921 if (result == nil || ![self isValidTarget:result])
9922 {
9924 return nil;
9925 }
9926 return result;
9927}
OOWeakReference * _foundTarget
Definition ShipEntity.h:440

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ frustration

- (double) frustration

◆ frustumRadius

- (GLfloat) frustumRadius

Reimplemented from Entity.

Definition at line 14954 of file ShipEntity.m.

891{
892 OOScalar exhaust_length = 0;
893 NSEnumerator *exEnum = nil;
894 OOExhaustPlumeEntity *exEnt = nil;
895 for (exEnum = [self exhaustEnumerator]; (exEnt = [exEnum nextObject]); )
896 {
897 if ([exEnt findCollisionRadius] > exhaust_length)
898 {
899 exhaust_length = [exEnt findCollisionRadius];
900 }
901 }
902 return _profileRadius + exhaust_length;
903}
GLfloat OOScalar
Definition OOMaths.h:64
NSEnumerator * exhaustEnumerator()

◆ fuel

- (OOFuelQuantity) fuel

◆ fuelCapacity

- (OOFuelQuantity) fuelCapacity

Definition at line 7619 of file ShipEntity.m.

8119{
8120 // FIXME: shipdata.plist can allow greater fuel quantities (without extending hyperspace range). Need some consistency here.
8121 return PLAYER_MAX_FUEL;
8122}
#define PLAYER_MAX_FUEL

◆ fuelChargeRate

- (GLfloat) fuelChargeRate

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8126{
8127 GLfloat rate = 1.0; // Standard (& strict play) charge rate.
8128
8129#if MASS_DEPENDENT_FUEL_PRICES
8130
8131 if (EXPECT(PLAYER != nil && mass> 0 && mass != [PLAYER baseMass]))
8132 {
8133 rate = calcFuelChargeRate(mass);
8134 }
8135
8136 OOLog(@"fuelPrices", @"\"%@\" fuel charge rate: %.2f (mass ratio: %.2f/%.2f)", [self shipDataKey], rate, mass, [PLAYER baseMass]);
8137#endif
8138
8139 return rate;
8140}

◆ generateMissileEquipmentTypeFrom:

- (OOEquipmentType *) generateMissileEquipmentTypeFrom: (NSString *) role
implementation

Provided by category ShipEntity(Private).

Definition at line 2093 of file ShipEntity.m.

3328 :(NSString *)role
3329{
3330 /* The generated missile equipment type provides for backward compatibility with pre-1.74 OXPs missile_roles
3331 and follows this template:
3332
3333 //NPC equipment, incompatible with player ship. Not buyable because of its TL.
3334 (
3335 100, 100000, "Missile",
3336 "EQ_X_MISSILE",
3337 "Unidentified missile type.",
3338 {
3339 is_external_store = true;
3340 }
3341 )
3342 */
3343 NSArray *itemInfo = [NSArray arrayWithObjects:@"100", @"100000", @"Missile", role, @"Unidentified missile type.",
3344 [NSDictionary dictionaryWithObjectsAndKeys: @"true", @"is_external_store", nil], nil];
3345
3348}
void addEquipmentWithInfo:(NSArray *itemInfo)

◆ getAI

- (AI *) getAI

Definition at line 7619 of file ShipEntity.m.

8015{
8016 return shipAI;
8017}

Referenced by ShipExitAI(), ShipGetProperty(), and ShipSetProperty().

+ Here is the caller graph for this function:

◆ getDemoStartTime

- (OOTimeAbsolute) getDemoStartTime
implementation

Definition at line 14073 of file ShipEntity.m.

14626{
14627 return demoStartTime;
14628}
OOTimeAbsolute demoStartTime
Definition ShipEntity.h:495

◆ getDestroyedBy:damageType:

- (void) getDestroyedBy: (Entity *) whom
damageType: (OOShipDamageType) type 

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

9035 :(Entity *)whom damageType:(OOShipDamageType)type
9036{
9037 [self noteKilledBy:whom damageType:type];
9038 [self abortDocking];
9039 [self becomeExplosion];
9040}
OOShipDamageType
Definition ShipEntity.h:183

◆ getJSClass:andPrototype:

- (void) getJSClass: (JSClass **) outClass
andPrototype: (JSObject **) outPrototype 
implementation

Reimplemented from Entity.

Reimplemented in DockEntity, and StationEntity.

Provided by category ShipEntity(OOJavaScriptExtensions).

Definition at line 1 of file EntityOOJavaScriptExtensions.m.

121 :(JSClass **)outClass andPrototype:(JSObject **)outPrototype
122{
123 *outClass = JSShipClass();
124 *outPrototype = JSShipPrototype();
125}
JSObject * JSShipPrototype(void)
Definition OOJSShip.m:601
JSClass * JSShipClass(void)
Definition OOJSShip.m:595

◆ getTractoredBy:

- (void) getTractoredBy: (ShipEntity *) other

Definition at line 9593 of file ShipEntity.m.

12881 :(ShipEntity *)other
12882{
12883 if([self status] == STATUS_BEING_SCOOPED) return; // both cargo and ship call this. Act only once.
12884 desired_speed = 0.0;
12885 [self setAITo:@"nullAI.plist"]; // prevent AI from changing status or behaviour.
12886 behaviour = BEHAVIOUR_TRACTORED;
12887 [self setStatus:STATUS_BEING_SCOOPED];
12888 [self addTarget:other];
12889 [self setOwner:other];
12890 // should we make this an all rather than first 16? - CIM
12891 // made it ignore other cargopods and similar at least. - CIM 28/7/2013
12892 [self checkScannerIgnoringUnpowered];
12893 unsigned i;
12894 ShipEntity *scooper;
12895 for (i = 0; i < n_scanned_ships ; i++)
12896 {
12897 scooper = (ShipEntity *)scanned_ships[i];
12898 // 'Dibs!' - Stops other ships from trying to scoop/shoot this cargo.
12899 if (other != scooper && (id) self == [scooper primaryTarget])
12900 {
12901 [scooper noteLostTarget];
12902 }
12903 }
12904}
void noteLostTarget()

◆ getWeaponOffsetFrom:withKey:inMode:

- (NSArray *) getWeaponOffsetFrom: (NSDictionary *) dict
withKey: (NSString *) key
inMode: (NSString *) mode 

Definition at line 14954 of file ShipEntity.m.

2001 :(NSDictionary *)dict withKey:(NSString *)key inMode:(NSString *)mode
2002{
2003 Vector offset;
2004 if ([mode isEqualToString:@"single"])
2005 {
2006 offset = vector_multiply_scalar([dict oo_vectorForKey:key defaultValue:kZeroVector],_scaleFactor);
2007 return [NSArray arrayWithObject:MAKE_VECTOR_ARRAY(offset)];
2008 }
2009 else
2010 {
2011 NSArray *offsets = [dict oo_arrayForKey:key defaultValue:nil];
2012 if (offsets == nil) {
2014 return [NSArray arrayWithObject:MAKE_VECTOR_ARRAY(offset)];
2015 }
2016 NSMutableArray *output = [NSMutableArray arrayWithCapacity:[offsets count]];
2017 NSUInteger i;
2018 for (i=0;i<[offsets count];i++) {
2019 offset = vector_multiply_scalar([offsets oo_vectorAtIndex:i defaultValue:kZeroVector],_scaleFactor);
2020 [output addObject:MAKE_VECTOR_ARRAY(offset)];
2021 }
2022 return [NSArray arrayWithArray:output];
2023 }
2024}
GLfloat _scaleFactor
Definition ShipEntity.h:388
const char int mode
Definition ioapi.h:133

◆ getWitchspaceEntryCoordinates

- (void) getWitchspaceEntryCoordinates
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ group

- (OOShipGroup *) group

Definition at line 6496 of file ShipEntity.m.

6909{
6910 return _group;
6911}

Referenced by ShipGetProperty(), and ShipGroupAddShip().

+ Here is the caller graph for this function:

◆ groupAttackTarget

- (void) groupAttackTarget

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

340{
341 NSEnumerator *shipEnum = nil;
342 ShipEntity *target = nil, *ship = nil;
343
344 target = [self primaryTarget];
345
346 if (target == nil) return;
347
348 if ([self group] == nil) // ship is alone!
349 {
350 [self setFoundTarget:target];
351 [shipAI reactToMessage:@"GROUP_ATTACK_TARGET" context:@"groupAttackTarget"];
352 [self doScriptEvent:OOJSID("helpRequestReceived") withArgument:self andArgument:target];
353 return;
354 }
355
356 for (shipEnum = [[self group] mutationSafeEnumerator]; (ship = [shipEnum nextObject]); )
357 {
358 [ship setFoundTarget:target];
359 [ship reactToAIMessage:@"GROUP_ATTACK_TARGET" context:@"groupAttackTarget"];
360 [ship doScriptEvent:OOJSID("helpRequestReceived") withArgument:self andArgument:target];
361
362 if ([ship escortGroup] != [ship group] && [[ship escortGroup] count] > 1) // Ship has a seperate escort group.
363 {
364 ShipEntity *escort = nil;
365 NSEnumerator *shipEnum = nil;
366 NSArray *escortMembers = [[ship escortGroup] memberArrayExcludingLeader];
367 for (shipEnum = [escortMembers objectEnumerator]; (escort = [shipEnum nextObject]); )
368 {
369 [escort setFoundTarget:target];
370 [escort reactToAIMessage:@"GROUP_ATTACK_TARGET" context:@"groupAttackTarget"];
371 [escort doScriptEvent:OOJSID("helpRequestReceived") withArgument:self andArgument:target];
372 }
373 }
374 }
375}

◆ hasAllEquipment:

- (BOOL) hasAllEquipment: (id) equipmentKeys

Definition at line 2093 of file ShipEntity.m.

3201 :(id)equipmentKeys
3202{
3203 return [self hasAllEquipment:equipmentKeys includeWeapons:NO whileLoading:NO];
3204}

◆ hasAllEquipment:includeWeapons:whileLoading:

- (BOOL) hasAllEquipment: (id) equipmentKeys
includeWeapons: (BOOL) includeWeapons
whileLoading: (BOOL) loading 

Definition at line 2093 of file ShipEntity.m.

3181 :(id)equipmentKeys includeWeapons:(BOOL)includeWeapons whileLoading:(BOOL)loading
3182{
3183 NSEnumerator *keyEnum = nil;
3184 id key = nil;
3185
3186 if (_equipment == nil) return NO;
3187
3188 // Make sure it's an array or set, using a single-object set if it's a string.
3189 if ([equipmentKeys isKindOfClass:[NSString class]]) equipmentKeys = [NSArray arrayWithObject:equipmentKeys];
3190 else if (![equipmentKeys isKindOfClass:[NSArray class]] && ![equipmentKeys isKindOfClass:[NSSet class]]) return NO;
3191
3192 for (keyEnum = [equipmentKeys objectEnumerator]; (key = [keyEnum nextObject]); )
3193 {
3194 if (![self hasOneEquipmentItem:key includeWeapons:includeWeapons whileLoading:loading]) return NO;
3195 }
3196
3197 return YES;
3198}

◆ hasAutoAI

- (BOOL) hasAutoAI

Definition at line 7619 of file ShipEntity.m.

8021{
8022 return [[self shipInfoDictionary] oo_fuzzyBooleanForKey:@"auto_ai" defaultValue:YES];
8023}

◆ hasAutoCloak

- (BOOL) hasAutoCloak

Definition at line 6496 of file ShipEntity.m.

6690{
6691 return cloakAutomatic;
6692}

◆ hasAutoWeapons

- (BOOL) hasAutoWeapons

Definition at line 7619 of file ShipEntity.m.

8033{
8034 return [[self shipInfoDictionary] oo_fuzzyBooleanForKey:@"auto_weapons" defaultValue:NO];
8035}

◆ hasCargoScoop

- (BOOL) hasCargoScoop

Definition at line 2093 of file ShipEntity.m.

3962{
3963 return [self hasEquipmentItemProviding:@"EQ_CARGO_SCOOPS"];
3964}

◆ hasCascadeMine

- (BOOL) hasCascadeMine

Definition at line 2093 of file ShipEntity.m.

4034{
4035 /* TODO: this could be providing since theoretically OXP
4036 * deployable mines could also do cascade effects, but there are
4037 * probably better ways to manage OXP pylon AI */
4038 return [self hasEquipmentItem:@"EQ_QC_MINE" includeWeapons:YES whileLoading:NO];
4039}

◆ hasCloakingDevice

- (BOOL) hasCloakingDevice

Definition at line 2093 of file ShipEntity.m.

3974{
3975 /* TODO: Checks above stop this being 'providing'. */
3976 return [self hasEquipmentItem:@"EQ_CLOAKING_DEVICE"];
3977}

◆ hasDockingComputer

- (BOOL) hasDockingComputer

Definition at line 2093 of file ShipEntity.m.

4049{
4050 return [self hasEquipmentItemProviding:@"EQ_DOCK_COMP"];
4051}

◆ hasECM

- (BOOL) hasECM

Definition at line 2093 of file ShipEntity.m.

3968{
3969 return [self hasEquipmentItemProviding:@"EQ_ECM"];
3970}

◆ hasEquipmentItem:

- (BOOL) hasEquipmentItem: (id) equipmentKeys

Definition at line 2093 of file ShipEntity.m.

3129 :(id)equipmentKeys
3130{
3131 return [self hasEquipmentItem:equipmentKeys includeWeapons:NO whileLoading:NO];
3132}

Referenced by ShipAwardEquipment(), and ShipSetEquipmentStatus().

+ Here is the caller graph for this function:

◆ hasEquipmentItem:includeWeapons:whileLoading:

- (BOOL) hasEquipmentItem: (id) equipmentKeys
includeWeapons: (BOOL) includeWeapons
whileLoading: (BOOL) loading 

Definition at line 2093 of file ShipEntity.m.

3107 :(id)equipmentKeys includeWeapons:(BOOL)includeWeapons whileLoading:(BOOL)loading
3108{
3109 // this method is also used internally to find out if an equipped item is undamaged.
3110 if ([equipmentKeys isKindOfClass:[NSString class]])
3111 {
3112 return [self hasOneEquipmentItem:equipmentKeys includeWeapons:includeWeapons whileLoading:loading];
3113 }
3114 else
3115 {
3116 NSParameterAssert([equipmentKeys isKindOfClass:[NSArray class]] || [equipmentKeys isKindOfClass:[NSSet class]]);
3117
3118 id key = nil;
3119 foreach (key, equipmentKeys)
3120 {
3121 if ([self hasOneEquipmentItem:key includeWeapons:includeWeapons whileLoading:loading]) return YES;
3122 }
3123 }
3124
3125 return NO;
3126}

◆ hasEquipmentItemProviding:

- (BOOL) hasEquipmentItemProviding: (NSString *) equipmentType

Definition at line 2093 of file ShipEntity.m.

3137 :(NSString *)equipmentType
3138{
3139 NSString *key = nil;
3140 foreach (key, _equipment) {
3141 if ([key isEqualToString:equipmentType])
3142 {
3143 // equipment always provides itself
3144 return YES;
3145 }
3146 else
3147 {
3149 if (et != nil && [et provides:equipmentType])
3150 {
3151 return YES;
3152 }
3153 }
3154 }
3155 return NO;
3156}

Referenced by ProxyPlayerEntity::alertCondition.

+ Here is the caller graph for this function:

◆ hasEscapePod

- (BOOL) hasEscapePod

Definition at line 2093 of file ShipEntity.m.

4043{
4044 return [self hasEquipmentItemProviding:@"EQ_ESCAPE_POD"];
4045}

◆ hasEscorts

- (BOOL) hasEscorts

Definition at line 6496 of file ShipEntity.m.

6977{
6978 if (_escortGroup == nil) return NO;
6979 return [_escortGroup count] > 1; // If only one member, it's self.
6980}

◆ hasExpandedCargoBay

- (BOOL) hasExpandedCargoBay

Definition at line 2093 of file ShipEntity.m.

4001{
4002 /* Not 'providing' - controlled through scripts */
4003 return [self hasEquipmentItem:@"EQ_CARGO_BAY"];
4004}

◆ hasFuelInjection

- (BOOL) hasFuelInjection

Definition at line 2093 of file ShipEntity.m.

4028{
4029 return [self hasEquipmentItemProviding:@"EQ_FUEL_INJECTION"];
4030}

◆ hasFuelScoop

- (BOOL) hasFuelScoop

Definition at line 2093 of file ShipEntity.m.

3955{
3956 return [self hasEquipmentItemProviding:@"EQ_FUEL_SCOOPS"];
3957}

◆ hasGalacticHyperdrive

- (BOOL) hasGalacticHyperdrive

Definition at line 2093 of file ShipEntity.m.

4055{
4056 return [self hasEquipmentItemProviding:@"EQ_GAL_DRIVE"];
4057}

◆ hasHeatShield

- (BOOL) hasHeatShield

Definition at line 2093 of file ShipEntity.m.

4022{
4023 return [self hasEquipmentItemProviding:@"EQ_HEAT_SHIELD"];
4024}

◆ hasHostileTarget

- (BOOL) hasHostileTarget

Reimplemented in PlayerEntity, and StationEntity.

Definition at line 7411 of file ShipEntity.m.

7446{
7447 Entity *t = [self primaryTarget];
7448 if (t == nil || ![t isShip])
7449 {
7450 return NO;
7451 }
7452 if ([self isMissile])
7453 {
7454 return YES; // missiles are always fired against a hostile target
7455 }
7456 if ((behaviour == BEHAVIOUR_AVOID_COLLISION)&&(previousCondition))
7457 {
7458 int old_behaviour = [previousCondition oo_intForKey:@"behaviour"];
7459 return IsBehaviourHostile(old_behaviour);
7460 }
7462}
static BOOL IsBehaviourHostile(OOBehaviour behaviour)

Referenced by HeadUpDisplay::hudDrawReticleOnTarget.

+ Here is the caller graph for this function:

◆ hasHyperspaceMotor

- (BOOL) hasHyperspaceMotor

Definition at line 2093 of file ShipEntity.m.

3208{
3209 return hyperspaceMotorSpinTime >= 0;
3210}
float hyperspaceMotorSpinTime
Definition ShipEntity.h:247

◆ hasMilitaryJammer

- (BOOL) hasMilitaryJammer

Definition at line 2093 of file ShipEntity.m.

3991{
3992#if USEMASC
3993 return [self hasEquipmentItemProviding:@"EQ_MILITARY_JAMMER"];
3994#else
3995 return NO;
3996#endif
3997}

◆ hasMilitaryScannerFilter

- (BOOL) hasMilitaryScannerFilter

Definition at line 2093 of file ShipEntity.m.

3981{
3982#if USEMASC
3983 return [self hasEquipmentItemProviding:@"EQ_MILITARY_SCANNER_FILTER"];
3984#else
3985 return NO;
3986#endif
3987}

◆ hasMilitaryShieldEnhancer

- (BOOL) hasMilitaryShieldEnhancer

Definition at line 2093 of file ShipEntity.m.

4015{
4016 /* Not 'providing' - controlled through scripts */
4017 return [self hasEquipmentItem:@"EQ_NAVAL_SHIELD_BOOSTER"];
4018}

◆ hasNewAI

- (BOOL) hasNewAI

Definition at line 7619 of file ShipEntity.m.

8027{
8028 return [[[self getAI] name] isEqualToString:@"nullAI.plist"];
8029}

◆ hasOneEquipmentItem:includeMissiles:whileLoading:

- (BOOL) hasOneEquipmentItem: (NSString *) itemKey
includeMissiles: (BOOL) includeMissiles
whileLoading: (BOOL) loading 

Definition at line 2093 of file ShipEntity.m.

3046 :(NSString *)itemKey includeMissiles:(BOOL)includeMissiles whileLoading:(BOOL)loading
3047{
3048 if ([_equipment containsObject:itemKey]) return YES;
3049
3050 if (loading)
3051 {
3052 NSString *damaged = [itemKey stringByAppendingString:@"_DAMAGED"];
3053 if ([_equipment containsObject:damaged]) return YES;
3054 }
3055
3056 if (includeMissiles && missiles > 0)
3057 {
3058 unsigned i;
3059 if ([itemKey isEqualToString:@"thargon"]) itemKey = @"EQ_THARGON";
3060 for (i = 0; i < missiles; i++)
3061 {
3062 if (missile_list[i] != nil && [[missile_list[i] identifier] isEqualTo:itemKey]) return YES;
3063 }
3064 }
3065
3066 return NO;
3067}

Referenced by ShipRemoveEquipment().

+ Here is the caller graph for this function:

◆ hasOneEquipmentItem:includeWeapons:whileLoading:

- (BOOL) hasOneEquipmentItem: (NSString *) itemKey
includeWeapons: (BOOL) includeMissiles
whileLoading: (BOOL) loading 

Definition at line 2093 of file ShipEntity.m.

3022 :(NSString *)itemKey includeWeapons:(BOOL)includeWeapons whileLoading:(BOOL)loading
3023{
3024 if ([self hasOneEquipmentItem:itemKey includeMissiles:includeWeapons whileLoading:loading]) return YES;
3025
3026 if (loading)
3027 {
3028 NSString *damaged = [itemKey stringByAppendingString:@"_DAMAGED"];
3029 if ([_equipment containsObject:damaged]) return YES;
3030 }
3031
3032 if (includeWeapons)
3033 {
3034 // Check for primary weapon
3036 if (!isWeaponNone(weaponType))
3037 {
3038 if ([self hasPrimaryWeapon:weaponType]) return YES;
3039 }
3040 }
3041
3042 return NO;
3043}
OOWeaponType OOWeaponTypeFromEquipmentIdentifierStrict(NSString *string) PURE_FUNC

◆ hasPrimaryRole:

- (BOOL) hasPrimaryRole: (NSString *) role

Definition at line 6496 of file ShipEntity.m.

7327 :(NSString *)role
7328{
7329 return [[self primaryRole] isEqual:role];
7330}

◆ hasPrimaryWeapon:

- (BOOL) hasPrimaryWeapon: (OOWeaponType) weaponType

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3070 :(OOWeaponType)weaponType
3071{
3072 NSEnumerator *subEntEnum = nil;
3073 ShipEntity *subEntity = nil;
3074
3075 if ([[forward_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
3076 [[aft_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
3077 [[port_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
3078 [[starboard_weapon_type identifier] isEqualToString:[weaponType identifier]])
3079 {
3080 return YES;
3081 }
3082
3083 for (subEntEnum = [self shipSubEntityEnumerator]; (subEntity = [subEntEnum nextObject]); )
3084 {
3085 if ([subEntity hasPrimaryWeapon:weaponType]) return YES;
3086 }
3087
3088 return NO;
3089}

◆ hasProximityAlertIgnoringTarget:

- (BOOL) hasProximityAlertIgnoringTarget: (BOOL) ignore_target

Definition at line 9593 of file ShipEntity.m.

11273 :(BOOL)ignore_target
11274{
11275 if (([self proximityAlert] != nil)&&(!ignore_target || ([self proximityAlert] != [self primaryTarget])))
11276 {
11277 return YES;
11278 }
11279 return NO;
11280}

◆ hasRole:

- (BOOL) hasRole: (NSString *) role

Definition at line 6496 of file ShipEntity.m.

7253 :(NSString *)role
7254{
7255 return [roleSet hasRole:role] || [role isEqual:primaryRole] || [role isEqual:[self shipDataKeyAutoRole]];
7256}

◆ hasScoop

- (BOOL) hasScoop

Definition at line 2093 of file ShipEntity.m.

3949{
3950 return [self hasEquipmentItemProviding:@"EQ_FUEL_SCOOPS"] || [self hasEquipmentItemProviding:@"EQ_CARGO_SCOOPS"];
3951}

Referenced by ProxyPlayerEntity::alertCondition.

+ Here is the caller graph for this function:

◆ hasShieldBooster

- (BOOL) hasShieldBooster

Definition at line 2093 of file ShipEntity.m.

4008{
4009 /* Not 'providing' - controlled through scripts */
4010 return [self hasEquipmentItem:@"EQ_SHIELD_BOOSTER"];
4011}

◆ hasSubEntity:

- (BOOL) hasSubEntity: (Entity<OOSubEntity> *) sub

Definition at line 14954 of file ShipEntity.m.

1325 :(Entity<OOSubEntity> *)sub
1326{
1327 return [subEntities containsObject:sub];
1328}

◆ heatInsulation

- (GLfloat) heatInsulation

Definition at line 7619 of file ShipEntity.m.

8822{
8823 return _heatInsulation;
8824}
float _heatInsulation
Definition ShipEntity.h:462

◆ homeSystem

- (OOSystemID) homeSystem

Definition at line 7619 of file ShipEntity.m.

7906{
7907 return home_system;
7908}
OOSystemID home_system
Definition ShipEntity.h:379

◆ hullHeatLevel

- (GLfloat) hullHeatLevel

Definition at line 9593 of file ShipEntity.m.

9760{
9761 GLfloat result = (GLfloat)ship_temperature / (GLfloat)SHIP_MAX_CABIN_TEMP;
9762 return OOClamp_0_1_f(result);
9763}
#define SHIP_MAX_CABIN_TEMP
Definition ShipEntity.h:67

◆ hyperspaceSpinTime

- (float) hyperspaceSpinTime

Definition at line 2093 of file ShipEntity.m.

3214{
3216}

◆ identFromShip:

- (NSString *) identFromShip: (ShipEntity*) otherShip

Definition at line 6496 of file ShipEntity.m.

7243 :(ShipEntity*) otherShip
7244{
7245 if ([self isJammingScanning] && ![otherShip hasMilitaryScannerFilter])
7246 {
7247 return DESC(@"unknown-target");
7248 }
7249 return [self displayName];
7250}
#define DESC(key)
Definition Universe.h:839

◆ increase_flight_pitch:

- (void) increase_flight_pitch: (double) delta

Definition at line 7619 of file ShipEntity.m.

8665 :(double) delta
8666{
8667 flightPitch += delta;
8670 else if (flightPitch < -max_flight_pitch)
8672}

◆ increase_flight_roll:

- (void) increase_flight_roll: (double) delta

Definition at line 7619 of file ShipEntity.m.

8645 :(double) delta
8646{
8647 flightRoll += delta;
8650 else if (flightRoll < -max_flight_roll)
8652}

◆ increase_flight_speed:

- (void) increase_flight_speed: (double) delta

Definition at line 7619 of file ShipEntity.m.

8614 :(double) delta
8615{
8616 double factor = 1.0;
8617 if (desired_speed > maxFlightSpeed && [self hasFuelInjection] && fuel > MIN_FUEL) factor = [self afterburnerFactor];
8618
8619 if (flightSpeed < maxFlightSpeed * factor)
8620 flightSpeed += delta * factor;
8621 else
8622 flightSpeed = maxFlightSpeed * factor;
8623}
BOOL hasFuelInjection()

◆ increase_flight_yaw:

- (void) increase_flight_yaw: (double) delta

Definition at line 7619 of file ShipEntity.m.

8685 :(double) delta
8686{
8687 flightYaw += delta;
8690 else if (flightYaw < -max_flight_yaw)
8692}

◆ init

- (id) init
implementation

Reimplemented from Entity.

Reimplemented in PlayerEntity.

Definition at line 14954 of file ShipEntity.m.

176{
177 /* -init used to set up a bunch of defaults that were different from
178 those in -reinit and -setUpShipFromDictionary:. However, it seems that
179 no ships are ever used which are not -setUpShipFromDictionary: (which
180 is as it should be), so these different defaults were meaningless.
181 */
182 return [self initWithKey:@"" definition:nil];
183}

◆ initBypassForPlayer

- (id) initBypassForPlayer
implementation

Provided by category ShipEntity(Hax).

Definition at line 14954 of file ShipEntity.m.

187{
188 return [super init];
189}

◆ initWithKey:definition:

- (id) initWithKey: (NSString *) key
definition: (NSDictionary *) dict 

Reimplemented in DockEntity, ProxyPlayerEntity, and StationEntity.

Definition at line 14954 of file ShipEntity.m.

193 :(NSString *)key definition:(NSDictionary *)dict
194{
196
197 NSParameterAssert(dict != nil);
198
199 self = [super init];
200 if (self == nil) return nil;
201
202 _shipKey = [key retain];
203
204 isShip = YES;
206 [self setStatus:STATUS_IN_FLIGHT];
207
212 weapon_temp = 0.0f;
214 forward_weapon_temp = 0.0f;
215 aft_weapon_temp = 0.0f;
216 port_weapon_temp = 0.0f;
218
219 _nextAegisCheck = -0.1f;
221
222 if (![self setUpShipFromDictionary:dict])
223 {
224 [self release];
225 self = nil;
226 }
227
228 // Problem observed in testing -- Ahruman
229 if (self != nil && !isfinite(maxFlightSpeed))
230 {
231 OOLog(@"ship.sanityCheck.failed", @"Ship %@ %@ infinite top speed, clamped to 300.", self, @"generated with");
232 maxFlightSpeed = 300;
233 }
234 return self;
235
237}
#define OOJS_PROFILE_EXIT
#define OOJS_PROFILE_ENTER
#define INITIAL_SHOT_TIME
Definition ShipEntity.h:100
#define SHIP_MIN_CABIN_TEMP
Definition ShipEntity.h:68
GLfloat zero_distance
Definition Entity.h:108
OOTimeDelta shot_time
Definition ShipEntity.h:197

Referenced by ProxyPlayerEntity::alertCondition.

+ Here is the caller graph for this function:

◆ inspBecomeTarget

- (void) inspBecomeTarget
implementation

Provided by category ShipEntity(OOEntityInspectorExtensions).

Definition at line 1 of file OOEntityInspectorExtensions.m.

203{
205}
void addTarget:(Entity *targetEntity)
PlayerEntity * sharedPlayer()

◆ inspCanBecomeTarget

- (BOOL) inspCanBecomeTarget
implementation

Reimplemented in PlayerEntity.

Provided by category ShipEntity(OOEntityInspectorExtensions).

Definition at line 1 of file OOEntityInspectorExtensions.m.

197{
198 return ![self isSubEntity];
199}

◆ inspDescription

- (NSString *) inspDescription
implementation

Reimplemented from Entity.

Reimplemented in PlayerEntity.

Provided by category ShipEntity(OOEntityInspectorExtensions).

Definition at line 1 of file OOEntityInspectorExtensions.m.

185{
186 return [NSString stringWithFormat:@"%@ ID %u", [self displayName], [self universalID]];
187}

◆ inspHasSecondaryIdentityLine

- (BOOL) inspHasSecondaryIdentityLine
implementation

Provided by category ShipEntity(OOEntityInspectorExtensions).

Definition at line 1 of file OOEntityInspectorExtensions.m.

173{
174 return YES;
175}

◆ inspSecondaryIdentityLine

- (NSString *) inspSecondaryIdentityLine
implementation

Reimplemented in PlayerEntity.

Provided by category ShipEntity(OOEntityInspectorExtensions).

Definition at line 1 of file OOEntityInspectorExtensions.m.

179{
180 return [self displayName];
181}

◆ inspTargetLine

- (NSString *) inspTargetLine
implementation

Reimplemented from Entity.

Provided by category ShipEntity(OOEntityInspectorExtensions).

Definition at line 1 of file OOEntityInspectorExtensions.m.

191{
192 return [[self primaryTarget] inspDescription];
193}

◆ interpretAIMessage:

- (void) interpretAIMessage: (NSString *) message

Reimplemented in PlayerEntity.

Definition at line 14073 of file ShipEntity.m.

14283 :(NSString *)ms
14284{
14285 if ([ms hasPrefix:AIMS_AGGRESSOR_SWITCHED_TARGET])
14286 {
14287 // if I'm under attack send a thank-you message to the rescuer
14288 //
14289 NSArray* tokens = ScanTokensFromString(ms);
14290 int switcher_id = [(NSString*)[tokens objectAtIndex:1] intValue]; // Attacker that switched targets.
14291 Entity* switcher = [UNIVERSE entityForUniversalID:switcher_id];
14292 int rescuer_id = [(NSString*)[tokens objectAtIndex:2] intValue]; // New primary target of attacker.
14293 Entity* rescuer = [UNIVERSE entityForUniversalID:rescuer_id];
14294 if ((switcher == [self primaryAggressor])&&(switcher == [self primaryTarget])&&(switcher)&&(rescuer)&&(rescuer->isShip)&&([self thankedShip] != rescuer)&&(scanClass != CLASS_THARGOID))
14295 {
14296 ShipEntity* rescueShip = (ShipEntity*)rescuer;
14297// ShipEntity* switchingShip = (ShipEntity*)switcher;
14298 if (scanClass == CLASS_POLICE)
14299 {
14300 [self sendExpandedMessage:@"[police-thanks-for-assist]" toShip:rescueShip];
14301 [rescueShip setBounty:[rescueShip bounty] * 0.80 withReason:kOOLegalStatusReasonAssistingPolice]; // lower bounty by 20%
14302 }
14303 else
14304 {
14305 [self sendExpandedMessage:@"[thanks-for-assist]" toShip:rescueShip];
14306 }
14307 [self setThankedShip:rescuer];
14308 }
14309 }
14310}
NSMutableArray * ScanTokensFromString(NSString *values)
#define AIMS_AGGRESSOR_SWITCHED_TARGET
Definition ShipEntity.h:94
Entity * thankedShip()

◆ isBeacon

- (BOOL) isBeacon
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1596{
1597 return [self beaconCode] != nil;
1598}

◆ IsBehaviourHostile

+ (static BOOL) IsBehaviourHostile (OOBehaviour) behaviour
implementation

Definition at line 7411 of file ShipEntity.m.

7412{
7413 switch (behaviour)
7414 {
7415 case BEHAVIOUR_ATTACK_TARGET:
7416 case BEHAVIOUR_ATTACK_FLY_TO_TARGET:
7417 case BEHAVIOUR_ATTACK_FLY_FROM_TARGET:
7418 case BEHAVIOUR_RUNNING_DEFENSE:
7419 case BEHAVIOUR_FLEE_TARGET:
7420 case BEHAVIOUR_ATTACK_BREAK_OFF_TARGET:
7421 case BEHAVIOUR_ATTACK_SLOW_DOGFIGHT:
7422 case BEHAVIOUR_EVASIVE_ACTION:
7423 case BEHAVIOUR_FLEE_EVASIVE_ACTION:
7424 case BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX:
7425 // case BEHAVIOUR_ATTACK_MINING_TARGET:
7426 case BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE:
7427 case BEHAVIOUR_ATTACK_BROADSIDE:
7428 case BEHAVIOUR_ATTACK_BROADSIDE_LEFT:
7429 case BEHAVIOUR_ATTACK_BROADSIDE_RIGHT:
7430 case BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE:
7431 case BEHAVIOUR_CLOSE_WITH_TARGET:
7432 case BEHAVIOUR_ATTACK_SNIPER:
7433 case BEHAVIOUR_SCRIPTED_ATTACK_AI:
7434 return YES;
7435
7436 default:
7437 return NO;
7438 }
7439
7440 return 100 < behaviour && behaviour < 120;
7441}

◆ isBoulder

- (BOOL) isBoulder

Definition at line 14954 of file ShipEntity.m.

1667{
1668 return [roleSet hasRole:kBoulderRole];
1669}

◆ isCloaked

- (BOOL) isCloaked

Definition at line 6496 of file ShipEntity.m.

6671{
6673}

◆ isDefenseTarget:

- (BOOL) isDefenseTarget: (Entity *) target

Definition at line 9593 of file ShipEntity.m.

11218 :(Entity *)target
11219{
11220 return [_defenseTargets containsObject:target];
11221}

◆ isDemoShip

- (BOOL) isDemoShip

◆ isEscort

- (BOOL) isEscort

Definition at line 6496 of file ShipEntity.m.

7376{
7377 return [UNIVERSE role:[self primaryRole] isInCategory:@"oolite-escort"];
7378}

◆ isExplicitlyUnpiloted

- (BOOL) isExplicitlyUnpiloted

Definition at line 6496 of file ShipEntity.m.

7400{
7401 return _explicitlyUnpiloted;
7402}
unsigned _explicitlyUnpiloted
Definition ShipEntity.h:274

◆ isFrangible

- (BOOL) isFrangible

◆ isFriendlyTo:

- (BOOL) isFriendlyTo: (ShipEntity *) otherShip

Definition at line 9593 of file ShipEntity.m.

10157 :(ShipEntity *)otherShip
10158{
10159 BOOL isFriendly = NO;
10160 OOShipGroup *myGroup = [self group];
10161 OOShipGroup *otherGroup = [otherShip group];
10162
10163 if ((otherShip == self) ||
10164 ([self isPolice] && [otherShip isPolice]) ||
10165 ([self isThargoid] && [otherShip isThargoid]) ||
10166 (myGroup != nil && otherGroup != nil && (myGroup == otherGroup || [otherGroup leader] == self)) ||
10167 ([self scanClass] == CLASS_MILITARY && [otherShip scanClass] == CLASS_MILITARY))
10168 {
10169 isFriendly = YES;
10170 }
10171
10172 return isFriendly;
10173}

◆ isHostileTo:

- (BOOL) isHostileTo: (Entity *) entity

Definition at line 7411 of file ShipEntity.m.

7465 :(Entity *)entity
7466{
7467 return ([self hasHostileTarget] && [self primaryTarget] == entity);
7468}

◆ isHulk

- (BOOL) isHulk

◆ isJammingScanning

- (BOOL) isJammingScanning
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 6496 of file ShipEntity.m.

6702{
6703 return ([self hasMilitaryJammer] && military_jammer_active);
6704}
BOOL hasMilitaryJammer()

◆ isMinable

- (BOOL) isMinable

Definition at line 14954 of file ShipEntity.m.

1673{
1674 if ([self hasRole:@"asteroid"] || [self isBoulder])
1675 {
1676 if (!noRocks)
1677 {
1678 return YES;
1679 }
1680 }
1681 return NO;
1682}

◆ isMine

- (BOOL) isMine

Definition at line 6496 of file ShipEntity.m.

7364{
7365 return [[self primaryRole] hasSuffix:@"MINE"];
7366}

◆ isMining

- (BOOL) isMining

Reimplemented in PlayerEntity.

Definition at line 14073 of file ShipEntity.m.

14278{
14279 return ((behaviour == BEHAVIOUR_ATTACK_MINING_TARGET)&&([forward_weapon_type isMiningLaser]));
14280}

◆ isMissile

- (BOOL) isMissile

◆ isMissileFlagSet

- (BOOL) isMissileFlagSet

Definition at line 9593 of file ShipEntity.m.

12318{
12319 return isMissile; // were we created using fireMissile? (for tracking submunitions and preventing collisions at launch)
12320}

◆ isPirate

- (BOOL) isPirate

Definition at line 6496 of file ShipEntity.m.

7352{
7353 return [UNIVERSE role:[self primaryRole] isInCategory:@"oolite-pirate"];
7354}

◆ isPirateVictim

- (BOOL) isPirateVictim

Definition at line 6496 of file ShipEntity.m.

7394{
7395 return [UNIVERSE roleIsPirateVictim:[self primaryRole]];
7396}

◆ isPolice

- (BOOL) isPolice

Definition at line 6496 of file ShipEntity.m.

7334{
7335 //bounty hunters have a police role, but are not police, so we must test by scan class, not by role
7336 return [self scanClass] == CLASS_POLICE;
7337}

◆ isShipWithSubEntityShip:

- (BOOL) isShipWithSubEntityShip: (Entity *) other
implementation

Reimplemented from Entity.

Provided by category ShipEntity(SubEntityRelationship).

Definition at line 14073 of file ShipEntity.m.

14874 :(Entity *)other
14875{
14876 assert ([self isShip]);
14877
14878 if (![other isShip]) return NO;
14879 if (![other isSubEntity]) return NO;
14880 if ([other owner] != self) return NO;
14881
14882#ifndef NDEBUG
14883 // Sanity check; this should always be true.
14884 if (![self hasSubEntity:(ShipEntity *)other])
14885 {
14886 OOLogERR(@"ship.subentity.sanityCheck.failed", @"%@ thinks it's a subentity of %@, but the supposed parent does not agree. %@", [other shortDescription], [self shortDescription], @"This is an internal error, please report it.");
14887 [other setOwner:nil];
14888 return NO;
14889 }
14890#endif
14891
14892 return YES;
14893}

◆ isShuttle

- (BOOL) isShuttle

Definition at line 6496 of file ShipEntity.m.

7382{
7383 return [UNIVERSE role:[self primaryRole] isInCategory:@"oolite-shuttle"];
7384}

◆ isTemplateCargoPod

- (BOOL) isTemplateCargoPod

Definition at line 14954 of file ShipEntity.m.

1018{
1019 return [[self primaryRole] isEqualToString:@"oolite-template-cargopod"];
1020}

◆ isThargoid

- (BOOL) isThargoid

Definition at line 6496 of file ShipEntity.m.

7340{
7341 return [self scanClass] == CLASS_THARGOID;
7342}

◆ isTrader

- (BOOL) isTrader

Definition at line 6496 of file ShipEntity.m.

7346{
7347 return [UNIVERSE role:[self primaryRole] isInCategory:@"oolite-trader"];
7348}

◆ isTurret

- (BOOL) isTurret

Definition at line 6496 of file ShipEntity.m.

7388{
7389 return behaviour == BEHAVIOUR_TRACK_AS_TURRET;
7390}

◆ isUnpiloted

- (BOOL) isUnpiloted

Reimplemented in StationEntity.

Definition at line 6496 of file ShipEntity.m.

7406{
7407 return [self isExplicitlyUnpiloted] || [self isHulk] || [self scanClass] == CLASS_ROCK || [self scanClass] == CLASS_CARGO;
7408}

◆ isValidTarget:

- (BOOL) isValidTarget: (Entity *) target

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

10034 :(Entity *)target
10035{
10036 if (target == nil)
10037 {
10038 return NO;
10039 }
10040 if ([target isShip])
10041 {
10042 OOEntityStatus tstatus = [target status];
10043 if (tstatus == STATUS_ENTERING_WITCHSPACE || tstatus == STATUS_IN_HOLD || tstatus == STATUS_DOCKED || tstatus == STATUS_DEAD)
10044 // 2013-01-13, Eric: added STATUS_DEAD because I keep seeing ships locked on dead ships in attack mode.
10045 {
10046 return NO;
10047 }
10048 return YES;
10049 }
10050 if ([target isWormhole] && [target scanClass] != CLASS_NO_DRAW)
10051 {
10052 return YES;
10053 }
10054 return NO;
10055}
OOEntityStatus
Definition Entity.h:60
unsigned isWormhole
Definition Entity.h:94

◆ isVisible

- (BOOL) isVisible
implementation

Reimplemented from Entity.

Definition at line 14954 of file ShipEntity.m.

1590{
1592}

◆ isVisibleToScripts

- (BOOL) isVisibleToScripts
implementation

Reimplemented from Entity.

Provided by category ShipEntity(OOJavaScriptExtensions).

Definition at line 1 of file EntityOOJavaScriptExtensions.m.

116{
117 return YES;
118}

◆ isWeapon

- (BOOL) isWeapon

Definition at line 6496 of file ShipEntity.m.

7370{
7371 return [self isMissile] || [self isMine];
7372}

◆ landOnPlanet

- (void) landOnPlanet
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1354{
1355 // Selects the nearest planet it can find.
1356 [self landOnPlanet:[self findNearestPlanet]];
1357}

◆ landOnPlanet:

- (void) landOnPlanet: (OOPlanetEntity *) planet

Definition at line 9593 of file ShipEntity.m.

14027 :(OOPlanetEntity *)planet
14028{
14029 if (planet && [self isShuttle])
14030 {
14031 [planet welcomeShuttle:self];
14032 }
14033 [self doScriptEvent:OOJSID("shipLandedOnPlanet") withArgument:planet andReactToAIMessage:@"LANDED_ON_PLANET"];
14034
14035#ifndef NDEBUG
14036 if ([self reportAIMessages])
14037 {
14038 OOLog(@"planet.collide.shuttleLanded", @"DEBUG: %@ landed on planet %@", self, planet);
14039 }
14040#endif
14041
14042 [UNIVERSE removeEntity:self];
14043}
BOOL isShuttle()

◆ laserColor

- (OOColor *) laserColor

Definition at line 9593 of file ShipEntity.m.

11718{
11719 return [[laser_color retain] autorelease];
11720}

◆ laserHeatLevel

- (GLfloat) laserHeatLevel

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

9711{
9712 GLfloat result = weapon_temp / NPC_MAX_WEAPON_TEMP;
9713 return OOClamp_0_1_f(result);
9714}

◆ laserHeatLevelAft

- (GLfloat) laserHeatLevelAft

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

9718{
9719 GLfloat result = aft_weapon_temp / NPC_MAX_WEAPON_TEMP;
9720 return OOClamp_0_1_f(result);
9721}

◆ laserHeatLevelForward

- (GLfloat) laserHeatLevelForward

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

9725{
9726 GLfloat result = forward_weapon_temp / NPC_MAX_WEAPON_TEMP;
9728 { // must check subents
9729 OOWeaponType forward_weapon_real_type = nil;
9730 NSEnumerator *subEnum = [self shipSubEntityEnumerator];
9731 ShipEntity *se = nil;
9732 while (isWeaponNone(forward_weapon_real_type) && (se = [subEnum nextObject]))
9733 {
9735 {
9736 forward_weapon_real_type = se->forward_weapon_type;
9738 }
9739 }
9740 }
9741 return OOClamp_0_1_f(result);
9742}

◆ laserHeatLevelPort

- (GLfloat) laserHeatLevelPort

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

9746{
9747 GLfloat result = port_weapon_temp / NPC_MAX_WEAPON_TEMP;
9748 return OOClamp_0_1_f(result);
9749}

◆ laserHeatLevelStarboard

- (GLfloat) laserHeatLevelStarboard

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

9753{
9754 GLfloat result = starboard_weapon_temp / NPC_MAX_WEAPON_TEMP;
9755 return OOClamp_0_1_f(result);
9756}

◆ laserPortOffset:

- (NSArray *) laserPortOffset: (OOWeaponFacing) direction

Definition at line 9593 of file ShipEntity.m.

11918 :(OOWeaponFacing)direction
11919{
11920 NSArray *laserPortOffset = nil;
11921 switch (direction)
11922 {
11924 case WEAPON_FACING_NONE:
11925 laserPortOffset = forwardWeaponOffset;
11926 break;
11927
11928 case WEAPON_FACING_AFT:
11929 laserPortOffset = aftWeaponOffset;
11930 break;
11931
11932 case WEAPON_FACING_PORT:
11933 laserPortOffset = portWeaponOffset;
11934 break;
11935
11937 laserPortOffset = starboardWeaponOffset;
11938 break;
11939 }
11940 return laserPortOffset;
11941}

◆ lastAegisLock

- (Entity< OOStellarBody > *) lastAegisLock
implementation

Provided by category ShipEntity(Private).

Definition at line 7619 of file ShipEntity.m.

7886{
7887 Entity<OOStellarBody> *stellar = [_lastAegisLock weakRefUnderlyingObject];
7888 if (stellar == nil)
7889 {
7890 [_lastAegisLock release];
7892 }
7893
7894 return stellar;
7895}

◆ lastEscortTarget

- (Entity *) lastEscortTarget

Definition at line 9593 of file ShipEntity.m.

9957{
9958 Entity *result = [_lastEscortTarget weakRefUnderlyingObject];
9959 if (result == nil || ![self isValidTarget:result])
9960 {
9962 return nil;
9963 }
9964 return result;
9965}
OOWeakReference * _lastEscortTarget
Definition ShipEntity.h:441

◆ launchCascadeMine

- (BOOL) launchCascadeMine

Definition at line 9593 of file ShipEntity.m.

12386{
12387 if (![self hasCascadeMine]) return NO;
12388 [self setSpeed: maxFlightSpeed + 300];
12389 ShipEntity* bomb = [UNIVERSE newShipWithRole:@"energy-bomb"];
12390 if (bomb == nil) return NO;
12391
12392 [self removeEquipmentItem:@"EQ_QC_MINE"];
12393
12394 double start = collision_radius + bomb->collision_radius;
12395 Quaternion random_direction;
12396 Vector vel;
12397 HPVector rpos;
12398 double random_roll = randf() - 0.5; // -0.5 to +0.5
12399 double random_pitch = randf() - 0.5; // -0.5 to +0.5
12400 quaternion_set_random(&random_direction);
12401
12402 rpos = HPvector_subtract([self position], vectorToHPVector(vector_multiply_scalar(v_forward, start)));
12403
12404 double eject_speed = -800.0;
12405 vel = vector_multiply_scalar(v_forward, [self flightSpeed] + eject_speed);
12406 eject_speed *= 0.5 * (randf() - 0.5); // -0.25x .. +0.25x
12407 vel = vector_add(vel, vector_multiply_scalar(v_up, eject_speed));
12408 eject_speed *= 0.5 * (randf() - 0.5); // -0.0625x .. +0.0625x
12409 vel = vector_add(vel, vector_multiply_scalar(v_right, eject_speed));
12410
12411 [bomb setPosition:rpos];
12412 [bomb setOrientation:random_direction];
12413 [bomb setRoll:random_roll];
12414 [bomb setPitch:random_pitch];
12415 [bomb setVelocity:vel];
12416 [bomb setScanClass:CLASS_MINE];
12417 [bomb setEnergy:5.0]; // 5 second countdown
12418 [bomb setBehaviour:BEHAVIOUR_ENERGY_BOMB_COUNTDOWN];
12419 [bomb setOwner:self];
12420 [UNIVERSE addEntity:bomb]; // STATUS_IN_FLIGHT, AI state GLOBAL
12421 [bomb release];
12422
12424 {
12425 [self deactivateCloakingDevice];
12426 }
12427
12428 if (self != PLAYER) // get the heck out of here
12429 {
12430 [self addTarget:bomb];
12431 [self setBehaviour:BEHAVIOUR_FLEE_TARGET];
12432 frustration = 0.0;
12433 }
12434 return YES;
12435}
void setBehaviour:(OOBehaviour cond)

◆ launchEscapeCapsule

- (ShipEntity *) launchEscapeCapsule

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12439{
12440 ShipEntity *result = nil;
12441 ShipEntity *mainPod = nil;
12442 unsigned n_pods, i;
12443 NSMutableArray *passengers = nil;
12444
12445 /*
12446 CHANGE: both player & NPCs can now launch escape pods in interstellar
12447 space. -- Kaks 20101113
12448 */
12449
12450 // check number of pods aboard -- require at least one.
12451 n_pods = [shipinfoDictionary oo_unsignedIntForKey:@"has_escape_pod"];
12452 if (n_pods > 65) n_pods = 65; // maximum of 64 passengers.
12453 if (n_pods > 1) passengers = [NSMutableArray arrayWithCapacity:n_pods-1];
12454
12455 if (crew) // transfer crew
12456 {
12457 // make sure crew inherit any legalStatus
12458 for (i = 0; i < [crew count]; i++)
12459 {
12460 OOCharacter *ch = (OOCharacter*)[crew objectAtIndex:i];
12461 [ch setLegalStatus: [self legalStatus] | [ch legalStatus]];
12462 }
12463 mainPod = [self launchPodWithCrew:crew];
12464 if (mainPod)
12465 {
12466 result = mainPod;
12467 [self setCrew:nil];
12468 [self setHulk:YES]; // we are without crew now.
12469 }
12470 }
12471
12472 // launch other pods (passengers)
12473 for (i = 1; i < n_pods; i++)
12474 {
12475 ShipEntity *passenger = nil;
12476 passenger = [self launchPodWithCrew:[NSArray arrayWithObject:[OOCharacter randomCharacterWithRole:@"passenger" andOriginalSystem:gen_rnd_number()]]];
12477 [passengers addObject:passenger];
12478 }
12479
12480 if (mainPod) [self doScriptEvent:OOJSID("shipLaunchedEscapePod") withArgument:mainPod andArgument:passengers];
12481
12482 return result;
12483}
#define OOJSID(str)
Definition OOJSPropID.h:38
void setLegalStatus:(int value)
OOCharacter * randomCharacterWithRole:andOriginalSystem:(NSString *c_role,[andOriginalSystem] OOSystemID s)

◆ launchPatrol

- (BOOL) launchPatrol
implementation

Reimplemented in StationEntity.

Provided by category ShipEntity(OOAIStationStubs).

Definition at line 1 of file ShipEntityAI.m.

2942{
2943 OOLog(@"ai.invalid.notAStation", @"Attempt to use station AI method \"%s\" on non-station %@.", "launchPatrol", self);
2944 return NO;
2945}

◆ launchPodWithCrew:

- (ShipEntity *) launchPodWithCrew: (NSArray *) podCrew
implementation

Provided by category ShipEntity(Private).

Definition at line 2093 of file ShipEntity.m.

2277 :(NSArray *)podCrew
2278{
2279 ShipEntity *pod = nil;
2280
2281 pod = [UNIVERSE newShipWithRole:[shipinfoDictionary oo_stringForKey:@"escape_pod_role"]]; // or nil
2282 if (!pod)
2283 {
2284 // _role not defined? it might have _model defined;
2285 pod = [UNIVERSE newShipWithRole:[shipinfoDictionary oo_stringForKey:@"escape_pod_model" defaultValue:@"escape-capsule"]];
2286 if (!pod)
2287 {
2288 pod = [UNIVERSE newShipWithRole:@"escape-capsule"];
2289 OOLog(@"shipEntity.noEscapePod", @"Ship %@ has no correct escape_pod_role defined. Now using default capsule.", self);
2290 }
2291 }
2292
2293 if (pod)
2294 {
2295 [pod setOwner:self];
2296 [pod setTemperature:[self randomEjectaTemperatureWithMaxFactor:0.9]];
2297 [pod setCommodity:@"slaves" andAmount:1];
2298 [pod setCrew:podCrew];
2299 [pod switchAITo:@"oolite-shuttleAI.js"];
2300 [self dumpItem:pod]; // CLASS_CARGO, STATUS_IN_FLIGHT, AI state GLOBAL
2301 [pod release]; //release
2302 }
2303
2304 return pod;
2305}
void setCrew:(NSArray *crewArray)
void switchAITo:(NSString *aiString)

◆ leaveDock:

- (void) leaveDock: (StationEntity *) station

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

13475 :(StationEntity *)station
13476{
13477 // This code is never used. Currently npc ships are only launched from the stations launch queue.
13478 if (station == nil) return;
13479
13480 [station launchShip:self];
13481
13482}
void launchShip:(ShipEntity *ship)

◆ leaveWitchspace

- (void) leaveWitchspace

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

13540{
13541 Quaternion q1;
13543 Vector v1 = vector_forward_from_quaternion(q1);
13544 double d1 = 0.0;
13545
13546 GLfloat min_d1 = [UNIVERSE safeWitchspaceExitDistance];
13547
13548 while (fabs(d1) < min_d1)
13549 {
13550 // not scannerRange - has no effect on witchspace exit
13551 d1 = SCANNER_MAX_RANGE * (randf() - randf());
13552 }
13553
13554 HPVector exitposition = [UNIVERSE getWitchspaceExitPosition];
13555 exitposition.x += v1.x * d1; // randomise exit position
13556 exitposition.y += v1.y * d1;
13557 exitposition.z += v1.z * d1;
13558 [self setPosition:exitposition];
13559 [self witchspaceLeavingEffects];
13560}

◆ legalStatus

- (int) legalStatus

Definition at line 7619 of file ShipEntity.m.

8313{
8314 if (scanClass == CLASS_THARGOID)
8315 return 5 * collision_radius;
8316 if (scanClass == CLASS_ROCK)
8317 return 0;
8318 return (int)[self bounty];
8319}

◆ lightsActive

- (BOOL) lightsActive

Definition at line 9593 of file ShipEntity.m.

13670{
13671 return _lightsActive;
13672}
unsigned _lightsActive
Definition ShipEntity.h:282

◆ lookingAtSunWithThresholdAngleCos:

- (GLfloat) lookingAtSunWithThresholdAngleCos: (GLfloat) thresholdAngleCos

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

11351 :(GLfloat) thresholdAngleCos
11352{
11353 OOSunEntity *sun = [UNIVERSE sun];
11354 GLfloat measuredCos = 999.0f, measuredCosAbs;
11355 GLfloat sunBrightness = 0.0f;
11356 Vector relativePosition, unitRelativePosition;
11357
11358 if (EXPECT_NOT(!sun)) return 0.0f;
11359
11360 relativePosition = HPVectorToVector(HPvector_subtract([self position], [sun position]));
11361 unitRelativePosition = vector_normal_or_zbasis(relativePosition);
11362 switch (currentWeaponFacing)
11363 {
11365 measuredCos = -dot_product(unitRelativePosition, v_forward);
11366 break;
11367 case WEAPON_FACING_AFT:
11368 measuredCos = +dot_product(unitRelativePosition, v_forward);
11369 break;
11370 case WEAPON_FACING_PORT:
11371 measuredCos = +dot_product(unitRelativePosition, v_right);
11372 break;
11374 measuredCos = -dot_product(unitRelativePosition, v_right);
11375 break;
11376 default:
11377 break;
11378 }
11379 measuredCosAbs = fabs(measuredCos);
11380 if (thresholdAngleCos <= measuredCosAbs && measuredCosAbs <= 1.0f) // angle from viewpoint to sun <= desired threshold
11381 {
11382 sunBrightness = (measuredCos - thresholdAngleCos) / (1.0f - thresholdAngleCos);
11383 if (sunBrightness < 0.0f) sunBrightness = 0.0f;
11384 }
11385 return sunBrightness * sunBrightness * sunBrightness;
11386}
Vector relativePosition()
Definition Entity.m:636

◆ manageCollisions

- (void) manageCollisions

Definition at line 9593 of file ShipEntity.m.

12643{
12644 // deal with collisions
12645 //
12646 Entity* ent;
12647 ShipEntity* other_ship;
12648
12649 while ([collidingEntities count] > 0)
12650 {
12651 // EMMSTRAN: investigate if doing this backwards would be more efficient. (Not entirely obvious, NSArray is kinda funky.) -- Ahruman 2011-02-12
12652 ent = [[[collidingEntities objectAtIndex:0] retain] autorelease];
12653 [collidingEntities removeObjectAtIndex:0];
12654 if (ent)
12655 {
12656 if ([ent isShip])
12657 {
12658 other_ship = (ShipEntity *)ent;
12659 [self collideWithShip:other_ship];
12660 }
12661 else if ([ent isStellarObject])
12662 {
12663 [self getDestroyedBy:ent damageType:[ent isSun] ? kOODamageTypeHitASun : kOODamageTypeHitAPlanet];
12664 if (self == PLAYER) [self retain];
12665 }
12666 else if ([ent isWormhole])
12667 {
12668 if( [self isPlayer] ) [self enterWormhole:(WormholeEntity*)ent];
12669 else [self enterWormhole:(WormholeEntity*)ent replacing:NO];
12670 }
12671 }
12672 }
12673}
BOOL isStellarObject()
Definition Entity.m:179

◆ markAsOffender:

- (void) markAsOffender: (int) offence_value

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

13591 :(int)offence_value
13592{
13593 [self markAsOffender:offence_value withReason:kOOLegalStatusReasonUnknown];
13594}

◆ markAsOffender:withReason:

- (void) markAsOffender: (int) offence_value
withReason: (OOLegalStatusReason) reason 

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

13597 :(int)offence_value withReason:(OOLegalStatusReason)reason
13598{
13599 if (![self isPolice] && ![self isCloaked] && self != [UNIVERSE station])
13600 {
13601 if ([self isSubEntity])
13602 {
13603 [[self parentEntity] markAsOffender:offence_value withReason:reason];
13604 }
13605 else
13606 {
13607 if ((scanClass == CLASS_THARGOID || scanClass == CLASS_STATION) && reason != kOOLegalStatusReasonSetup && reason != kOOLegalStatusReasonByScript)
13608 {
13609 return; // no non-scripted bounties for thargoids and stations
13610 }
13611
13612 JSContext *context = OOJSAcquireContext();
13613
13614 jsval amountVal = JSVAL_VOID;
13615 JS_NewNumberValue(context, (bounty | offence_value)-bounty, &amountVal);
13616
13617 bounty |= offence_value; // can't set the new bounty until the size of the change is known
13618
13619 jsval reasonVal = OOJSValueFromLegalStatusReason(context, reason);
13620
13621 ShipScriptEvent(context, self, "shipBountyChanged", amountVal, reasonVal);
13622
13623 OOJSRelinquishContext(context);
13624
13625 }
13626 }
13627}
OOINLINE jsval OOJSValueFromLegalStatusReason(JSContext *context, OOLegalStatusReason value)
OOLegalStatusReason
Definition OOTypes.h:157
#define ShipScriptEvent(context, ship, event,...)

◆ markedForFines

- (BOOL) markedForFines

Definition at line 14073 of file ShipEntity.m.

14263{
14264 return being_fined;
14265}

◆ markForFines

- (BOOL) markForFines

Definition at line 14073 of file ShipEntity.m.

14269{
14270 if (being_fined)
14271 return NO; // can't mark twice
14272 being_fined = ([self legalStatus] > 0);
14273 return being_fined;
14274}

Referenced by ShipMarkTargetForFines().

+ Here is the caller graph for this function:

◆ markTargetForFines

- (void) markTargetForFines
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2098{
2099 ShipEntity *ship = [self primaryTarget];
2100 if ((ship == nil) || ([ship status] == STATUS_DEAD) || ([ship status] == STATUS_DOCKED))
2101 {
2102 [self noteLostTarget];
2103 return;
2104 }
2105 if ([ship markForFines]) [shipAI message:@"TARGET_MARKED"];
2106}

◆ markTargetForOffence:

- (void) markTargetForOffence: (NSString *) valueString
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2109 :(NSString *)valueString
2110{
2111 if ((isStation)||(scanClass == CLASS_POLICE))
2112 {
2113 ShipEntity *ship = [self primaryTarget];
2114 if ((ship == nil) || ([ship status] == STATUS_DEAD) || ([ship status] == STATUS_DOCKED))
2115 {
2116 [self noteLostTarget];
2117 return;
2118 }
2119 NSString *finalValue = OOExpand(valueString); // expand values
2120 [ship markAsOffender:[finalValue intValue] withReason:kOOLegalStatusReasonSeenByPolice];
2121 }
2122}

◆ maxAftShieldLevel

- (float) maxAftShieldLevel

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

4079{
4080 return BASELINE_SHIELD_LEVEL * [self shieldBoostFactor];
4081}
#define BASELINE_SHIELD_LEVEL
Definition ShipEntity.h:99

◆ maxAvailableCargoSpace

- (OOCargoQuantity) maxAvailableCargoSpace

Definition at line 7619 of file ShipEntity.m.

8369{
8370 return max_cargo - equipment_weight;
8371}

Referenced by OOShipLibraryCargo(), and ShipSetProperty().

+ Here is the caller graph for this function:

◆ maxEscortCount

- (uint8_t) maxEscortCount

Definition at line 6496 of file ShipEntity.m.

7017{
7018 return _maxEscortCount;
7019}

◆ maxFlightPitch

- (GLfloat) maxFlightPitch

Definition at line 7619 of file ShipEntity.m.

8730{
8731 return max_flight_pitch;
8732}

Referenced by OOShipLibraryTurnRate().

+ Here is the caller graph for this function:

◆ maxFlightRoll

- (GLfloat) maxFlightRoll

Definition at line 7619 of file ShipEntity.m.

8742{
8743 return max_flight_roll;
8744}

Referenced by OOShipLibraryTurnRate().

+ Here is the caller graph for this function:

◆ maxFlightSpeed

- (GLfloat) maxFlightSpeed

◆ maxFlightYaw

- (GLfloat) maxFlightYaw

Definition at line 7619 of file ShipEntity.m.

8748{
8749 return max_flight_yaw;
8750}

◆ maxForwardShieldLevel

- (float) maxForwardShieldLevel

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

4073{
4074 return BASELINE_SHIELD_LEVEL * [self shieldBoostFactor];
4075}

◆ maxHyperspaceDistance

- (double) maxHyperspaceDistance

Definition at line 2093 of file ShipEntity.m.

4091{
4092 return MAX_JUMP_RANGE;
4093}
#define MAX_JUMP_RANGE
Definition ShipEntity.h:107

◆ maxShipSubEntities

- (NSUInteger) maxShipSubEntities

Definition at line 14954 of file ShipEntity.m.

793{
794 return _maxShipSubIdx;
795}
NSUInteger _maxShipSubIdx
Definition ShipEntity.h:343

◆ maxThrust

- (float) maxThrust

Definition at line 2093 of file ShipEntity.m.

4120{
4121 return max_thrust;
4122}
GLfloat max_thrust
Definition ShipEntity.h:245

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ mesh

- (OOMesh *) mesh

Definition at line 14954 of file ShipEntity.m.

1249{
1250 return (OOMesh *)[self drawable];
1251}

Referenced by ShipSetMaterialsInternal().

+ Here is the caller graph for this function:

◆ messageMother:

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

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1917 :(NSString *)msgString
1918{
1919 ShipEntity *mother = [self owner];
1920 if (mother != nil && mother != self)
1921 {
1922 NSString *context = nil;
1923#ifndef NDEBUG
1924 context = [NSString stringWithFormat:@"%@ messageMother", [self shortDescription]];
1925#endif
1926 [mother reactToAIMessage:msgString context:context];
1927 }
1928}

◆ messageSelf:

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

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1931 :(NSString *)msgString
1932{
1933 [self sendAIMessage:msgString];
1934}

◆ messageTime

- (double) messageTime

◆ missedShots

- (int) missedShots

Definition at line 9593 of file ShipEntity.m.

12086{
12087 if ([self isSubEntity])
12088 {
12089 return [[self owner] missedShots];
12090 }
12091 else
12092 {
12093 return _missed_shots;
12094 }
12095}

◆ missileCapacity

- (NSUInteger) missileCapacity

Definition at line 2093 of file ShipEntity.m.

3936{
3937 return max_missiles;
3938}

Referenced by OOShipLibraryWeapons().

+ Here is the caller graph for this function:

◆ missileCount

- (NSUInteger) missileCount

Definition at line 2093 of file ShipEntity.m.

3930{
3931 return missiles;
3932}

◆ missileLaunchPosition

- (Vector) missileLaunchPosition

Definition at line 9593 of file ShipEntity.m.

12147{
12148 Vector start;
12149 // default launching position
12150 start.x = 0.0f; // in the middle
12151 start.y = boundingBox.min.y - 4.0f; // 4m below bounding box
12152 start.z = boundingBox.max.z + 1.0f; // 1m ahead of bounding box
12153
12154 // custom launching position
12155 start = [shipinfoDictionary oo_vectorForKey:@"missile_launch_position" defaultValue:start];
12156 if (EXPECT_NOT(_scaleFactor != 1.0))
12157 {
12158 start = vector_multiply_scalar(start,_scaleFactor);
12159 }
12160
12161 if (start.x == 0.0f && start.y == 0.0f && start.z <= 0.0f) // The kZeroVector as start is illegal also.
12162 {
12163 OOLog(@"ship.missileLaunch.invalidPosition", @"***** ERROR: The missile_launch_position defines a position %@ behind the %@. In future versions such missiles may explode on launch because they have to travel through the ship.", VectorDescription(start), self);
12164 start.x = 0.0f;
12165 start.y = boundingBox.min.y - 4.0f;
12166 start.z = boundingBox.max.z + 1.0f;
12167 }
12168 return start;
12169}

◆ missileLoadTime

- (OOTimeDelta) missileLoadTime

Definition at line 9593 of file ShipEntity.m.

12330{
12331 return missile_load_time;
12332}

◆ missilesList

- (NSArray *) missilesList

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3303{
3304 // if missile_list is empty, avoid exception and return empty NSArray instead
3305 return missile_list[0] != nil ? [NSArray arrayWithObjects:missile_list count:missiles] :
3306 [NSArray array];
3307}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ missileTrackPrimaryTarget:

- (double) missileTrackPrimaryTarget: (double) delta_t

Definition at line 9593 of file ShipEntity.m.

10830 :(double) delta_t
10831{
10832 Vector relPos;
10833 GLfloat d_forward, d_up, d_right;
10834 ShipEntity *target = [self primaryTarget];
10835 BOOL inPursuit = YES;
10836
10837 if (!target || ![target isShip]) // leave now!
10838 return 0.0;
10839
10840 double damping = 0.5 * delta_t;
10841
10842 stick_roll = 0.0; //desired roll and pitch
10843 stick_pitch = 0.0;
10844 stick_yaw = 0.0;
10845
10846 relPos = [self vectorTo:target];
10847
10848 // Adjust missile course by taking into account target's velocity and missile
10849 // accuracy. Modification on original code contributed by Cmdr James.
10850
10851 float missileSpeed = (float)[self speed];
10852
10853 // Avoid getting ourselves in a divide by zero situation by setting a missileSpeed
10854 // low threshold. Arbitrarily chosen 0.01, since it seems to work quite well.
10855 // Missile accuracy is already clamped within the 0.0 to 10.0 range at initialization,
10856 // but doing these calculations every frame when accuracy equals 0.0 just wastes cycles.
10857 if (missileSpeed > 0.01f && accuracy > 0.0f)
10858 {
10859 inPursuit = (dot_product([target forwardVector], v_forward) > 0.0f);
10860 if (inPursuit)
10861 {
10862 Vector leading = [target velocity];
10863 float lead = magnitude(relPos) / missileSpeed;
10864
10865 // Adjust where we are going to take into account target's velocity.
10866 // Use accuracy value to determine how well missile will track target.
10867 relPos.x += (lead * leading.x * (accuracy / 10.0f));
10868 relPos.y += (lead * leading.y * (accuracy / 10.0f));
10869 relPos.z += (lead * leading.z * (accuracy / 10.0f));
10870 }
10871 }
10872
10873 if (!vector_equal(relPos, kZeroVector)) relPos = vector_normal(relPos);
10874 else relPos.z = 1.0;
10875
10876 d_right = dot_product(relPos, v_right); // = cosine of angle between angle to target and v_right
10877 d_up = dot_product(relPos, v_up); // = cosine of angle between angle to target and v_up
10878 d_forward = dot_product(relPos, v_forward); // = cosine of angle between angle to target and v_forward
10879
10880 // begin rule-of-thumb manoeuvres
10881
10882 stick_roll = 0.0;
10883
10884 if (pitching_over)
10885 pitching_over = (stick_pitch != 0.0);
10886
10887 if ((d_forward < -pitch_tolerance) && (!pitching_over))
10888 {
10889 pitching_over = YES;
10890 if (d_up >= 0)
10892 if (d_up < 0)
10894 }
10895
10896 if (pitching_over)
10897 {
10898 pitching_over = (d_forward < 0.5);
10899 }
10900 else
10901 {
10902 stick_pitch = -max_flight_pitch * d_up;
10903 stick_roll = -max_flight_roll * d_right;
10904 }
10905
10906 // end rule-of-thumb manoeuvres
10907
10908 // apply damping
10909 if (flightRoll < 0)
10910 flightRoll += (flightRoll < -damping) ? damping : -flightRoll;
10911 if (flightRoll > 0)
10912 flightRoll -= (flightRoll > damping) ? damping : flightRoll;
10913 if (flightPitch < 0)
10914 flightPitch += (flightPitch < -damping) ? damping : -flightPitch;
10915 if (flightPitch > 0)
10916 flightPitch -= (flightPitch > damping) ? damping : flightPitch;
10917
10918
10919 [self applySticks:delta_t];
10920
10921 //
10922 // return target confidence 0.0 .. 1.0
10923 //
10924 if (d_forward < 0.0)
10925 return 0.0;
10926 return d_forward;
10927}
Vector forwardVector()
GLfloat pitch_tolerance
Definition ShipEntity.h:374

◆ name

- (NSString *) name

◆ nextBeacon

- (Entity< OOBeaconEntity > *) nextBeacon
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1632{
1633 return [_nextBeacon weakRefUnderlyingObject];
1634}

◆ noteFrustration:

- (void) noteFrustration: (NSString *) context
implementation

Provided by category ShipEntity(Private).

Definition at line 2093 of file ShipEntity.m.

2953 :(NSString *)context
2954{
2955 [shipAI reactToMessage:@"FRUSTRATED" context:context];
2956 [self doScriptEvent:OOJSID("shipAIFrustrated") withArgument:context];
2957}

◆ noteKilledBy:damageType:

- (void) noteKilledBy: (Entity *) whom
damageType: (OOShipDamageType) type 

Definition at line 7619 of file ShipEntity.m.

9010 :(Entity *)whom damageType:(OOShipDamageType)type
9011{
9012 if ([self status] == STATUS_DEAD) return;
9013
9014 [PLAYER setScriptTarget:self];
9015
9016 JSContext *context = OOJSAcquireContext();
9017
9018 jsval whomVal = OOJSValueFromNativeObject(context, whom);
9019 jsval typeVal = OOJSValueFromShipDamageType(context, type);
9020 OOEntityStatus originalStatus = [self status];
9021 [self setStatus:STATUS_DEAD];
9022
9023 ShipScriptEvent(context, self, "shipDied", whomVal, typeVal);
9024 if ([whom isShip])
9025 {
9026 jsval selfVal = OOJSValueFromNativeObject(context, self);
9027 ShipScriptEvent(context, (ShipEntity *)whom, "shipKilledOther", selfVal, typeVal);
9028 }
9029
9030 [self setStatus:originalStatus];
9031 OOJSRelinquishContext(context);
9032}
OOINLINE jsval OOJSValueFromShipDamageType(JSContext *context, OOShipDamageType value)

◆ noteLostTarget

- (void) noteLostTarget

Definition at line 9593 of file ShipEntity.m.

10193{
10194 id target = nil;
10195 if ([self primaryTarget] != nil)
10196 {
10197 ShipEntity* ship = [self primaryTarget];
10198 if ([self isDefenseTarget:ship])
10199 {
10200 [self removeDefenseTarget:ship];
10201 }
10202 // for compatibility with 1.76 behaviour of this function, only pass
10203 // the target as a function parameter if the target is still a potential
10204 // valid target (e.g. not scooped, docked, hyperspaced, etc.)
10205 target = (ship && ship->isShip && [self isValidTarget:ship]) ? (id)ship : nil;
10206 if ([self primaryAggressor] == ship)
10207 {
10209 }
10211 }
10212 // always do target lost
10213 [self doScriptEvent:OOJSID("shipTargetLost") withArgument:target];
10214 if (target == nil) [shipAI message:@"TARGET_LOST"]; // stale target? no major urgency.
10215 else [shipAI reactToMessage:@"TARGET_LOST" context:@"flight updates"]; // execute immediately otherwise.
10216}
OOWeakReference * _primaryAggressor
Definition ShipEntity.h:438

◆ noteLostTargetAndGoIdle

- (void) noteLostTargetAndGoIdle

Definition at line 9593 of file ShipEntity.m.

10220{
10221 behaviour = BEHAVIOUR_IDLE;
10222 frustration = 0.0;
10223 [self noteLostTarget];
10224}

◆ noteTakingDamage:from:type:

- (void) noteTakingDamage: (double) amount
from: (Entity *) entity
type: (OOShipDamageType) type 

Reimplemented in DockEntity.

Definition at line 7619 of file ShipEntity.m.

8975 :(double)amount from:(Entity *)entity type:(OOShipDamageType)type
8976{
8977 if (amount < 0 || (amount == 0 && [[UNIVERSE gameController] isGamePaused])) return;
8978
8979 JSContext *context = OOJSAcquireContext();
8980
8981 jsval amountVal = JSVAL_VOID;
8982 JS_NewNumberValue(context, amount, &amountVal);
8983 jsval entityVal = OOJSValueFromNativeObject(context, entity);
8984 jsval typeVal = OOJSValueFromShipDamageType(context, type);
8985
8986 ShipScriptEvent(context, self, "shipTakingDamage", amountVal, entityVal, typeVal);
8987 OOJSRelinquishContext(context);
8988
8989 if ([entity isShip]) {
8990// ShipEntity* attacker = (ShipEntity *)entity;
8991 if ([self hasHostileTarget] && accuracy >= COMBAT_AI_IS_SMART && (randf()*10.0 < accuracy || desired_speed < 0.5 * maxFlightSpeed) && behaviour != BEHAVIOUR_EVASIVE_ACTION && behaviour != BEHAVIOUR_FLEE_EVASIVE_ACTION && behaviour != BEHAVIOUR_SCRIPTED_ATTACK_AI)
8992 {
8993 if (behaviour == BEHAVIOUR_FLEE_TARGET)
8994 {
8995// jink should be sufficient to avoid being hit most of the time
8996// if not, this will make a sharp turn and then select a new jink position
8997 behaviour = BEHAVIOUR_FLEE_EVASIVE_ACTION;
8998 }
8999 else
9000 {
9001 behaviour = BEHAVIOUR_EVASIVE_ACTION;
9002 }
9003 frustration = 0.0;
9004 }
9005 }
9006
9007}

◆ noteTargetDestroyed:

- (void) noteTargetDestroyed: (ShipEntity *) target

Definition at line 9593 of file ShipEntity.m.

10226 :(ShipEntity *)target
10227{
10228 [self collectBountyFor:(ShipEntity *)target];
10229 if ([self primaryTarget] == target)
10230 {
10231 [self removeTarget:target];
10232 [self doScriptEvent:OOJSID("shipTargetDestroyed") withArgument:target];
10233 [shipAI message:@"TARGET_DESTROYED"];
10234 }
10235 if ([self isDefenseTarget:target])
10236 {
10237 [self removeDefenseTarget:target];
10238 [shipAI message:@"DEFENSE_TARGET_DESTROYED"];
10239 [self doScriptEvent:OOJSID("defenseTargetDestroyed") withArgument:target];
10240 }
10241}

◆ noticeECM

- (void) noticeECM

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12343{
12344 if (accuracy >= COMBAT_AI_ISNT_AWFUL && missiles > 0 && [[missile_list[0] identifier] isEqualTo:@"EQ_MISSILE"])
12345 {
12346// if we're being ECMd, and our missiles appear to be standard, and we
12347// have some combat sense, wait a bit before firing the next one!
12348 missile_launch_time = [UNIVERSE getTime] + fmax(2.0,missile_load_time); // set minimum launchtime for the next missile.
12349 }
12350}

◆ numberOfScannedShips

- (int) numberOfScannedShips

Definition at line 9593 of file ShipEntity.m.

9913{
9914 return n_scanned_ships;
9915}

◆ octree

- (Octree *) octree

◆ onTarget:withWeapon:

- (BOOL) onTarget: (OOWeaponFacing) direction
withWeapon: (OOWeaponType) weapon 

Definition at line 9593 of file ShipEntity.m.

11389 :(OOWeaponFacing)direction withWeapon:(OOWeaponType)weapon_type
11390{
11391 // initialize dq to a value that would normally return NO; dq is handled inside the defaultless switch(direction) statement
11392 // and should alaways be recalculated anyway. Initialization here needed to silence compiler warning - Nikos 20120526
11393 GLfloat dq = -1.0f;
11394 GLfloat d2, radius, astq;
11395 Vector rel_pos, urp;
11396 if ([weapon_type isTurretLaser])
11397 {
11398 return YES;
11399 }
11400
11401 Entity *target = [self primaryTarget];
11402 if (target == nil) return NO;
11403 if ([target status] == STATUS_DEAD) return NO;
11404
11405 if (isSunlit && (target->isSunlit == NO) && (randf() < 0.75))
11406 {
11407 return NO; // 3/4 of the time you can't see from a lit place into a darker place
11408 }
11409 radius = target->collision_radius;
11410 rel_pos = HPVectorToVector(HPvector_subtract([self calculateTargetPosition], position));
11411 d2 = magnitude2(rel_pos);
11412 urp = vector_normal_or_zbasis(rel_pos);
11413
11414 switch (direction)
11415 {
11417 dq = +dot_product(urp, v_forward); // cosine of angle between v_forward and unit relative position
11418 break;
11419
11420 case WEAPON_FACING_AFT:
11421 dq = -dot_product(urp, v_forward); // cosine of angle between v_forward and unit relative position
11422 break;
11423
11424 case WEAPON_FACING_PORT:
11425 dq = -dot_product(urp, v_right); // cosine of angle between v_right and unit relative position
11426 break;
11427
11429 dq = +dot_product(urp, v_right); // cosine of angle between v_right and unit relative position
11430 break;
11431
11432 case WEAPON_FACING_NONE:
11433 break;
11434 }
11435
11436 if (dq < 0.0) return NO;
11437
11438 GLfloat aim = [self currentAimTolerance];
11439 if (dq > aim*aim) return YES;
11440
11441 // cosine of 1/3 of half angle subtended by target (mostly they'll
11442 // fire sooner anyway due to currentAimTolerance, but this should
11443 // almost always be a solid hit)
11444 astq = sqrt(1.0 - radius * radius / (d2 * 9));
11445
11446 return (fabs(dq) >= astq);
11447}
HPVector calculateTargetPosition()

◆ oo_jsClassName

- (NSString *) oo_jsClassName
implementation

Reimplemented from Entity.

Reimplemented in DockEntity, PlayerEntity, and StationEntity.

Provided by category ShipEntity(OOJavaScriptExtensions).

Definition at line 1 of file EntityOOJavaScriptExtensions.m.

129{
130 return @"Ship";
131}

◆ orientationChanged

- (void) orientationChanged
implementation

Reimplemented from Entity.

Reimplemented in PlayerEntity.

Definition at line 6496 of file ShipEntity.m.

6788{
6789 [super orientationChanged];
6790
6794}
Vector vector_up_from_quaternion(Quaternion quat)
Vector vector_right_from_quaternion(Quaternion quat)

◆ overrideScriptInfo:

- (void) overrideScriptInfo: (NSDictionary *) override

Definition at line 14073 of file ShipEntity.m.

14588 :(NSDictionary *)override
14589{
14590 if (scriptInfo == nil) scriptInfo = [override retain];
14591 else if (override != nil)
14592 {
14593 NSMutableDictionary *newInfo = [NSMutableDictionary dictionaryWithDictionary:scriptInfo];
14594 [newInfo addEntriesFromDictionary:override];
14595 [scriptInfo release];
14596 scriptInfo = [newInfo copy];
14597 }
14598}
NSDictionary * scriptInfo
Definition ShipEntity.h:431

◆ parcelCount

- (NSUInteger) parcelCount

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3912{
3913 return 0;
3914}

◆ parcelListForScripting

- (NSArray *) parcelListForScripting

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3317{
3318 return [NSArray array];
3319}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ passengerCapacity

- (NSUInteger) passengerCapacity

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3924{
3925 return 0;
3926}

Referenced by ShipRemoveEquipment().

+ Here is the caller graph for this function:

◆ passengerCount

- (NSUInteger) passengerCount

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3918{
3919 return 0;
3920}

◆ passengerListForScripting

- (NSArray *) passengerListForScripting

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3311{
3312 return [NSArray array];
3313}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ patrolReportIn

- (void) patrolReportIn
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2058{
2059 // Set a report time in the patrolled station to delay a new launch.
2060 ShipEntity *the_station = [[self group] leader];
2061 if(!the_station || ![the_station isStation]) the_station = [UNIVERSE station];
2062 [(StationEntity*)the_station acceptPatrolReportFrom:self];
2063}

◆ pauseAI:

- (void) pauseAI: (NSString *) intervalString
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

851 :(NSString *)intervalString
852{
853 [shipAI setNextThinkTime:[UNIVERSE getTime] + [intervalString doubleValue]];
854}

◆ pendingEscortCount

- (uint8_t) pendingEscortCount

Definition at line 6496 of file ShipEntity.m.

7005{
7006 return _pendingEscortCount;
7007}
uint8_t _pendingEscortCount
Definition ShipEntity.h:469

◆ performAttack

- (void) performAttack

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

379{
380 if (behaviour != BEHAVIOUR_EVASIVE_ACTION)
381 {
382 behaviour = BEHAVIOUR_ATTACK_TARGET;
383 desired_range = 1250 * randf() + 750; // 750 til 2000
384 frustration = 0.0;
385 }
386}

◆ performBuoyTumble

- (void) performBuoyTumble
implementation

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

511{
512 stick_roll = 0.10;
513 stick_pitch = 0.15;
514 behaviour = BEHAVIOUR_TUMBLE;
515 frustration = 0.0;
516}

◆ performCollect

- (void) performCollect

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

390{
391 behaviour = BEHAVIOUR_COLLECT_TARGET;
392 frustration = 0.0;
393}

◆ performEscort

- (void) performEscort

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

397{
398 if(behaviour != BEHAVIOUR_FORMATION_FORM_UP)
399 {
400 behaviour = BEHAVIOUR_FORMATION_FORM_UP;
401 frustration = 0.0; // behavior changed, reset frustration.
402 }
403}

◆ performFaceDestination

- (void) performFaceDestination

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

407{
408 behaviour = BEHAVIOUR_FACE_DESTINATION;
409 frustration = 0.0;
410}

◆ performFlee

- (void) performFlee

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

414{
415 if (behaviour != BEHAVIOUR_FLEE_EVASIVE_ACTION)
416 {
417 behaviour = BEHAVIOUR_FLEE_TARGET;
418 [self setEvasiveJink:400.0];
419 frustration = 0.0;
420 if (accuracy > COMBAT_AI_ISNT_AWFUL)
421 {
422 // alert! they've got us in their sights! react!!
423 if ([self approachAspectToPrimaryTarget] > 0.9995)
424 {
425 behaviour = randf() < 0.15 ? BEHAVIOUR_EVASIVE_ACTION : BEHAVIOUR_FLEE_EVASIVE_ACTION;
426 }
427 }
428 }
429}

◆ performFlyRacepoints

- (void) performFlyRacepoints
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2733{
2734 next_navpoint_index = 0;
2735 desired_range = collision_radius;
2736 behaviour = BEHAVIOUR_FLY_THRU_NAVPOINTS;
2737}

◆ performFlyToRangeFromDestination

- (void) performFlyToRangeFromDestination

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

433{
434 behaviour = BEHAVIOUR_FLY_RANGE_FROM_DESTINATION;
435 frustration = 0.0;
436}

◆ performHold

- (void) performHold

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

440{
441 desired_speed = 0.0;
442 behaviour = BEHAVIOUR_TRACK_TARGET;
443 frustration = 0.0;
444}

◆ performHyperSpaceExit

- (void) performHyperSpaceExit
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ performHyperSpaceExitReplace:

- (BOOL) performHyperSpaceExitReplace: (BOOL) replace
implementation

Provided by category ShipEntity(OOAIPrivate).

Definition at line 1 of file ShipEntityAI.m.

2758 :(BOOL)replace
2759{
2760 return [self performHyperSpaceExitReplace:replace toSystem:-1];
2761}

◆ performHyperSpaceExitReplace:toSystem:

- (BOOL) performHyperSpaceExitReplace: (BOOL) replace
toSystem: (OOSystemID) systemID 
implementation

Provided by category ShipEntity(OOAIPrivate).

Definition at line 1 of file ShipEntityAI.m.

2764 :(BOOL)replace toSystem:(OOSystemID)systemID
2765{
2766 if(![self hasHyperspaceMotor])
2767 {
2768 [shipAI reactToMessage:@"WITCHSPACE UNAVAILABLE" context:@"performHyperSpaceExit"];
2769 return NO;
2770 }
2771 if([self status] == STATUS_ENTERING_WITCHSPACE)
2772 {
2773// already in a wormhole
2774 return NO;
2775 }
2776
2777 NSArray *sDests = nil;
2778 OOSystemID targetSystem;
2779 NSUInteger i = 0;
2780
2781 // get a list of destinations within range
2782 sDests = [UNIVERSE nearbyDestinationsWithinRange: 0.1f * fuel];
2783 NSUInteger n_dests = [sDests count];
2784
2785 // if none available report to the AI and exit
2786 if (n_dests == 0)
2787 {
2788 [shipAI reactToMessage:@"WITCHSPACE UNAVAILABLE" context:@"performHyperSpaceExit"];
2789
2790 // If no systems exist near us, the AI is switched to a different state, so we do not need
2791 // the nearby destinations array anymore.
2792 return NO;
2793 }
2794
2795 // check if we're clear of nearby masses
2796 ShipEntity *blocker = [UNIVERSE entityForUniversalID:[self checkShipsInVicinityForWitchJumpExit]];
2797 if (blocker)
2798 {
2799 [self setFoundTarget:blocker];
2800 [shipAI reactToMessage:@"WITCHSPACE BLOCKED" context:@"performHyperSpaceExit"];
2801 [self doScriptEvent:OOJSID("shipWitchspaceBlocked") withArgument:blocker];
2802
2803 return NO;
2804 }
2805
2806 if (systemID == -1)
2807 {
2808 // select one at random
2809 if (n_dests > 1)
2810 {
2811 i = ranrot_rand() % n_dests;
2812 }
2813
2814
2815 targetSystem = [[sDests oo_dictionaryAtIndex:i] oo_intForKey:@"sysID"];
2816 }
2817 else
2818 {
2819 targetSystem = systemID;
2820
2821 for (i = 0; i < n_dests; i++)
2822 {
2823 if (systemID == [[sDests oo_dictionaryAtIndex:i] oo_intForKey:@"sysID"]) break;
2824 }
2825
2826 if (i == n_dests) // no match found
2827 {
2828 return NO;
2829 }
2830 }
2831 float dist = [[sDests oo_dictionaryAtIndex:i] oo_floatForKey:@"distance"];
2832 if (dist > [self maxHyperspaceDistance] || dist > fuel/10.0f)
2833 {
2834 OOLogWARN(@"script.debug", @"DEBUG: %@ Jumping %f which is further than allowed. I have %d fuel", self, dist, fuel);
2835 }
2836 fuel -= 10 * dist;
2837
2838 // create wormhole
2839 WormholeEntity *whole = [[[WormholeEntity alloc] initWormholeTo: targetSystem fromShip:self] autorelease];
2840 [UNIVERSE addEntity: whole];
2841
2842 [self enterWormhole:whole replacing:replace];
2843
2844 // we've no need for the destinations array anymore.
2845 return YES;
2846}
#define OOLogWARN(class, format,...)
Definition OOLogging.h:113
int16_t OOSystemID
Definition OOTypes.h:211

◆ performHyperSpaceExitWithoutReplacing

- (void) performHyperSpaceExitWithoutReplacing
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1636{
1637 [self performHyperSpaceExitReplace:NO];
1638}

◆ performHyperSpaceToSpecificSystem:

- (BOOL) performHyperSpaceToSpecificSystem: (OOSystemID) systemID

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

536 :(OOSystemID)systemID
537{
538 return [self performHyperSpaceExitReplace:NO toSystem:systemID];
539}

Referenced by ShipExitSystem().

+ Here is the caller graph for this function:

◆ performIdle

- (void) performIdle

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

448{
449 behaviour = BEHAVIOUR_IDLE;
450 frustration = 0.0;
451}

◆ performIntercept

- (void) performIntercept

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

455{
456 behaviour = BEHAVIOUR_INTERCEPT_TARGET;
457 frustration = 0.0;
458}

◆ performLandOnPlanet

- (void) performLandOnPlanet

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

462{
463 OOPlanetEntity *nearest = [self findNearestPlanet];
464 if (isNearPlanetSurface)
465 {
466 _destination = [nearest position];
467 behaviour = BEHAVIOUR_LAND_ON_PLANET;
468 planetForLanding = [nearest universalID];
469 }
470 else
471 {
472 behaviour = BEHAVIOUR_IDLE;
473 [shipAI message:@"NO_PLANET_NEARBY"];
474 }
475
476 frustration = 0.0;
477}

◆ performMining

- (void) performMining

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

481{
482 Entity *target = [self primaryTarget];
483 // mining is not seen as hostile behaviour, so ensure it is only used against rocks.
484 if (target && [target scanClass] == CLASS_ROCK)
485 {
486 behaviour = BEHAVIOUR_ATTACK_MINING_TARGET;
487 frustration = 0.0;
488 }
489 else
490 {
491 [self noteLostTargetAndGoIdle];
492 }
493}

◆ performScriptedAI

- (void) performScriptedAI

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

497{
498 behaviour = BEHAVIOUR_SCRIPTED_AI;
499 frustration = 0.0;
500}

◆ performScriptedAttackAI

- (void) performScriptedAttackAI

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

504{
505 behaviour = BEHAVIOUR_SCRIPTED_ATTACK_AI;
506 frustration = 0.0;
507}

◆ performStop

- (void) performStop

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

520{
521 behaviour = BEHAVIOUR_STOP_STILL;
522 desired_speed = 0.0;
523 frustration = 0.0;
524}

◆ performTumble

- (void) performTumble

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

528{
529 stick_roll = max_flight_roll*2.0*(randf() - 0.5);
530 stick_pitch = max_flight_pitch*2.0*(randf() - 0.5);
531 behaviour = BEHAVIOUR_TUMBLE;
532 frustration = 0.0;
533}

◆ portWeaponOffset

- (NSArray *) portWeaponOffset

◆ positionOffsetForAlignment:

- (Vector) positionOffsetForAlignment: (NSString*) align

Definition at line 7619 of file ShipEntity.m.

9546 :(NSString*) align
9547{
9548 NSString* padAlign = [NSString stringWithFormat:@"%@---", align];
9549 Vector result = kZeroVector;
9550 switch ([padAlign characterAtIndex:0])
9551 {
9552 case (unichar)'c':
9553 case (unichar)'C':
9554 result.x = 0.5 * (boundingBox.min.x + boundingBox.max.x);
9555 break;
9556 case (unichar)'M':
9557 result.x = boundingBox.max.x;
9558 break;
9559 case (unichar)'m':
9560 result.x = boundingBox.min.x;
9561 break;
9562 }
9563 switch ([padAlign characterAtIndex:1])
9564 {
9565 case (unichar)'c':
9566 case (unichar)'C':
9567 result.y = 0.5 * (boundingBox.min.y + boundingBox.max.y);
9568 break;
9569 case (unichar)'M':
9570 result.y = boundingBox.max.y;
9571 break;
9572 case (unichar)'m':
9573 result.y = boundingBox.min.y;
9574 break;
9575 }
9576 switch ([padAlign characterAtIndex:2])
9577 {
9578 case (unichar)'c':
9579 case (unichar)'C':
9580 result.z = 0.5 * (boundingBox.min.z + boundingBox.max.z);
9581 break;
9582 case (unichar)'M':
9583 result.z = boundingBox.max.z;
9584 break;
9585 case (unichar)'m':
9586 result.z = boundingBox.min.z;
9587 break;
9588 }
9589 return result;
9590}

◆ positionOffsetForShipInRotationToAlignment

- (Vector) positionOffsetForShipInRotationToAlignment (ShipEntity *) ship
(Quaternion) q
(NSString *) align 

Definition at line 9593 of file ShipEntity.m.

9594{
9595 NSString* padAlign = [NSString stringWithFormat:@"%@---", align];
9596 Vector i = vector_right_from_quaternion(q);
9597 Vector j = vector_up_from_quaternion(q);
9598 Vector k = vector_forward_from_quaternion(q);
9599 BoundingBox arbb = [ship findBoundingBoxRelativeToPosition:kZeroHPVector InVectors:i :j :k];
9600 Vector result = kZeroVector;
9601 switch ([padAlign characterAtIndex:0])
9602 {
9603 case (unichar)'c':
9604 case (unichar)'C':
9605 result.x = 0.5 * (arbb.min.x + arbb.max.x);
9606 break;
9607 case (unichar)'M':
9608 result.x = arbb.max.x;
9609 break;
9610 case (unichar)'m':
9611 result.x = arbb.min.x;
9612 break;
9613 }
9614 switch ([padAlign characterAtIndex:1])
9615 {
9616 case (unichar)'c':
9617 case (unichar)'C':
9618 result.y = 0.5 * (arbb.min.y + arbb.max.y);
9619 break;
9620 case (unichar)'M':
9621 result.y = arbb.max.y;
9622 break;
9623 case (unichar)'m':
9624 result.y = arbb.min.y;
9625 break;
9626 }
9627 switch ([padAlign characterAtIndex:2])
9628 {
9629 case (unichar)'c':
9630 case (unichar)'C':
9631 result.z = 0.5 * (arbb.min.z + arbb.max.z);
9632 break;
9633 case (unichar)'M':
9634 result.z = arbb.max.z;
9635 break;
9636 case (unichar)'m':
9637 result.z = arbb.min.z;
9638 break;
9639 }
9640 return result;
9641}
BoundingBox findBoundingBoxRelativeToPosition:InVectors:i:j:(HPVector opv,[InVectors] Vector,[i] Vector,[j] Vector k)

◆ prevBeacon

- (Entity< OOBeaconEntity > *) prevBeacon
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1626{
1627 return [_prevBeacon weakRefUnderlyingObject];
1628}

◆ primaryAggressor

- (Entity *) primaryAggressor

Definition at line 9593 of file ShipEntity.m.

9938{
9939 Entity *result = [_primaryAggressor weakRefUnderlyingObject];
9940 if (result == nil || ![self isValidTarget:result])
9941 {
9943 return nil;
9944 }
9945 return result;
9946}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ primaryRole

- (NSString *) primaryRole

◆ primaryTarget

- (id) primaryTarget

Definition at line 9593 of file ShipEntity.m.

10122{
10123 id result = [_primaryTarget weakRefUnderlyingObject];
10124 if ((result == nil && _primaryTarget != nil)
10125 || ![self isValidTarget:result])
10126 {
10128 return nil;
10129 }
10130 else if (EXPECT_NOT(result == self))
10131 {
10132 /* Added in response to a crash report showing recursion in
10133 [PlayerEntity hasHostileTarget].
10134 -- Ahruman 2009-12-17
10135 */
10137 }
10138 return result;
10139}

Referenced by HeadUpDisplay::hudDrawReticleOnTarget, ShipFireMissile(), and ShipGetProperty().

+ Here is the caller graph for this function:

◆ primaryTargetWithoutValidityCheck

- (id) primaryTargetWithoutValidityCheck

Definition at line 9593 of file ShipEntity.m.

10145{
10146 id result = [_primaryTarget weakRefUnderlyingObject];
10147 if (EXPECT_NOT(result == self))
10148 {
10149 // just in case
10151 return nil;
10152 }
10153 return result;
10154}

◆ processBehaviour:

- (void) processBehaviour: (OOTimeDelta) delta_t

Definition at line 2093 of file ShipEntity.m.

2793 :(OOTimeDelta)delta_t
2794{
2795 BOOL applyThrust = YES;
2796 switch (behaviour)
2797 {
2798 case BEHAVIOUR_TUMBLE :
2799 [self behaviour_tumble: delta_t];
2800 break;
2801
2802 case BEHAVIOUR_STOP_STILL :
2803 case BEHAVIOUR_STATION_KEEPING :
2804 [self behaviour_stop_still: delta_t];
2805 break;
2806
2807 case BEHAVIOUR_IDLE :
2808 if ([self isSubEntity])
2809 {
2810 applyThrust = NO;
2811 }
2812 [self behaviour_idle: delta_t];
2813 break;
2814
2815 case BEHAVIOUR_TRACTORED :
2816 [self behaviour_tractored: delta_t];
2817 break;
2818
2819 case BEHAVIOUR_TRACK_TARGET :
2820 [self behaviour_track_target: delta_t];
2821 break;
2822
2823 case BEHAVIOUR_INTERCEPT_TARGET :
2824 case BEHAVIOUR_COLLECT_TARGET :
2825 [self behaviour_intercept_target: delta_t];
2826 break;
2827
2828 case BEHAVIOUR_ATTACK_TARGET :
2829 [self behaviour_attack_target: delta_t];
2830 break;
2831
2832 case BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX :
2833 case BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE :
2834 [self behaviour_fly_to_target_six: delta_t];
2835 break;
2836
2837 case BEHAVIOUR_ATTACK_MINING_TARGET :
2838 [self behaviour_attack_mining_target: delta_t];
2839 break;
2840
2841 case BEHAVIOUR_ATTACK_FLY_TO_TARGET :
2842 [self behaviour_attack_fly_to_target: delta_t];
2843 break;
2844
2845 case BEHAVIOUR_ATTACK_FLY_FROM_TARGET :
2846 [self behaviour_attack_fly_from_target: delta_t];
2847 break;
2848
2849 case BEHAVIOUR_ATTACK_BREAK_OFF_TARGET :
2850 [self behaviour_attack_break_off_target: delta_t];
2851 break;
2852
2853 case BEHAVIOUR_ATTACK_SLOW_DOGFIGHT :
2854 [self behaviour_attack_slow_dogfight: delta_t];
2855 break;
2856
2857 case BEHAVIOUR_RUNNING_DEFENSE :
2858 [self behaviour_running_defense: delta_t];
2859 break;
2860
2861 case BEHAVIOUR_ATTACK_BROADSIDE :
2862 [self behaviour_attack_broadside: delta_t];
2863 break;
2864
2865 case BEHAVIOUR_ATTACK_BROADSIDE_LEFT :
2866 [self behaviour_attack_broadside_left: delta_t];
2867 break;
2868
2869 case BEHAVIOUR_ATTACK_BROADSIDE_RIGHT :
2870 [self behaviour_attack_broadside_right: delta_t];
2871 break;
2872
2873 case BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE :
2874 [self behaviour_close_to_broadside_range: delta_t];
2875 break;
2876
2877 case BEHAVIOUR_CLOSE_WITH_TARGET :
2878 [self behaviour_close_with_target: delta_t];
2879 break;
2880
2881 case BEHAVIOUR_ATTACK_SNIPER :
2882 [self behaviour_attack_sniper: delta_t];
2883 break;
2884
2885 case BEHAVIOUR_EVASIVE_ACTION :
2886 case BEHAVIOUR_FLEE_EVASIVE_ACTION :
2887 [self behaviour_evasive_action: delta_t];
2888 break;
2889
2890 case BEHAVIOUR_FLEE_TARGET :
2891 [self behaviour_flee_target: delta_t];
2892 break;
2893
2894 case BEHAVIOUR_FLY_RANGE_FROM_DESTINATION :
2895 [self behaviour_fly_range_from_destination: delta_t];
2896 break;
2897
2898 case BEHAVIOUR_FACE_DESTINATION :
2899 [self behaviour_face_destination: delta_t];
2900 break;
2901
2902 case BEHAVIOUR_LAND_ON_PLANET :
2903 [self behaviour_land_on_planet: delta_t];
2904 break;
2905
2906 case BEHAVIOUR_FORMATION_FORM_UP :
2907 [self behaviour_formation_form_up: delta_t];
2908 break;
2909
2910 case BEHAVIOUR_FLY_TO_DESTINATION :
2911 [self behaviour_fly_to_destination: delta_t];
2912 break;
2913
2914 case BEHAVIOUR_FLY_FROM_DESTINATION :
2915 case BEHAVIOUR_FORMATION_BREAK :
2916 [self behaviour_fly_from_destination: delta_t];
2917 break;
2918
2919 case BEHAVIOUR_AVOID_COLLISION :
2920 [self behaviour_avoid_collision: delta_t];
2921 break;
2922
2923 case BEHAVIOUR_TRACK_AS_TURRET :
2924 applyThrust = NO;
2925 [self behaviour_track_as_turret: delta_t];
2926 break;
2927
2928 case BEHAVIOUR_FLY_THRU_NAVPOINTS :
2929 [self behaviour_fly_thru_navpoints: delta_t];
2930 break;
2931
2932 case BEHAVIOUR_SCRIPTED_AI:
2933 case BEHAVIOUR_SCRIPTED_ATTACK_AI:
2934 [self behaviour_scripted_ai: delta_t];
2935 break;
2936
2937 case BEHAVIOUR_ENERGY_BOMB_COUNTDOWN:
2938 applyThrust = NO;
2939 // Do nothing
2940 break;
2941 }
2942
2943 // generally the checks above should be turning this *off* for subents
2944 if (applyThrust)
2945 {
2946 [self applyAttitudeChanges:delta_t];
2947 [self applyThrust:delta_t];
2948 }
2949}
double OOTimeDelta
Definition OOTypes.h:224

◆ proximityAlert

- (Entity *) proximityAlert

Definition at line 6496 of file ShipEntity.m.

7045{
7046 Entity* prox = [_proximityAlert weakRefUnderlyingObject];
7047 if (prox == nil)
7048 {
7050 }
7051 return prox;
7052}
OOWeakReference * _proximityAlert
Definition ShipEntity.h:444

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ randomEjectaTemperature

- (float) randomEjectaTemperature

Definition at line 7619 of file ShipEntity.m.

8797{
8798 return [self randomEjectaTemperatureWithMaxFactor:0.99f];
8799}

◆ randomEjectaTemperatureWithMaxFactor:

- (float) randomEjectaTemperatureWithMaxFactor: (float) factor

Definition at line 7619 of file ShipEntity.m.

8802 :(float)factor
8803{
8804 const float kRange = 0.02f;
8805 factor -= kRange;
8806
8807 float parentTemp = [self temperature];
8808 float adjusted = parentTemp * (bellf(5) * (kRange * 2.0f) - kRange + factor);
8809 if (adjusted > SHIP_MAX_CABIN_TEMP)
8810 {
8811 adjusted = SHIP_MAX_CABIN_TEMP;
8812 }
8813
8814 // Interpolate so that result == parentTemp when parentTemp is SHIP_MIN_CABIN_TEMP
8815 float interp = OOClamp_0_1_f((parentTemp - SHIP_MIN_CABIN_TEMP) / (SHIP_MAX_CABIN_TEMP - SHIP_MIN_CABIN_TEMP));
8816
8817 return OOLerp(SHIP_MIN_CABIN_TEMP, adjusted, interp);
8818}
float bellf(int n)

◆ randomPauseAI:

- (void) randomPauseAI: (NSString *) intervalString
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ randomSeedForShaders

- (uint32_t) randomSeedForShaders
implementation

Definition at line 9593 of file ShipEntity.m.

9779{
9780 return entity_personality * 0x00010001;
9781}

◆ rangeToDestination

- (GLfloat) rangeToDestination

Definition at line 9593 of file ShipEntity.m.

11113{
11114 return HPdistance(position, _destination);
11115}

◆ rangeToPrimaryTarget

- (double) rangeToPrimaryTarget

Definition at line 9593 of file ShipEntity.m.

11238{
11239 return [self rangeToSecondaryTarget:[self primaryTarget]];
11240}

◆ rangeToSecondaryTarget:

- (double) rangeToSecondaryTarget: (Entity *) target

Definition at line 9593 of file ShipEntity.m.

11243 :(Entity *)target
11244{
11245 double dist;
11246 Vector delta;
11247 if (target == nil) // leave now!
11248 return 0.0;
11249 delta = HPVectorToVector(HPvector_subtract(target->position, position));
11250 dist = magnitude(delta);
11251 dist -= target->collision_radius;
11252 dist -= collision_radius;
11253 return dist;
11254}

◆ rawEscortGroup

- (OOShipGroup *) rawEscortGroup
implementation

Provided by category ShipEntity(DebugRawAccess).

Definition at line 6496 of file ShipEntity.m.

6958{
6959 return _escortGroup;
6960}

◆ reactionTime

- (float) reactionTime

◆ reactToAIMessage:context:

- (void) reactToAIMessage: (NSString *) message
context: (NSString *) debugContext 

Definition at line 14073 of file ShipEntity.m.

14717 :(NSString *)message context:(NSString *)debugContext
14718{
14719 [shipAI reactToMessage:message context:debugContext];
14720}

Referenced by ShipReactToAIMessage().

+ Here is the caller graph for this function:

◆ realAlertCondition

- (OOAlertCondition) realAlertCondition

Reimplemented in PlayerEntity.

Definition at line 14073 of file ShipEntity.m.

14760{
14761 if ([self status] == STATUS_DOCKED)
14762 {
14764 }
14765 if ([self hasHostileTarget])
14766 {
14767 return ALERT_CONDITION_RED;
14768 }
14769 else
14770 {
14771 NSEnumerator *sEnum = [_defenseTargets objectEnumerator];
14772 ShipEntity *ship = nil;
14773 double scanrange2 = scannerRange * scannerRange;
14774 while ((ship = [sEnum nextObject]))
14775 {
14776 if ([ship hasHostileTarget] || ([ship isPlayer] && [PLAYER weaponsOnline]))
14777 {
14778 if (HPdistance2([ship position],position) < scanrange2)
14779 {
14780 return ALERT_CONDITION_RED;
14781 }
14782 }
14783 }
14784 // also need to check primary target separately
14785 if ([self hasHostileTarget])
14786 {
14787 Entity *ptarget = [self primaryTargetWithoutValidityCheck];
14788 if (ptarget != nil && [ptarget isShip])
14789 {
14790 ship = (ShipEntity *)ptarget;
14791 if ([ship hasHostileTarget] || ([ship isPlayer] && [PLAYER weaponsOnline]))
14792 {
14793 if (HPdistance2([ship position],position) < scanrange2 * 1.5625)
14794 {
14795 return ALERT_CONDITION_RED;
14796 }
14797 }
14798 }
14799 }
14800 if (_group)
14801 {
14802 sEnum = [_group objectEnumerator];
14803 while ((ship = [sEnum nextObject]))
14804 {
14805 if ([ship hasHostileTarget] || ([ship isPlayer] && [PLAYER weaponsOnline]))
14806 {
14807 if (HPdistance2([ship position],position) < scanrange2)
14808 {
14809 return ALERT_CONDITION_RED;
14810 }
14811 }
14812 }
14813 }
14815 {
14816 sEnum = [_escortGroup objectEnumerator];
14817 while ((ship = [sEnum nextObject]))
14818 {
14819 if ([ship hasHostileTarget] || ([ship isPlayer] && [PLAYER weaponsOnline]))
14820 {
14821 if (HPdistance2([ship position],position) < scanrange2)
14822 {
14823 return ALERT_CONDITION_RED;
14824 }
14825 }
14826 }
14827 }
14828 }
14830}

◆ recallDockingInstructions

- (void) recallDockingInstructions

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

600{
601 if (dockingInstructions != nil)
602 {
603 _destination = [dockingInstructions oo_hpvectorForKey:@"destination"];
604 desired_speed = fmin([dockingInstructions oo_floatForKey:@"speed"], maxFlightSpeed);
605 desired_range = [dockingInstructions oo_floatForKey:@"range"];
606 if ([dockingInstructions objectForKey:@"station"])
607 {
608 StationEntity *targetStation = [[dockingInstructions objectForKey:@"station"] weakRefUnderlyingObject];
609 if (targetStation != nil)
610 {
611 [self addTarget:targetStation];
612 [self setTargetStation:targetStation];
613 }
614 else
615 {
616 [self removeTarget:[self primaryTarget]];
617 }
618 }
619 docking_match_rotation = [dockingInstructions oo_boolForKey:@"match_rotation"];
620 }
621}

◆ recallStoredTarget

- (void) recallStoredTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ receiveCommsMessage:from:

- (void) receiveCommsMessage: (NSString *) message_text
from: (ShipEntity *) other 

Reimplemented in PlayerEntity.

Definition at line 14073 of file ShipEntity.m.

14240 :(NSString *) message_text from:(ShipEntity *) other
14241{
14242 // Too complex for AI scripts to handle, JS event only.
14243 [self doScriptEvent:OOJSID("commsMessageReceived") withArgument:message_text andArgument:other];
14244}

◆ reference

- (Vector) reference

◆ refreshEscortPositions

- (void) refreshEscortPositions
implementation

Provided by category ShipEntity(Private).

Definition at line 9593 of file ShipEntity.m.

13791{
13793 {
13794 JSContext *context = OOJSAcquireContext();
13795 jsval result;
13796 jsval args[] = { INT_TO_JSVAL(0), INT_TO_JSVAL(_maxEscortCount) };
13797 BOOL OK;
13798
13799 // Reset validity first so updateEscortFormation can be called from the update callback.
13801
13802 uint8_t i;
13803 for (i = 0; i < _maxEscortCount; i++)
13804 {
13805 args[0] = INT_TO_JSVAL(i);
13806 OK = [script callMethod:OOJSID("coordinatesForEscortPosition")
13807 inContext:context
13808 withArguments:args count:sizeof args / sizeof *args
13809 result:&result];
13810
13811 if (OK) OK = JSValueToVector(context, result, &_escortPositions[i]);
13812
13813 if (!OK) _escortPositions[i] = kZeroVector;
13814 }
13815
13816 OOJSRelinquishContext(context);
13817 }
13818}
BOOL JSValueToVector(JSContext *context, jsval value, Vector *outVector) NONNULL_FUNC
Definition OOJSVector.m:259
BOOL _escortPositionsValid
Definition ShipEntity.h:472

◆ releaseCargoPodsDebris

- (void) releaseCargoPodsDebris
implementation

Definition at line 7619 of file ShipEntity.m.

9086{
9087 HPVector xposition = position;
9088 NSUInteger i;
9089 Vector v;
9090 Quaternion q;
9091 int speed_low = 200;
9092
9093 NSArray *jetsam = nil; // this will contain the stuff to get thrown out
9094 unsigned cargo_chance = 70;
9095 jetsam = [NSArray arrayWithArray:cargo]; // what the ship is carrying
9096 [cargo removeAllObjects]; // dispense with it!
9097 unsigned limit = 15;
9098 // Throw out cargo
9099 NSUInteger n_jetsam = [jetsam count];
9100
9101 for (i = 0; i < n_jetsam; i++)
9102 {
9103 if (Ranrot() % 100 < cargo_chance) // chance of any given piece of cargo surviving decompression
9104 {
9105 // a higher chance of getting at least a couple of bits of cargo out
9106 if (cargo_chance > 10)
9107 {
9108 if (EXPECT_NOT([self isPlayer]))
9109 {
9110 cargo_chance -= 20;
9111 }
9112 else
9113 {
9114 cargo_chance -= 30;
9115 }
9116 }
9117 limit--;
9118 ShipEntity* cargoObj = [jetsam objectAtIndex:i];
9119 ShipEntity* container = [UNIVERSE reifyCargoPod:cargoObj];
9120 /* TODO: this debris position/velocity setting code is
9121 * duplicated - sometimes not very cleanly - all over the
9122 * place. Unify to a single function - CIM */
9123 HPVector rpos = xposition;
9125 rpos.x += rrand.x; rpos.y += rrand.y; rpos.z += rrand.z;
9126 rpos.x += (ranrot_rand() % 7) - 3;
9127 rpos.y += (ranrot_rand() % 7) - 3;
9128 rpos.z += (ranrot_rand() % 7) - 3;
9129 [container setPosition:rpos];
9130 v.x = 0.1 *((ranrot_rand() % speed_low) - speed_low / 2);
9131 v.y = 0.1 *((ranrot_rand() % speed_low) - speed_low / 2);
9132 v.z = 0.1 *((ranrot_rand() % speed_low) - speed_low / 2);
9133 [container setVelocity:vector_add(v,[self velocity])];
9135 [container setOrientation:q];
9136
9137 [container setTemperature:[self randomEjectaTemperature]];
9138 [container setScanClass: CLASS_CARGO];
9139 [UNIVERSE addEntity:container]; // STATUS_IN_FLIGHT, AI state GLOBAL
9140
9141 AI *containerAI = [container getAI];
9142 if ([containerAI hasSuspendedStateMachines]) // check if new or recycled cargo.
9143 {
9144 [containerAI exitStateMachineWithMessage:nil];
9145 [container setThrust:[container maxThrust]]; // restore old value. Was set to zero on previous scooping.
9146 [container setOwner:container];
9147 }
9148 }
9149 if (limit <= 0)
9150 {
9151 break; // even really big ships won't have too much cargo survive an explosion
9152 }
9153 }
9154
9155}
void exitStateMachineWithMessage:(NSString *message)
Definition AI.m:296

◆ rememberedShip

- (Entity *) rememberedShip

Definition at line 9593 of file ShipEntity.m.

9995{
9996 Entity *result = [_rememberedShip weakRefUnderlyingObject];
9997 if (result == nil || ![self isValidTarget:result])
9998 {
10000 return nil;
10001 }
10002 return result;
10003}
OOWeakReference * _rememberedShip
Definition ShipEntity.h:443

◆ removeAllDefenseTargets

- (void) removeAllDefenseTargets

Definition at line 9593 of file ShipEntity.m.

11226{
11227 [_defenseTargets removeAllObjects];
11228}

◆ removeAllEquipment

- (void) removeAllEquipment

Definition at line 2093 of file ShipEntity.m.

3898{
3899 [_equipment release];
3900 _equipment = nil;
3901}

◆ removeCargo:amount:

- (BOOL) removeCargo: (OOCommodityType) commodity
amount: (OOCargoQuantity) amount 

Definition at line 7619 of file ShipEntity.m.

8470 :(OOCommodityType)commodity amount:(OOCargoQuantity) amount
8471{
8472 OOCargoQuantity found = 0;
8473 ShipEntity *pod = nil;
8474 foreach (pod, cargo)
8475 {
8476 if ([[pod commodityType] isEqualToString:commodity])
8477 {
8478 found++;
8479 }
8480 }
8481 if (found < amount)
8482 {
8483 // don't remove any if there aren't enough to remove the full amount
8484 return NO;
8485 }
8486
8487 NSUInteger i = [cargo count] - 1;
8488 // iterate downwards to be safe removing during iteration
8489 while (amount > 0)
8490 {
8491 if ([[[cargo objectAtIndex:i] commodityType] isEqualToString:commodity])
8492 {
8493 amount--;
8494 [cargo removeObjectAtIndex:i];
8495 }
8496 // check above means array index can't underflow here
8497 i--;
8498 }
8499
8500 return YES;
8501}

◆ removeCollisionException:

- (void) removeCollisionException: (ShipEntity *) ship

Definition at line 9593 of file ShipEntity.m.

11139 :(ShipEntity *)ship
11140{
11142 {
11143 [_collisionExceptions removeObject:ship];
11144 }
11145}

Referenced by ShipRemoveCollisionException().

+ Here is the caller graph for this function:

◆ removeDefenseTarget:

- (void) removeDefenseTarget: (Entity *) target

Definition at line 9593 of file ShipEntity.m.

11231 :(Entity *)target
11232{
11233 [_defenseTargets removeObject:target];
11234}

◆ removeEquipmentItem:

- (void) removeEquipmentItem: (NSString *) equipmentKey

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3642 :(NSString *)equipmentKey
3643{
3644 NSString *equipmentTypeCheckKey = equipmentKey;
3645 NSString *lcEquipmentKey = [equipmentKey lowercaseString];
3646 NSUInteger equipmentIndex = NSNotFound;
3647 // determine the equipment type and make sure it works also in the case of damaged equipment
3648 if ([equipmentKey hasSuffix:@"_DAMAGED"])
3649 {
3650 equipmentTypeCheckKey = [equipmentKey substringToIndex:[equipmentKey length] - [@"_DAMAGED" length]];
3651 }
3652 OOEquipmentType *eqType = [OOEquipmentType equipmentTypeWithIdentifier:equipmentTypeCheckKey];
3653 if (eqType == nil) return;
3654
3655 if ([eqType isMissileOrMine] || ([self isThargoid] && ([lcEquipmentKey hasSuffix:@"thargon"] || [lcEquipmentKey hasPrefix:@"thargon"])))
3656 {
3657 [self removeExternalStore:eqType];
3658 }
3659 else
3660 {
3661 if ([_equipment containsObject:equipmentKey])
3662 {
3663 if (![equipmentKey isEqualToString:@"EQ_PASSENGER_BERTH"])
3664 {
3665 equipment_weight -= [eqType requiredCargoSpace]; // all other cases;
3666 }
3667
3668 if ([equipmentKey isEqualToString:@"EQ_CLOAKING_DEVICE"])
3669 {
3670 if ([self isCloaked]) [self setCloaked:NO];
3671 }
3672
3673 if (!isPlayer)
3674 {
3675 if([equipmentKey isEqualToString:@"EQ_SHIELD_BOOSTER"])
3676 {
3677 maxEnergy -= 256.0f;
3679 }
3680 else if([equipmentKey isEqualToString:@"EQ_SHIELD_ENHANCER"])
3681 {
3682 maxEnergy -= 256.0f;
3683 energy_recharge_rate /= 1.5;
3685 }
3686 else if ([equipmentKey isEqual:@"EQ_CARGO_BAY"])
3687 {
3689 }
3690 }
3691 }
3692
3693 if (![equipmentKey hasSuffix:@"_DAMAGED"] && ![eqType canCarryMultiple])
3694 {
3695 NSString *damagedKey = [equipmentKey stringByAppendingString:@"_DAMAGED"];
3696 if ([_equipment containsObject:damagedKey])
3697 {
3698 equipmentIndex = [_equipment indexOfObject:damagedKey];
3699 if (equipmentIndex != NSNotFound)
3700 {
3701 // remove damaged counterpart
3702 [_equipment removeObjectAtIndex:equipmentIndex];
3703 }
3704 equipment_weight -= [eqType requiredCargoSpace];
3705 }
3706 }
3707 equipmentIndex = [_equipment indexOfObject:equipmentKey];
3708 if (equipmentIndex != NSNotFound)
3709 {
3710 [_equipment removeObjectAtIndex:equipmentIndex];
3711 }
3712 // this event must come after the item is actually removed
3713 [self doScriptEvent:OOJSID("equipmentRemoved") withArgument:equipmentKey];
3714
3715 // if all docking computers are damaged while active
3716 if ([self isPlayer] && [self status] == STATUS_AUTOPILOT_ENGAGED && ![self hasDockingComputer])
3717 {
3718 [(PlayerEntity *)self disengageAutopilot];
3719 }
3720
3721
3722 if ([_equipment count] == 0) [self removeAllEquipment];
3723 }
3724}
BOOL hasDockingComputer()

Referenced by ShipRemoveEquipment(), and ShipSetEquipmentStatus().

+ Here is the caller graph for this function:

◆ removeExhaust:

- (void) removeExhaust: (OOExhaustPlumeEntity *) exhaust

Definition at line 7619 of file ShipEntity.m.

9506 :(OOExhaustPlumeEntity *)exhaust
9507{
9508 [subEntities removeObject:exhaust];
9509 [exhaust setOwner:nil];
9510}

Referenced by OOExhaustPlumeEntity(OOJavaScriptExtensions)::getJSClass:andPrototype:.

+ Here is the caller graph for this function:

◆ removeExternalStore:

- (BOOL) removeExternalStore: (OOEquipmentType *) eqType

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3727 :(OOEquipmentType *)eqType
3728{
3729 NSString *identifier = [eqType identifier];
3730 unsigned i;
3731
3732 for (i = 0; i < missiles; i++)
3733 {
3734 if ([[missile_list[i] identifier] isEqualTo:identifier])
3735 {
3736 // now 'delete' [i] by compacting the array
3737 while ( ++i < missiles ) missile_list[i - 1] = missile_list[i];
3738
3739 missiles--;
3740 return YES;
3741 }
3742 }
3743 return NO;
3744}

◆ removeFlasher:

- (void) removeFlasher: (OOFlasherEntity *) flasher

Definition at line 7619 of file ShipEntity.m.

9513 :(OOFlasherEntity *)flasher
9514{
9515 [subEntities removeObject:flasher];
9516 [flasher setOwner:nil];
9517}

◆ removeMissiles

- (OOCreditsQuantity) removeMissiles

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3905{
3906 missiles = 0;
3907 return 0;
3908}

Referenced by ShipAwardEquipment().

+ Here is the caller graph for this function:

◆ removeRole:

- (void) removeRole: (NSString *) role

Definition at line 6496 of file ShipEntity.m.

7288 :(NSString *)role
7289{
7290 if ([self hasRole:role])
7291 {
7292 OORoleSet *newRoles = [roleSet roleSetWithRemovedRole:role];
7293 if (newRoles != nil)
7294 {
7295 [roleSet release];
7296 roleSet = [newRoles retain];
7297 }
7298 }
7299}

◆ removeScript

- (void) removeScript

Definition at line 14954 of file ShipEntity.m.

1149{
1150 [script autorelease];
1151 script = nil;
1152}

Referenced by ShipRemove().

+ Here is the caller graph for this function:

◆ removeTarget:

- (void) removeTarget: (Entity *) targetEntity

Definition at line 9593 of file ShipEntity.m.

10073 :(Entity *) targetEntity
10074{
10075 if(targetEntity != nil) [self noteLostTarget];
10076 else DESTROY(_primaryTarget);
10077 // targetEntity == nil is currently only true for mounted player missiles.
10078 // we don't want to send lostTarget messages while the missile is mounted.
10079
10080 [[self shipSubEntityEnumerator] makeObjectsPerformSelector:@selector(removeTarget:) withObject:targetEntity];
10081}

◆ repeatString:times:

- (NSString *) repeatString: (NSString *) str
times: (NSUInteger) times 
implementation

Definition at line 14954 of file ShipEntity.m.

798 :(NSString *)str times:(NSUInteger)times
799{
800 if (times == 0) return @"";
801
802 NSMutableString *result = [NSMutableString stringWithCapacity:[str length] * times];
803
804 for (NSUInteger i = 0; i < times; i++)
805 {
806 [result appendString:str];
807 }
808
809 return result;
810}

◆ reportAIMessages

- (BOOL) reportAIMessages

◆ requestDockingCoordinates

- (void) requestDockingCoordinates

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

543{
544 /*- requests coordinates from the target station
545 if the target station can't be found
546 then use the nearest it can find (which may be a rock hermit) -*/
547
548 StationEntity *station = nil;
549 Entity *targStation = nil;
550 NSString *message = nil;
551 double distanceToStation2 = 0.0;
552
553 targStation = [self targetStation];
554 if ([targStation isStation])
555 {
556 station = (StationEntity*)targStation;
557 }
558 else
559 {
560 station = [UNIVERSE nearestShipMatchingPredicate:IsStationPredicate
561 parameter:nil
562 relativeToEntity:self];
563 }
564
565 distanceToStation2 = HPdistance2([station position], [self position]);
566
567 // Player check for being inside the aegis already exists in PlayerEntityControls. We just
568 // check here that distance to station is less than 2.5 times scanner range to avoid problems with
569 // NPC ships getting stuck with a dockingAI while just outside the aegis - Nikos 20090630, as proposed by Eric
570 // On very busy systems (> 50 docking ships) docking ships can be sent to a hold position outside the range,
571 // so also test for presence of dockingInstructions. - Eric 20091130
572 if (station != nil && (distanceToStation2 < SCANNER_MAX_RANGE2 * 6.25 || dockingInstructions != nil))
573 {
574 // remember the instructions
575 [dockingInstructions release];
576 dockingInstructions = [[station dockingInstructionsForShip:self] retain];
577 if (dockingInstructions != nil)
578 {
579 [self recallDockingInstructions];
580
581 message = [dockingInstructions objectForKey:@"ai_message"];
582 if (message != nil) [shipAI message:message];
583 message = [dockingInstructions objectForKey:@"comms_message"];
584 if (message != nil) [station sendExpandedMessage:message toShip:self];
585 }
586 }
587 else
588 {
589 DESTROY(dockingInstructions);
590 }
591
592 if (dockingInstructions == nil)
593 {
594 [shipAI message:@"NO_STATION_FOUND"];
595 }
596}

◆ requestNewTarget

- (void) requestNewTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ rescaleBy:

- (void) rescaleBy: (GLfloat) factor
implementation

Reimplemented from <OOSubEntity>.

Provided by category ShipEntity(Private).

Definition at line 7619 of file ShipEntity.m.

9043 :(GLfloat)factor
9044{
9045 [self rescaleBy:factor writeToCache:YES];
9046}

◆ rescaleBy:writeToCache:

- (void) rescaleBy: (GLfloat) factor
writeToCache: (BOOL) writeToCache 
implementation

Reimplemented from <OOSubEntity>.

Provided by category ShipEntity(Private).

Definition at line 7619 of file ShipEntity.m.

9049 :(GLfloat)factor writeToCache:(BOOL)writeToCache
9050{
9051 _scaleFactor *= factor;
9052 OOMesh *mesh = nil;
9053
9054 NSDictionary *shipDict = [self shipInfoDictionary];
9055 NSString *modelName = [shipDict oo_stringForKey:@"model"];
9056 if (modelName != nil)
9057 {
9058 mesh = [OOMesh meshWithName:modelName
9059 cacheKey:[NSString stringWithFormat:@"%@-%.3f",_shipKey,_scaleFactor]
9060 materialDictionary:[shipDict oo_dictionaryForKey:@"materials"]
9061 shadersDictionary:[shipDict oo_dictionaryForKey:@"shaders"]
9062 smooth:[shipDict oo_boolForKey:@"smooth" defaultValue:NO]
9063 shaderMacros:OODefaultShipShaderMacros()
9065 scaleFactor:factor
9066 cacheWriteable:writeToCache];
9067
9068 if (mesh == nil) return;
9069 [self setMesh:mesh];
9070 }
9071
9072 // rescale subentities
9074 foreach (se, [self subEntities])
9075 {
9076 [se setPosition:HPvector_multiply_scalar([se position], factor)];
9077 [se rescaleBy:factor writeToCache:writeToCache];
9078 }
9079
9080 // rescale mass
9081 mass *= factor * factor * factor;
9082}
instancetype meshWithName:cacheKey:materialDictionary:shadersDictionary:smooth:shaderMacros:shaderBindingTarget:scaleFactor:cacheWriteable:(NSString *name,[cacheKey] NSString *cacheKey,[materialDictionary] NSDictionary *materialDict,[shadersDictionary] NSDictionary *shadersDict,[smooth] BOOL smooth,[shaderMacros] NSDictionary *macros,[shaderBindingTarget] id< OOWeakReferenceSupport > object,[scaleFactor] float factor,[cacheWriteable] BOOL cacheWriteable)
Definition OOMesh.m:252
OOMesh * mesh()

◆ resetExhaustPlumes

- (void) resetExhaustPlumes

Definition at line 9593 of file ShipEntity.m.

9801{
9802 NSEnumerator *exEnum = nil;
9803 OOExhaustPlumeEntity *exEnt = nil;
9804
9805 for (exEnum = [self exhaustEnumerator]; (exEnt = [exEnum nextObject]); )
9806 {
9807 [exEnt resetPlume];
9808 }
9809}

◆ resetShotTime

- (void) resetShotTime

Definition at line 9593 of file ShipEntity.m.

11639{
11640 shot_time = 0.0;
11641}

◆ respondToAttackFrom:becauseOf:

- (void) respondToAttackFrom: (Entity *) from
becauseOf: (Entity *) other 

Definition at line 2093 of file ShipEntity.m.

2960 :(Entity *)from becauseOf:(Entity *)other
2961{
2962 Entity *source = nil;
2963
2964 if ([other isKindOfClass:[ShipEntity class]])
2965 {
2966 source = other;
2967
2968 // JSAIs handle friendly fire themselves
2969 if (![self hasNewAI])
2970 {
2971
2972 ShipEntity *hunter = (ShipEntity *)other;
2973 //if we are in the same group, then we have to be careful about how we handle things
2974 if ([self isPolice] && [hunter isPolice])
2975 {
2976 //police never get into a fight with each other
2977 return;
2978 }
2979
2980 OOShipGroup *group = [self group];
2981
2982 if (group != nil && group == [hunter group])
2983 {
2984 //we are in the same group, do we forgive you?
2985 //criminals are less likely to forgive
2986 if (randf() < (0.8 - (bounty/100)))
2987 {
2988 //it was an honest mistake, lets get on with it
2989 return;
2990 }
2991
2992 ShipEntity *groupLeader = [group leader];
2993 if (hunter == groupLeader)
2994 {
2995 //oops we were attacked by our leader, desert him
2996 [group removeShip:self];
2997 }
2998 else
2999 {
3000 //evict them from our group
3001 [group removeShip:hunter];
3002
3003 [groupLeader setFoundTarget:other];
3004 [groupLeader setPrimaryAggressor:hunter];
3005 [groupLeader respondToAttackFrom:from becauseOf:other];
3006 }
3007 }
3008 }
3009 }
3010 else
3011 {
3012 source = from;
3013 }
3014
3015 [self doScriptEvent:OOJSID("shipBeingAttacked") withArgument:source andReactToAIMessage:@"ATTACKED"];
3016 if ([source isShip]) [(ShipEntity *)source doScriptEvent:OOJSID("shipAttackedOther") withArgument:self];
3017}
void respondToAttackFrom:becauseOf:(Entity *from,[becauseOf] Entity *other)

◆ resumePostProximityAlert

- (void) resumePostProximityAlert

Definition at line 6496 of file ShipEntity.m.

6875{
6876 if (!previousCondition) return;
6877
6878 behaviour = [previousCondition oo_intForKey:@"behaviour"];
6879 [_primaryTarget release];
6880 _primaryTarget = [[previousCondition objectForKey:@"primaryTarget"] weakRetain];
6881 [self startTrackingCurve];
6882 desired_range = [previousCondition oo_floatForKey:@"desired_range"];
6883 desired_speed = [previousCondition oo_floatForKey:@"desired_speed"];
6884 _destination = [previousCondition oo_hpvectorForKey:@"destination"];
6885
6886 [previousCondition release];
6888 frustration = 0.0;
6889
6891
6892 //[shipAI message:@"RESTART_DOCKING"]; // if docking, start over, other AIs will ignore this message
6893}

◆ rightVector

- (Vector) rightVector

Definition at line 14954 of file ShipEntity.m.

1284{
1285 return v_right;
1286}

◆ roleSet

- (OORoleSet *) roleSet

◆ rollD:

- (void) rollD: (NSString *) die_number
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2267 :(NSString *)die_number
2268{
2269 int die_sides = [die_number intValue];
2270 if (die_sides > 0)
2271 {
2272 int die_roll = 1 + (ranrot_rand() % die_sides);
2273 NSString* result = [NSString stringWithFormat:@"ROLL_%d", die_roll];
2274 [shipAI reactToMessage:result context:@"rollD:"];
2275 }
2276 else
2277 {
2278 OOLog(@"ai.rollD.invalidValue", @"***** ERROR: invalid value supplied to rollD: '%@'.", die_number);
2279 }
2280}

◆ rollToMatchUp:rotating:

- (GLfloat) rollToMatchUp: (Vector) up_vec
rotating: (GLfloat) match_roll 

Definition at line 9593 of file ShipEntity.m.

11082 :(Vector)up_vec rotating:(GLfloat)match_roll
11083{
11084 GLfloat cosTheta = dot_product(up_vec, v_up); // == cos of angle between up vectors
11085 GLfloat sinTheta = dot_product(up_vec, v_right);
11086
11087 if (!isPlayer)
11088 {
11089 match_roll = -match_roll; // make necessary corrections for a different viewpoint
11090 sinTheta = -sinTheta;
11091 }
11092
11093 if (cosTheta < 0.0f)
11094 {
11095 cosTheta = -cosTheta;
11096 sinTheta = -sinTheta;
11097 }
11098
11099 if (sinTheta > 0.0f)
11100 {
11101 // increase roll rate
11102 return cosTheta * cosTheta * match_roll + sinTheta * sinTheta * max_flight_roll;
11103 }
11104 else
11105 {
11106 // decrease roll rate
11107 return cosTheta * cosTheta * match_roll - sinTheta * sinTheta * max_flight_roll;
11108 }
11109}

◆ safeScriptActionOnTarget:

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

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2601 :(NSString *)action
2602{
2603 PlayerEntity *player = PLAYER;
2604 ShipEntity *targEnt = [self primaryTarget];
2605 ShipEntity *oldTarget = nil;
2606
2607 if ([targEnt isShip])
2608 {
2609 oldTarget = [player scriptTarget];
2610 [player setScriptTarget:(ShipEntity*)targEnt];
2611 [player runUnsanitizedScriptActions:[NSArray arrayWithObject:action]
2613 withContextName:[NSString stringWithFormat:@"<AI \"%@\" state %@ - safeScriptActionOnTarget:>", [[self getAI] name], [[self getAI] state]]
2614 forTarget:targEnt];
2615 [player setScriptTarget:oldTarget];
2616 }
2617}
void runUnsanitizedScriptActions:allowingAIMethods:withContextName:forTarget:(NSArray *unsanitizedActions,[allowingAIMethods] BOOL allowAIMethods,[withContextName] NSString *contextName,[forTarget] ShipEntity *target)
void setScriptTarget:(ShipEntity *ship)

◆ savedShipDictionaryWithContext:

- (NSDictionary *) savedShipDictionaryWithContext: (NSMutableDictionary *) context

Provided by category ShipEntity(LoadRestore).

Definition at line 365 of file ShipEntityLoadRestore.m.

79 :(NSMutableDictionary *)context
80{
81 NSMutableDictionary *result = [NSMutableDictionary dictionary];
82 if (context == nil) context = [NSMutableDictionary dictionary];
83
84 [result setObject:_shipKey forKey:KEY_SHIP_KEY];
85
86 NSMutableDictionary *updatedShipInfo = [NSMutableDictionary dictionaryWithDictionary:shipinfoDictionary];
87
88 [updatedShipInfo setObject:[[self roleSet] roleString] forKey:KEY_ROLES];
89 [updatedShipInfo oo_setUnsignedInteger:fuel forKey:KEY_FUEL];
90 [updatedShipInfo oo_setUnsignedLongLong:bounty forKey:KEY_BOUNTY];
91 [updatedShipInfo setObject:OOStringFromWeaponType(forward_weapon_type) forKey:KEY_FORWARD_WEAPON];
92 [updatedShipInfo setObject:OOStringFromWeaponType(aft_weapon_type) forKey:KEY_AFT_WEAPON];
93 [updatedShipInfo setObject:OOStringFromScanClass(scanClass) forKey:KEY_SCAN_CLASS];
94
95 NSArray *deletes = nil;
96 [self simplifyShipdata:updatedShipInfo andGetDeletes:&deletes];
97
98 [result setObject:updatedShipInfo forKey:KEY_SHIPDATA_OVERRIDES];
99 if (deletes != nil) [result setObject:deletes forKey:KEY_SHIPDATA_DELETES];
100
101 if (!HPvector_equal([self position], kZeroHPVector))
102 {
103 [result oo_setHPVector:[self position] forKey:KEY_POSITION];
104 }
105 if (!quaternion_equal([self normalOrientation], kIdentityQuaternion))
106 {
107 [result oo_setQuaternion:[self normalOrientation] forKey:KEY_ORIENTATION];
108 }
109
110 if (energy != maxEnergy) [result oo_setFloat:energy / maxEnergy forKey:KEY_ENERGY_LEVEL];
111
112 [result setObject:[self primaryRole] forKey:KEY_PRIMARY_ROLE];
113
114 // Add equipment.
115 NSArray *equipment = [[self equipmentEnumerator] allObjects];
116 if ([equipment count] != 0) [result setObject:equipment forKey:KEY_EQUIPMENT];
117
118 // Add missiles.
119 if (missiles > 0)
120 {
121 NSMutableArray *missileArray = [NSMutableArray array];
122 unsigned i;
123 for (i = 0; i < missiles; i++)
124 {
125 NSString *missileType = [missile_list[i] identifier];
126 if (missileType != nil) [missileArray addObject:missileType];
127 }
128 [result setObject:missileArray forKey:KEY_MISSILES];
129 }
130
131 // Add groups.
132 if (_group != nil)
133 {
134 [result oo_setUnsignedInteger:GroupIDForGroup(_group, context) forKey:KEY_GROUP_ID];
135 if ([_group leader] == self) [result oo_setBool:YES forKey:KEY_IS_GROUP_LEADER];
136 NSString *groupName = [_group name];
137 if (groupName != nil)
138 {
139 [result setObject:groupName forKey:KEY_GROUP_NAME];
140 }
141 }
142 if (_escortGroup != nil)
143 {
144 [result oo_setUnsignedInteger:GroupIDForGroup(_escortGroup, context) forKey:KEY_ESCORT_GROUP_ID];
145 }
146 /* Eric:
147 The escortGroup property is removed from the lead ship, on entering witchspace.
148 But it is needed in the save file to correctly restore an escorted group.
149 */
150 else if (_group != nil && [_group leader] == self)
151 {
152 [result oo_setUnsignedInteger:GroupIDForGroup(_group, context) forKey:KEY_ESCORT_GROUP_ID];
153 }
154
155 // FIXME: AI.
156 // Eric: I think storing the AI name should be enough. On entering a wormhole, the stack is cleared so there are no preserved AI states.
157 // Also the AI restarts itself with the GLOBAL state, so no need to store any old state.
158 if ([[[self getAI] name] isEqualToString:@"nullAI.plist"])
159 {
160 // might be a JS version
161 [result setObject:[[self getAI] associatedJS] forKey:KEY_AI];
162 // if there isn't, loading nullAI.js will load nullAI.plist anyway
163 }
164 else
165 {
166 [result setObject:[[self getAI] name] forKey:KEY_AI];
167 }
168
169 return result;
170}

◆ scanClass

- (OOScanClass) scanClass
implementation

Reimplemented from Entity.

Definition at line 14954 of file ShipEntity.m.

2064{
2065 if (cloaking_device_active) return CLASS_NO_DRAW;
2066 return scanClass;
2067}

◆ scanDescription

- (NSString *) scanDescription

Definition at line 6496 of file ShipEntity.m.

7166{
7167 if (scan_description != nil)
7168 {
7169 return scan_description;
7170 }
7171 else
7172 {
7173 NSString *desc = nil;
7174 switch ([self scanClass])
7175 {
7176 case CLASS_NEUTRAL:
7177 {
7178 int legal = [self legalStatus];
7179 int legal_i = 0;
7180 if (legal > 0)
7181 {
7182 legal_i = (legal <= 50) ? 1 : 2;
7183 }
7184 desc = [[[UNIVERSE descriptions] oo_arrayForKey:@"legal_status"] oo_stringAtIndex:legal_i];
7185 }
7186 break;
7187
7188 case CLASS_THARGOID:
7189 desc = DESC(@"legal-desc-alien");
7190 break;
7191
7192 case CLASS_POLICE:
7193 desc = DESC(@"legal-desc-system-vessel");
7194 break;
7195
7196 case CLASS_MILITARY:
7197 desc = DESC(@"legal-desc-military-vessel");
7198 break;
7199
7200 default:
7201 break;
7202 }
7203 return desc;
7204 }
7205}

Referenced by HeadUpDisplay::hudDrawReticleOnTarget.

+ Here is the caller graph for this function:

◆ scanDescriptionForScripting

- (NSString *) scanDescriptionForScripting

Definition at line 6496 of file ShipEntity.m.

7160{
7161 return scan_description;
7162}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ scanForFormationLeader

- (void) scanForFormationLeader
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForHostiles

- (void) scanForHostiles

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

315{
316 /*-- Locates all the ships in range targeting the receiver and chooses the nearest --*/
317 DESTROY(_foundTarget);
318
319 [self checkScanner];
320 unsigned i;
321 GLfloat found_d2 = scannerRange * scannerRange;
322 for (i = 0; i < n_scanned_ships ; i++)
323 {
324 ShipEntity *thing = scanned_ships[i];
325 GLfloat d2 = distance2_scanned_ships[i];
326 if ((d2 < found_d2)
327 && ([thing isThargoid] || (([thing primaryTarget] == self) && [thing hasHostileTarget]) || [thing isDefenseTarget:self])
328 && ![thing isCloaked])
329 {
330 [self setFoundTarget:thing];
331 found_d2 = d2;
332 }
333 }
334
335 [self checkFoundTarget];
336}

◆ scanForLoot

- (void) scanForLoot
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForNearestIncomingMissile

- (void) scanForNearestIncomingMissile

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

625{
627 {
628 HasScanClassPredicate, [NSNumber numberWithInt:CLASS_MISSILE],
630 };
631 [self scanForNearestShipWithPredicate:ANDPredicate parameter:&param];
632}
BOOL HasScanClassPredicate(Entity *entity, void *parameter)
BOOL IsHostileAgainstTargetPredicate(Entity *ship, void *parameter)

◆ scanForNearestMerchantman

- (void) scanForNearestMerchantman
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForNearestShipHavingAnyRole:

- (void) scanForNearestShipHavingAnyRole: (NSString *) scanRoles
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2302 :(NSString *)scanRoles
2303{
2304 NSSet *set = [NSSet setWithArray:ScanTokensFromString(scanRoles)];
2305 [self scanForNearestShipWithPredicate:HasRoleInSetPredicate parameter:set];
2306}

◆ scanForNearestShipHavingRole:

- (void) scanForNearestShipHavingRole: (NSString *) scanRole
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2289 :(NSString *)scanRole
2290{
2291 [self scanForNearestShipWithPredicate:HasRolePredicate parameter:scanRole];
2292}

◆ scanForNearestShipMatchingPredicate:

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

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForNearestShipNotHavingAnyRole:

- (void) scanForNearestShipNotHavingAnyRole: (NSString *) scanRoles
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2335 :(NSString *)scanRoles
2336{
2337 NSSet *set = [NSSet setWithArray:ScanTokensFromString(scanRoles)];
2338 [self scanForNearestShipWithNegatedPredicate:HasRoleInSetPredicate parameter:set];
2339}

◆ scanForNearestShipNotHavingRole:

- (void) scanForNearestShipNotHavingRole: (NSString *) scanRole
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2322 :(NSString *)scanRole
2323{
2324 [self scanForNearestShipWithNegatedPredicate:HasRolePredicate parameter:scanRole];
2325}

◆ scanForNearestShipWithAnyPrimaryRole:

- (void) scanForNearestShipWithAnyPrimaryRole: (NSString *) scanRoles
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForNearestShipWithNegatedPredicate:parameter:

- (void) scanForNearestShipWithNegatedPredicate: (EntityFilterPredicate) predicate
parameter: (void *) parameter 
implementation

Provided by category ShipEntity(OOAIPrivate).

Definition at line 1 of file ShipEntityAI.m.

2877 :(EntityFilterPredicate)predicate parameter:(void *)parameter
2878{
2879 ChainedEntityPredicateParameter param = { predicate, parameter };
2880 [self scanForNearestShipWithPredicate:NOTPredicate parameter:&param];
2881}
BOOL(* EntityFilterPredicate)(Entity *entity, void *parameter)
Definition Universe.h:52

◆ scanForNearestShipWithoutAnyPrimaryRole:

- (void) scanForNearestShipWithoutAnyPrimaryRole: (NSString *) scanRoles
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForNearestShipWithoutPrimaryRole:

- (void) scanForNearestShipWithoutPrimaryRole: (NSString *) scanRole
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForNearestShipWithoutScanClass:

- (void) scanForNearestShipWithoutScanClass: (NSString *) scanScanClass
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2342 :(NSString *)scanScanClass
2343{
2344 NSNumber *parameter = [NSNumber numberWithInt:OOScanClassFromString(scanScanClass)];
2345 [self scanForNearestShipWithNegatedPredicate:HasScanClassPredicate parameter:parameter];
2346}

◆ scanForNearestShipWithPredicate:parameter:

- (void) scanForNearestShipWithPredicate: (EntityFilterPredicate) predicate
parameter: (void *) parameter 
implementation

Provided by category ShipEntity(OOAIPrivate).

Definition at line 1 of file ShipEntityAI.m.

2849 :(EntityFilterPredicate)predicate parameter:(void *)parameter
2850{
2851 // Locates all the ships in range for which predicate returns YES, and chooses the nearest.
2852 unsigned i;
2853 ShipEntity *candidate;
2854 float d2, found_d2 = scannerRange * scannerRange;
2855
2856 DESTROY(_foundTarget);
2857 [self checkScanner];
2858
2859 if (predicate == NULL) return;
2860
2861 for (i = 0; i < n_scanned_ships ; i++)
2862 {
2863 candidate = scanned_ships[i];
2864 d2 = distance2_scanned_ships[i];
2865 if ((d2 < found_d2) && (candidate->scanClass != CLASS_CARGO) && ([candidate status] != STATUS_DOCKED)
2866 && predicate(candidate, parameter) && ![candidate isCloaked])
2867 {
2868 [self setFoundTarget:candidate];
2869 found_d2 = d2;
2870 }
2871 }
2872
2873 [self checkFoundTarget];
2874}

◆ scanForNearestShipWithPrimaryRole:

- (void) scanForNearestShipWithPrimaryRole: (NSString *) scanRole
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForNearestShipWithScanClass:

- (void) scanForNearestShipWithScanClass: (NSString *) scanScanClass
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2309 :(NSString *)scanScanClass
2310{
2311 NSNumber *parameter = [NSNumber numberWithInt:OOScanClassFromString(scanScanClass)];
2312 [self scanForNearestShipWithPredicate:HasScanClassPredicate parameter:parameter];
2313}

◆ scanForNonThargoid

- (void) scanForNonThargoid
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForOffenders

- (void) scanForOffenders
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForRandomLoot

- (void) scanForRandomLoot
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForRandomMerchantman

- (void) scanForRandomMerchantman
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForRocks

- (void) scanForRocks
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ scanForThargoid

- (void) scanForThargoid
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1693{
1694 return [self scanForNearestShipWithPrimaryRole:@"thargoid"];
1695}

◆ scannedShips

- (ShipEntity **) scannedShips

Definition at line 9593 of file ShipEntity.m.

9906{
9907 scanned_ships[n_scanned_ships] = nil; // terminate array
9908 return scanned_ships;
9909}

◆ scannerDisplayColor1

- (OOColor *) scannerDisplayColor1

Definition at line 6496 of file ShipEntity.m.

6629{
6630 return [[scanner_display_color1 retain] autorelease];
6631}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ scannerDisplayColor2

- (OOColor *) scannerDisplayColor2

Definition at line 6496 of file ShipEntity.m.

6635{
6636 return [[scanner_display_color2 retain] autorelease];
6637}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ scannerDisplayColorForShip:otherShip:isHostile:flash:scannerDisplayColor1:scannerDisplayColor2:scannerDisplayColorH1:

- (GLfloat *) scannerDisplayColorForShip: (ShipEntity*)
otherShip: (BOOL)
isHostile: (BOOL)
flash: (OOColor *)
scannerDisplayColor1: (OOColor *)
scannerDisplayColor2: (OOColor *)
scannerDisplayColorH1: (OOColor *) scannerDisplayColorH2 

Definition at line 6496 of file ShipEntity.m.

6498 :(ShipEntity*)otherShip :(BOOL)isHostile :(BOOL)flash :(OOColor *)scannerDisplayColor1 :(OOColor *)scannerDisplayColor2 :(OOColor *)scannerDisplayColorH1 :(OOColor *)scannerDisplayColorH2
6499{
6500 if (isHostile)
6501 {
6502 /* if there are any scripted scanner hostile display colours
6503 * for the ship, use them - otherwise fall through to the
6504 * normal scripted colours, then the scan class colours */
6505 if (scannerDisplayColorH1 || scannerDisplayColorH2)
6506 {
6507 if (scannerDisplayColorH1 && !scannerDisplayColorH2)
6508 {
6509 [scannerDisplayColorH1 getRed:&scripted_color[0] green:&scripted_color[1] blue:&scripted_color[2] alpha:&scripted_color[3]];
6510 }
6511
6512 if (!scannerDisplayColorH1 && scannerDisplayColorH2)
6513 {
6514 [scannerDisplayColorH2 getRed:&scripted_color[0] green:&scripted_color[1] blue:&scripted_color[2] alpha:&scripted_color[3]];
6515 }
6516
6517 if (scannerDisplayColorH1 && scannerDisplayColorH2)
6518 {
6519 if (flash)
6520 [scannerDisplayColorH1 getRed:&scripted_color[0] green:&scripted_color[1] blue:&scripted_color[2] alpha:&scripted_color[3]];
6521 else
6522 [scannerDisplayColorH2 getRed:&scripted_color[0] green:&scripted_color[1] blue:&scripted_color[2] alpha:&scripted_color[3]];
6523 }
6524
6525 return scripted_color;
6526 }
6527 }
6528
6529 // if there are any scripted scanner display colors for the ship, use them
6531 {
6533 {
6534 [scannerDisplayColor1 getRed:&scripted_color[0] green:&scripted_color[1] blue:&scripted_color[2] alpha:&scripted_color[3]];
6535 }
6536
6538 {
6539 [scannerDisplayColor2 getRed:&scripted_color[0] green:&scripted_color[1] blue:&scripted_color[2] alpha:&scripted_color[3]];
6540 }
6541
6543 {
6544 if (flash)
6545 [scannerDisplayColor1 getRed:&scripted_color[0] green:&scripted_color[1] blue:&scripted_color[2] alpha:&scripted_color[3]];
6546 else
6547 [scannerDisplayColor2 getRed:&scripted_color[0] green:&scripted_color[1] blue:&scripted_color[2] alpha:&scripted_color[3]];
6548 }
6549
6550 return scripted_color;
6551 }
6552
6553 // no scripted scanner display colors defined, proceed as per standard
6554 if ([self isJammingScanning])
6555 {
6556 if (![otherShip hasMilitaryScannerFilter])
6557 return jammed_color;
6558 else
6559 {
6560 if (flash)
6561 return mascem_color1;
6562 else
6563 {
6564 if (isHostile)
6565 return hostile_color;
6566 else
6567 return mascem_color2;
6568 }
6569 }
6570 }
6571
6572 switch (scanClass)
6573 {
6574 case CLASS_ROCK :
6575 case CLASS_CARGO :
6576 return cargo_color;
6577 case CLASS_THARGOID :
6578 if (flash)
6579 return hostile_color;
6580 else
6581 return friendly_color;
6582 case CLASS_MISSILE :
6583 return missile_color;
6584 case CLASS_STATION :
6585 return friendly_color;
6586 case CLASS_BUOY :
6587 if (flash)
6588 return friendly_color;
6589 else
6590 return neutral_color;
6591 case CLASS_POLICE :
6592 case CLASS_MILITARY :
6593 if ((isHostile)&&(flash))
6594 return police_color2;
6595 else
6596 return police_color1;
6597 case CLASS_MINE :
6598 if (flash)
6599 return neutral_color;
6600 else
6601 return hostile_color;
6602 default :
6603 if (isHostile)
6604 return hostile_color;
6605 }
6606 return neutral_color;
6607}
static GLfloat scripted_color[4]
static GLfloat mascem_color1[4]
static GLfloat neutral_color[4]
static GLfloat cargo_color[4]
static GLfloat hostile_color[4]
static GLfloat missile_color[4]
static GLfloat police_color1[4]
static GLfloat mascem_color2[4]
static GLfloat jammed_color[4]
static GLfloat friendly_color[4]
static GLfloat police_color2[4]
void getRed:green:blue:alpha:(float *red,[green] float *green,[blue] float *blue,[alpha] float *alpha)
Definition OOColor.m:368
OOColor * scannerDisplayColor2()
OOColor * scannerDisplayColor1()

◆ scannerDisplayColorHostile1

- (OOColor *) scannerDisplayColorHostile1

Definition at line 6496 of file ShipEntity.m.

6659{
6660 return [[scanner_display_color_hostile1 retain] autorelease];
6661}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ scannerDisplayColorHostile2

- (OOColor *) scannerDisplayColorHostile2

Definition at line 6496 of file ShipEntity.m.

6665{
6666 return [[scanner_display_color_hostile2 retain] autorelease];
6667}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ scannerRange

- (GLfloat) scannerRange

◆ scoopIn:

- (void) scoopIn: (ShipEntity *) other

Definition at line 9593 of file ShipEntity.m.

12907 :(ShipEntity *)other
12908{
12909 [other getTractoredBy:self];
12910}
void getTractoredBy:(ShipEntity *other)

◆ scoopUp:

- (void) scoopUp: (ShipEntity *) other

Definition at line 9593 of file ShipEntity.m.

12919 :(ShipEntity *)other
12920{
12921 [self scoopUpProcess:other processEvents:YES processMessages:YES];
12922}

◆ scoopUpProcess:processEvents:processMessages:

- (void) scoopUpProcess: (ShipEntity *) other
processEvents: (BOOL) proc_events
processMessages: (BOOL) proc_messages 

Definition at line 9593 of file ShipEntity.m.

12925 :(ShipEntity *)other processEvents:(BOOL) procEvents processMessages:(BOOL) procMessages
12926{
12927 if (other == nil) return;
12928
12929 OOCommodityType co_type = nil;
12930 OOCargoQuantity co_amount;
12931
12932 // don't even think of trying to scoop if the cargo hold is already full
12933 if (max_cargo && [cargo count] >= [self maxAvailableCargoSpace])
12934 {
12935 [other setStatus:STATUS_IN_FLIGHT];
12936 return;
12937 }
12938
12939 switch ([other cargoType])
12940 {
12941 case CARGO_RANDOM:
12942 co_type = [other commodityType];
12943 co_amount = [other commodityAmount];
12944 break;
12945
12947 {
12948 //scripting
12949 PlayerEntity *player = PLAYER;
12950 [player setScriptTarget:self];
12951 if (procEvents)
12952 {
12953 [other doScriptEvent:OOJSID("shipWasScooped") withArgument:self];
12954 }
12955
12956 if ([other commodityType] != nil)
12957 {
12958 co_type = [other commodityType];
12959 co_amount = [other commodityAmount];
12960 // don't show scoop message now, will happen later.
12961 }
12962 else
12963 {
12964 if (isPlayer && [other showScoopMessage] && procMessages)
12965 {
12966 [UNIVERSE clearPreviousMessage];
12967 NSString *shipName = [other displayName];
12968 [UNIVERSE addMessage:OOExpandKey(@"scripted-item-scooped", shipName) forCount:4];
12969 }
12970 [other setCommodityForPod:nil andAmount:0];
12971 co_amount = 0;
12972 co_type = nil;
12973 }
12974 }
12975 break;
12976
12977 default :
12978 co_amount = 0;
12979 co_type = nil;
12980 break;
12981 }
12982
12983 /* Bug: docking failed due to NSRangeException while looking for element
12984 NSNotFound of cargo mainfest in -[PlayerEntity unloadCargoPods].
12985 Analysis: bad cargo pods being generated due to
12986 -[Universe commodityForName:] looking in wrong place for names.
12987 Fix 1: fix -[Universe commodityForName:].
12988 Fix 2: catch NSNotFound here and substitute random cargo type.
12989 -- Ahruman 20070714
12990 */
12991 if (co_type == nil && co_amount > 0)
12992 {
12993 co_type = [UNIVERSE getRandomCommodity];
12994 co_amount = [UNIVERSE getRandomAmountOfCommodity:co_type];
12995 }
12996
12997 if (co_amount > 0)
12998 {
12999 [other setCommodity:co_type andAmount:co_amount]; // belt and braces setting this!
13001
13002 if (isPlayer)
13003 {
13004 if ([other crew])
13005 {
13006 if ([other showScoopMessage] && procMessages)
13007 {
13008 [UNIVERSE clearPreviousMessage];
13009 unsigned i;
13010 for (i = 0; i < [[other crew] count]; i++)
13011 {
13012 OOCharacter *rescuee = [[other crew] objectAtIndex:i];
13013 NSString *characterName = [rescuee name];
13014 if ([rescuee legalStatus])
13015 {
13016 [UNIVERSE addMessage:OOExpandKey(@"scoop-captured-character", characterName) forCount: 4.5];
13017 }
13018 else if ([rescuee insuranceCredits])
13019 {
13020 [UNIVERSE addMessage:OOExpandKey(@"scoop-rescued-character", characterName) forCount: 4.5];
13021 }
13022 else
13023 {
13024 [UNIVERSE addMessage: DESC(@"scoop-got-slave") forCount: 4.5];
13025 }
13026 }
13027 }
13028 if (procEvents)
13029 {
13030 [(PlayerEntity *)self playEscapePodScooped];
13031 }
13032 }
13033 else
13034 {
13035 if ([other showScoopMessage] && procMessages)
13036 {
13037 [UNIVERSE clearPreviousMessage];
13038 [UNIVERSE addMessage:[UNIVERSE describeCommodity:co_type amount:co_amount] forCount:4.5];
13039 }
13040 }
13041 }
13042 [cargo insertObject:other atIndex:0]; // places most recently scooped object at eject position
13043 [other setStatus:STATUS_IN_HOLD];
13044 [other performTumble];
13045 [shipAI message:@"CARGO_SCOOPED"];
13046 if (max_cargo && [cargo count] >= [self maxAvailableCargoSpace]) [shipAI message:@"HOLD_FULL"];
13047 }
13048 if (procEvents)
13049 {
13050 [self doScriptEvent:OOJSID("shipScoopedOther") withArgument:other]; // always fire, even without commodity.
13051 }
13052
13053 // if shipScoopedOther does something strange to the object, we must
13054 // then remove it from the hold, or it will be over-retained
13055 if ([other status] != STATUS_IN_HOLD)
13056 {
13057 if ([cargo containsObject:other])
13058 {
13059 [cargo removeObject:other];
13060 }
13061 }
13062
13063 [[other collisionArray] removeObject:self]; // so it can't be scooped twice!
13064 // make sure other ships trying to scoop it lose it
13065 // probably already happened, but some may have acquired it
13066 // after the scooping started, and they might get stuck in a scooping
13067 // attempt as a result
13068 [self checkScannerIgnoringUnpowered];
13069 unsigned i;
13070 ShipEntity *scooper;
13071 for (i = 0; i < n_scanned_ships ; i++)
13072 {
13073 scooper = (ShipEntity *)scanned_ships[i];
13074 if (self != scooper && (id) other == [scooper primaryTargetWithoutValidityCheck])
13075 {
13076 [scooper noteLostTarget];
13077 }
13078 }
13079
13080 [self suppressTargetLost];
13081 [UNIVERSE removeEntity:other];
13082}
@ CARGO_RANDOM
Definition OOTypes.h:75
@ CARGO_SCRIPTED_ITEM
Definition OOTypes.h:76
@ CARGO_FLAG_CANISTERS
Definition OOTypes.h:117
NSMutableArray * collisionArray()
Definition Entity.m:923
NSString * name()
void setStatus:(OOEntityStatus stat)
void performTumble()
void setCommodityForPod:andAmount:(OOCommodityType co_type,[andAmount] OOCargoQuantity co_amount)
BOOL showScoopMessage()

Referenced by ShipAddCargoEntity().

+ Here is the caller graph for this function:

◆ script

- (OOJSScript *) script

◆ scriptActionOnTarget:

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

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2567 :(NSString *)action
2568{
2569 PlayerEntity *player = PLAYER;
2570 ShipEntity *targEnt = [self primaryTarget];
2571 ShipEntity *oldTarget = nil;
2572
2573#ifndef NDEBUG
2574 static BOOL deprecationWarning = NO;
2575
2576 if (!deprecationWarning)
2577 {
2578 deprecationWarning = YES;
2579 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]);
2580 }
2581 else
2582 {
2583 OOLog(@"script.deprecated.scriptActionOnTarget.repeat", @"----- WARNING in AI %@: the AI method scriptActionOnTarget: is deprecated and should not be used.", [AI currentlyRunningAIDescription]);
2584 }
2585#endif
2586
2587 if ([targEnt isShip])
2588 {
2589 oldTarget = [player scriptTarget];
2590 [player setScriptTarget:(ShipEntity*)targEnt];
2591 [player runUnsanitizedScriptActions:[NSArray arrayWithObject:action]
2593 withContextName:[NSString stringWithFormat:@"<AI \"%@\" state %@ - scriptActionOnTarget:>", [[self getAI] name], [[self getAI] state]]
2594 forTarget:targEnt];
2595 [player checkScript]; // react immediately to any changes this makes
2596 [player setScriptTarget:oldTarget];
2597 }
2598}

◆ scriptedMisjump

- (BOOL) scriptedMisjump

Definition at line 14954 of file ShipEntity.m.

1290{
1291 return scripted_misjump;
1292}
unsigned scripted_misjump
Definition ShipEntity.h:278

◆ scriptedMisjumpRange

- (GLfloat) scriptedMisjumpRange

Definition at line 14954 of file ShipEntity.m.

1302{
1303 return _scriptedMisjumpRange;
1304}
GLfloat _scriptedMisjumpRange
Definition ShipEntity.h:284

◆ scriptInfo

- (NSDictionary *) scriptInfo

◆ selectMissile

- (OOEquipmentType *) selectMissile

Definition at line 2093 of file ShipEntity.m.

3839{
3840 OOEquipmentType *missileType = nil;
3841 NSString *role = nil;
3842 double chance = randf();
3843 BOOL thargoidMissile = NO;
3844
3845 if ([self isThargoid])
3846 {
3847 if (_missileRole != nil) missileType = [self verifiedMissileTypeFromRole:_missileRole];
3848 if (missileType == nil) {
3849 _missileRole = @"EQ_THARGON"; // no valid missile_role defined, use thargoid fallback from now on.
3850 missileType = [self verifiedMissileTypeFromRole:_missileRole];
3851 }
3852 }
3853 else
3854 {
3855 // All other ships: random role 10% of the cases when auto weapons is set, if a missile_role is defined.
3856 // Without auto weapons, never random.
3857 float randomSelectionChance = chance;
3858 if(![self hasAutoWeapons]) randomSelectionChance = 0.0f;
3859 if (randomSelectionChance < 0.9f && _missileRole != nil)
3860 {
3861 missileType = [self verifiedMissileTypeFromRole:_missileRole];
3862 }
3863
3864 if (missileType == nil) // the random 10% , or no valid missile_role defined
3865 {
3866 if (chance < 0.9f && _missileRole != nil) // no valid missile_role defined?
3867 {
3868 _missileRole = nil; // use generic ship fallback from now on.
3869 }
3870
3871 // assign random missiles 20% of the time without missile_role (or 10% with valid missile_role)
3872 if (chance > 0.8f) role = @"missile";
3873 // otherwise use the standard role
3874 else role = @"EQ_MISSILE";
3875
3876 missileType = [self verifiedMissileTypeFromRole:role];
3877 }
3878 }
3879
3880 if (missileType == nil) OOLogERR(@"ship.setUp.missiles", @"could not resolve missile / mine type for ship \"%@\". Original missile role:\"%@\".", [self name],_missileRole);
3881
3882 role = [[missileType identifier] lowercaseString];
3883 thargoidMissile = [self isThargoid] && ([role hasSuffix:@"thargon"] || [role hasPrefix:@"thargon"]);
3884
3885 if (thargoidMissile || (!thargoidMissile && [missileType isMissileOrMine]))
3886 {
3887 return missileType;
3888 }
3889 else
3890 {
3891 OOLogWARN(@"ship.setUp.missiles", @"missile_role \"%@\" is not a valid missile / mine type for ship \"%@\".%@", [missileType identifier] , [self name],@" No missile selected.");
3892 return nil;
3893 }
3894}
BOOL hasAutoWeapons()
NSString * _missileRole
Definition ShipEntity.h:321

Referenced by ShipSelectNewMissile().

+ Here is the caller graph for this function:

◆ sendAIMessage:

- (void) sendAIMessage: (NSString *) message

Definition at line 14073 of file ShipEntity.m.

14723 :(NSString *)message
14724{
14725 [shipAI message:message];
14726}

Referenced by ShipSendAIMessage().

+ Here is the caller graph for this function:

◆ sendExpandedMessage:toShip:

- (void) sendExpandedMessage: (NSString *) message_text
toShip: (ShipEntity*) other_ship 

Definition at line 14073 of file ShipEntity.m.

14151 :(NSString *)message_text toShip:(ShipEntity *)other_ship
14152{
14153 if (!other_ship || !crew)
14154 return; // nobody to receive or send the signal
14155 if ((lastRadioMessage) && (messageTime > 0.0) && [message_text isEqual:lastRadioMessage])
14156 return; // don't send the same message too often
14157 [lastRadioMessage autorelease];
14158 lastRadioMessage = [message_text retain];
14159
14160 double d2 = HPdistance2(position, [other_ship position]);
14161 if (d2 > scannerRange * scannerRange)
14162 {
14163 // out of comms range
14164 return;
14165 }
14166
14167 Random_Seed very_random_seed;
14168 very_random_seed.a = rand() & 255;
14169 very_random_seed.b = rand() & 255;
14170 very_random_seed.c = rand() & 255;
14171 very_random_seed.d = rand() & 255;
14172 very_random_seed.e = rand() & 255;
14173 very_random_seed.f = rand() & 255;
14174 seed_RNG_only_for_planet_description(very_random_seed);
14175
14176 NSDictionary *specials = [NSDictionary dictionaryWithObjectsAndKeys:
14177 [self displayName], @"[self:name]",
14178 [other_ship identFromShip: self], @"[target:name]",
14179 nil];
14180 NSString *expandedMessage = OOExpandDescriptionString(OOStringExpanderDefaultRandomSeed(), message_text, specials, nil, nil, kOOExpandNoOptions);
14181
14182 [self sendMessage:expandedMessage toShip:other_ship withUnpilotedOverride:NO];
14183}
@ kOOExpandNoOptions
Random_Seed OOStringExpanderDefaultRandomSeed(void)
NSString * OOExpandDescriptionString(Random_Seed seed, NSString *string, NSDictionary *overrides, NSDictionary *legacyLocals, NSString *systemName, OOExpandOptions options)
NSString * identFromShip:(ShipEntity *otherShip)

◆ sendMessage:toShip:withUnpilotedOverride:

- (void) sendMessage: (NSString *) message_text
toShip: (ShipEntity*) other_ship
withUnpilotedOverride: (BOOL) unpilotedOverride 

Definition at line 14073 of file ShipEntity.m.

14128 :(NSString *) message_text toShip:(ShipEntity*) other_ship withUnpilotedOverride:(BOOL)unpilotedOverride
14129{
14130 if (!other_ship || !message_text) return;
14131 if (!crew && !unpilotedOverride) return;
14132
14133 double d2 = HPdistance2(position, [other_ship position]);
14134 if (d2 > scannerRange * scannerRange)
14135 return; // out of comms range
14136
14137 NSString *expandedMessage = OOExpand(message_text); // consistent with broadcast message.
14138
14139 if (other_ship->isPlayer)
14140 {
14141 [self setCommsMessageColor];
14142 [(PlayerEntity *)other_ship receiveCommsMessage:expandedMessage from:self];
14143 messageTime = 6.0;
14144 [UNIVERSE resetCommsLogColor];
14145 }
14146 else
14147 [other_ship receiveCommsMessage:expandedMessage from:self];
14148}
void receiveCommsMessage:from:(NSString *message_text,[from] ShipEntity *other)

Referenced by ShipCommsMessage().

+ Here is the caller graph for this function:

◆ sendScriptMessage:

- (void) sendScriptMessage: (NSString *) message
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2621 :(NSString *)message
2622{
2623 NSArray *components = ScanTokensFromString(message);
2624
2625 if ([components count] == 1)
2626 {
2627 [self doScriptEvent:OOJSIDFromString(message)];
2628 }
2629 else
2630 {
2631 NSString *function = [components objectAtIndex:0];
2632 components = [components subarrayWithRange:NSMakeRange(1, [components count] - 1)];
2633 [self doScriptEvent:OOJSIDFromString(function) withArgument:components];
2634 }
2635}

◆ sendTargetCommsMessage:

- (void) sendTargetCommsMessage: (NSString *) message
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2085 :(NSString*) message
2086{
2087 ShipEntity *ship = [self primaryTarget];
2088 if ((ship == nil) || ([ship status] == STATUS_DEAD) || ([ship status] == STATUS_DOCKED))
2089 {
2090 [self noteLostTarget];
2091 return;
2092 }
2093 [self sendExpandedMessage:message toShip:[self primaryTarget]];
2094}

◆ serializeShipSubEntities

- (NSString *) serializeShipSubEntities

Definition at line 14954 of file ShipEntity.m.

814{
815 NSMutableString *result = [NSMutableString stringWithCapacity:4];
816 NSEnumerator *subEnum = nil;
817 ShipEntity *se = nil;
818 NSUInteger diff, i = 0;
819
820 for (subEnum = [self shipSubEntityEnumerator]; (se = [subEnum nextObject]); )
821 {
822 diff = [se subIdx] - i;
823 i += diff + 1;
824 [result appendString:[self repeatString:@"0" times:diff]];
825 [result appendString:@"1"];
826 }
827 // add trailing zeroes
828 [result appendString:[self repeatString:@"0" times:[self maxShipSubEntities] - i]];
829 return result;
830}

◆ setAccuracy:

- (void) setAccuracy: (GLfloat) new_accuracy

Definition at line 14954 of file ShipEntity.m.

1223 :(GLfloat) new_accuracy
1224{
1225 if (new_accuracy < 0.0f && scanClass == CLASS_MISSILE)
1226 {
1227 new_accuracy = 0.0;
1228 }
1229 else if (new_accuracy < -5.0f)
1230 {
1231 new_accuracy = -5.0;
1232 }
1233 else if (new_accuracy > 10.0f)
1234 {
1235 new_accuracy = 10.0;
1236 }
1237 accuracy = new_accuracy;
1238 pitch_tolerance = 0.01 * (85.0f + accuracy);
1239// especially against small targets, less good pilots will waste some shots
1240 aim_tolerance = 240.0 - (18.0f * accuracy);
1241
1243 {
1244 missile_load_time = 2.0; // smart enough not to waste all missiles on 1 ECM!
1245 }
1246}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setAfterburnerFactor:

- (void) setAfterburnerFactor: (GLfloat) new

Definition at line 2093 of file ShipEntity.m.

4107 :(GLfloat)new
4108{
4110}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setAfterburnerRate:

- (void) setAfterburnerRate: (GLfloat) new

Definition at line 2093 of file ShipEntity.m.

4113 :(GLfloat)new
4114{
4115 afterburner_rate = new;
4116}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setAI:

- (void) setAI: (AI *) ai

Definition at line 7619 of file ShipEntity.m.

8002 :(AI *)ai
8003{
8004 [ai retain];
8005 if (shipAI)
8006 {
8007 [shipAI clearAllData];
8008 [shipAI autorelease];
8009 }
8010 shipAI = ai;
8011}

◆ setAIScript:

- (void) setAIScript: (NSString *) aiString

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

284 :(NSString *)aiString
285{
286 NSMutableDictionary *properties = nil;
287
288 properties = [NSMutableDictionary dictionary];
289 [properties setObject:self forKey:@"ship"];
290
291 [aiScript autorelease];
292 aiScript = [OOScript jsAIScriptFromFileNamed:aiString properties:properties];
293 if (aiScript == nil)
294 {
295 OOLog(@"ai.load.failed.unknownAI",@"Unable to load JS AI %@ for ship %@ (%@ for role %@)",aiString,self,[self shipDataKey],[self primaryRole]);
296 aiScript = [OOScript jsAIScriptFromFileNamed:@"oolite-nullAI.js" properties:properties];
297 }
298 else
299 {
300 aiScriptWakeTime = 0;
301 haveStartedJSAI = NO;
302 }
303 [aiScript retain];
304}
id jsAIScriptFromFileNamed:properties:(NSString *fileName,[properties] NSDictionary *properties)
Definition OOScript.m:221

◆ setAIScriptWakeTime:

- (void) setAIScriptWakeTime: (OOTimeAbsolute) t

Definition at line 14954 of file ShipEntity.m.

1414 :(OOTimeAbsolute) t
1415{
1416 aiScriptWakeTime = t;
1417}
double OOTimeAbsolute
Definition OOTypes.h:223

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setAITo:

- (void) setAITo: (NSString *) aiString

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

252 :(NSString *)aiString
253{
254 // don't try to load real AIs if the game hasn't started yet
255 if (![PLAYER scriptsLoaded])
256 {
257 aiString = @"oolite-nullAI.js";
258 }
259 if ([aiString hasSuffix:@".plist"])
260 {
261 [[self getAI] setStateMachine:aiString withJSScript:@"oolite-nullAI.js"];
262 [self setAIScript:@"oolite-nullAI.js"];
263 }
264 else if ([aiString hasSuffix:@".js"])
265 {
266 [[self getAI] setStateMachine:@"nullAI.plist" withJSScript:aiString];
267 [self setAIScript:aiString];
268 }
269 else
270 {
271 NSString *path = [ResourceManager pathForFileNamed:[aiString stringByAppendingString:@".js"] inFolder:@"AIs"];
272 if (path == nil) // no js, use plist
273 {
274 [self setAITo:[aiString stringByAppendingString:@".plist"]];
275 }
276 else
277 {
278 [self setAITo:[aiString stringByAppendingString:@".js"]];
279 }
280 }
281}
NSString * pathForFileNamed:inFolder:(NSString *fileName,[inFolder] NSString *folderName)

Referenced by ShipSetAI().

+ Here is the caller graph for this function:

◆ setAutoCloak:

- (void) setAutoCloak: (BOOL) automatic

Definition at line 6496 of file ShipEntity.m.

6695 :(BOOL)automatic
6696{
6697 cloakAutomatic = !!automatic;
6698}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setBeaconCode:

- (void) setBeaconCode: (NSString *) bcode
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1552 :(NSString *)bcode
1553{
1554 if ([bcode length] == 0) bcode = nil;
1555
1556 if (_beaconCode != bcode)
1557 {
1558 [_beaconCode release];
1559 _beaconCode = [bcode copy];
1560
1562 }
1563 // if not blanking code and label is currently blank, default label to code
1564 if (bcode != nil && (_beaconLabel == nil || [_beaconLabel length] == 0))
1565 {
1566 [self setBeaconLabel:bcode];
1567 }
1568}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setBeaconLabel:

- (void) setBeaconLabel: (NSString *) blabel
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1577 :(NSString *)blabel
1578{
1579 if ([blabel length] == 0) blabel = nil;
1580
1581 if (_beaconLabel != blabel)
1582 {
1583 [_beaconLabel release];
1584 _beaconLabel = [OOExpand(blabel) retain];
1585 }
1586}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setBehaviour:

- (void) setBehaviour: (OOBehaviour) cond

Definition at line 9593 of file ShipEntity.m.

10250 :(OOBehaviour) cond
10251{
10252 if (cond != behaviour)
10253 {
10254 frustration = 0.0; // change is a GOOD thing
10255 behaviour = cond;
10256 }
10257}
OOBehaviour
Definition ShipEntity.h:150

◆ setBounty:

- (void) setBounty: (OOCreditsQuantity) amount

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8246 :(OOCreditsQuantity) amount
8247{
8248 [self setBounty:amount withReason:kOOLegalStatusReasonUnknown];
8249}
uint64_t OOCreditsQuantity
Definition OOTypes.h:182

◆ setBounty:withReason:

- (void) setBounty: (OOCreditsQuantity) amount
withReason: (OOLegalStatusReason) reason 

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8252 :(OOCreditsQuantity) amount withReason:(OOLegalStatusReason)reason
8253{
8254 if ([self isSubEntity])
8255 {
8256 [[self parentEntity] setBounty:amount withReason:reason];
8257 }
8258 else
8259 {
8260 if ((scanClass == CLASS_THARGOID || scanClass == CLASS_STATION) && reason != kOOLegalStatusReasonSetup && reason != kOOLegalStatusReasonByScript)
8261 {
8262 return; // no standard bounties for Thargoids / Stations
8263 }
8264 if (scanClass == CLASS_POLICE && amount != 0)
8265 {
8266 return; // police never have bounties
8267 }
8268 NSString* nReason = OOStringFromLegalStatusReason(reason);
8269 [self setBounty:amount withReasonAsString:nReason];
8270 }
8271}
NSString * OOStringFromLegalStatusReason(OOLegalStatusReason reason)

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setBounty:withReasonAsString:

- (void) setBounty: (OOCreditsQuantity) amount
withReasonAsString: (NSString *) reason 

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8273 :(OOCreditsQuantity) amount withReasonAsString:(NSString*)reason
8274{
8275 if ([self isSubEntity])
8276 {
8277 [[self parentEntity] setBounty:amount withReasonAsString:reason];
8278 }
8279 else
8280 {
8281 JSContext *context = OOJSAcquireContext();
8282
8283 jsval amountVal = JSVAL_VOID;
8284 JS_NewNumberValue(context, (int)amount-(int)bounty, &amountVal);
8285
8286 bounty = amount; // can't set the new bounty until the size of the change is known
8287
8288 jsval reasonVal = OOJSValueFromNativeObject(context,reason);
8289
8290 ShipScriptEvent(context, self, "shipBountyChanged", amountVal, reasonVal);
8291
8292 OOJSRelinquishContext(context);
8293
8294 }
8295}

Referenced by ShipSetBounty().

+ Here is the caller graph for this function:

◆ setCargo:

- (void) setCargo: (NSArray *) some_cargo

Definition at line 7619 of file ShipEntity.m.

8449 :(NSArray *) some_cargo
8450{
8451 [cargo removeAllObjects];
8452 [cargo addObjectsFromArray:some_cargo];
8453}

◆ setCargoFlag:

- (void) setCargoFlag: (OOCargoFlag) flag

Definition at line 7619 of file ShipEntity.m.

8517 :(OOCargoFlag) flag
8518{
8519 if (cargo_flag != flag)
8520 {
8521 cargo_flag = flag;
8522 NSArray *newCargo = nil;
8523 unsigned num = 0;
8524 if (likely_cargo > 0)
8525 {
8526 num = likely_cargo * (0.5+randf());
8527 if (num > [self maxAvailableCargoSpace])
8528 {
8529 num = [self maxAvailableCargoSpace];
8530 }
8531 }
8532 else
8533 {
8534 num = [self maxAvailableCargoSpace];
8535 }
8536 if (num > 200)
8537 {
8538 num = 200;
8539 /* no core NPC ship carries this much when generated (the
8540 * Anaconda could, but doesn't): let's not waste time generating
8541 * thousands of pods - even if they are semi-virtual - for some
8542 * massive OXP ship */
8543 }
8544 if (num > 0)
8545 {
8546 switch (cargo_flag)
8547 {
8549 newCargo = [UNIVERSE getContainersOfCommodity:[shipinfoDictionary oo_stringForKey:@"cargo_carried"] :num];
8550 break;
8552 newCargo = [UNIVERSE getContainersOfGoods:num scarce:NO legal:YES];
8553 break;
8555 newCargo = [UNIVERSE getContainersOfGoods:num scarce:YES legal:YES];
8556 break;
8558 newCargo = [UNIVERSE getContainersOfCommodity:@"Narcotics" :num];
8559 break;
8561 newCargo = [UNIVERSE getContainersOfGoods:num scarce:YES legal:NO];
8562 break;
8563 case CARGO_FLAG_PIRATE:
8564 newCargo = [UNIVERSE getContainersOfGoods:(Ranrot() % (1+num/2)) scarce:YES legal:NO];
8565 break;
8567 // TODO: allow passengers to survive
8568 case CARGO_FLAG_NONE:
8569 default:
8570 break;
8571 }
8572 }
8573 [self setCargo:newCargo];
8574 }
8575}
OOCargoFlag
Definition OOTypes.h:109
@ CARGO_FLAG_FULL_CONTRABAND
Definition OOTypes.h:114
@ CARGO_FLAG_FULL_SCARCE
Definition OOTypes.h:112
@ CARGO_FLAG_FULL_PLENTIFUL
Definition OOTypes.h:111
@ CARGO_FLAG_PIRATE
Definition OOTypes.h:115
@ CARGO_FLAG_FULL_UNIFORM
Definition OOTypes.h:116
@ CARGO_FLAG_FULL_MEDICAL
Definition OOTypes.h:113
@ CARGO_FLAG_FULL_PASSENGERS
Definition OOTypes.h:118
@ CARGO_FLAG_NONE
Definition OOTypes.h:110

Referenced by ShipSetCargoType().

+ Here is the caller graph for this function:

◆ setCloaked:

- (void) setCloaked: (BOOL) cloak

Definition at line 6496 of file ShipEntity.m.

6682 :(BOOL)cloak
6683{
6684 if (cloak) [self activateCloakingDevice];
6685 else [self deactivateCloakingDevice];
6686}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setCommodity:andAmount:

- (void) setCommodity: (OOCommodityType) co_type
andAmount: (OOCargoQuantity) co_amount 

Definition at line 7619 of file ShipEntity.m.

8322 :(OOCommodityType)co_type andAmount:(OOCargoQuantity)co_amount
8323{
8324 if (co_type != nil)
8325 {
8326 /* The tmp variable is needed as scoopUp can cause the method
8327 * to be passed a reference to self.commodity_type, so DESTROY
8328 * then copying the parameter segfaults */
8329 NSString *tmp = [co_type copy];
8331 commodity_type = tmp;
8332 commodity_amount = co_amount;
8333 }
8334}

◆ setCommodityForPod:andAmount:

- (void) setCommodityForPod: (OOCommodityType) co_type
andAmount: (OOCargoQuantity) co_amount 

Definition at line 7619 of file ShipEntity.m.

8337 :(OOCommodityType)co_type andAmount:(OOCargoQuantity)co_amount
8338{
8339 // can be nil for pods
8340 if (co_type == nil)
8341 {
8343 commodity_amount = 0;
8344 return;
8345 }
8346 // pod content should never be greater than 1 ton or this will give cargo counting problems elsewhere in the code.
8347 // so do first a mass check for cargo added by script/plist.
8348 OOMassUnit unit = [[UNIVERSE commodityMarket] massUnitForGood:co_type];
8349 if (unit == UNITS_TONS && co_amount > 1) co_amount = 1;
8350 else if (unit == UNITS_KILOGRAMS && co_amount > 1000) co_amount = 1000;
8351 else if (unit == UNITS_GRAMS && co_amount > 1000000) co_amount = 1000000;
8352 [self setCommodity:co_type andAmount:co_amount];
8353}
OOMassUnit
Definition OOTypes.h:123
@ UNITS_TONS
Definition OOTypes.h:124
@ UNITS_GRAMS
Definition OOTypes.h:126
@ UNITS_KILOGRAMS
Definition OOTypes.h:125

Referenced by ShipSetCargo().

+ Here is the caller graph for this function:

◆ setCommsMessageColor

- (void) setCommsMessageColor

Definition at line 14073 of file ShipEntity.m.

14230{
14231 float hue = 0.0625f * (universalID & 15);
14232 [[UNIVERSE commLogGUI] setTextColor:[OOColor colorWithHue:hue saturation:0.375f brightness:1.0f alpha:1.0f]];
14233 if (scanClass == CLASS_THARGOID)
14234 [[UNIVERSE commLogGUI] setTextColor:[OOColor greenColor]];
14235 if (scanClass == CLASS_POLICE)
14236 [[UNIVERSE commLogGUI] setTextColor:[OOColor cyanColor]];
14237}
OOColor * cyanColor()
Definition OOColor.m:286
OOColor * greenColor()
Definition OOColor.m:274
OOColor * colorWithHue:saturation:brightness:alpha:(float hue,[saturation] float saturation,[brightness] float brightness,[alpha] float alpha)
Definition OOColor.m:87

◆ setCoordinate:

- (void) setCoordinate: (HPVector) coord

Definition at line 9593 of file ShipEntity.m.

10270 :(HPVector) coord // The name "setCoordinates" is already used by AI scripting.
10271{
10272 coordinates = coord;
10273}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setCoordinates:

- (void) setCoordinates: (NSString *) system_x_y_z
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setCoordinatesFromPosition

- (void) setCoordinatesFromPosition
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1226{
1227 coordinates = position;
1228}

◆ setCourseToPlanet

- (void) setCourseToPlanet
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setCourseToWitchpoint

- (void) setCourseToWitchpoint
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1605{
1606 if (UNIVERSE)
1607 {
1608 _destination = [UNIVERSE getWitchspaceExitPosition];
1609 desired_range = 10000.0; // 10km away
1610 }
1611}

◆ setCrew:

- (void) setCrew: (NSArray *) crewArray

Definition at line 7619 of file ShipEntity.m.

7951 :(NSArray *)crewArray
7952{
7953 if ([self isExplicitlyUnpiloted])
7954 {
7955 //unpiloted ships cannot have crew
7956 // but may have crew before isExplicitlyUnpiloted set, so force *that* to clear too
7957 [crew autorelease];
7958 crew = nil;
7959 return;
7960 }
7961 //do not set to hulk here when crew is nil (or 0). Some things like missiles have no crew.
7962 [crew autorelease];
7963 crew = [crewArray copy];
7964}
BOOL isExplicitlyUnpiloted()

Referenced by ShipSetCrew().

+ Here is the caller graph for this function:

◆ setDemoShip:

- (void) setDemoShip: (OOScalar) demoRate

Definition at line 14073 of file ShipEntity.m.

14606 : (OOScalar) rate
14607{
14609 demoRate = rate;
14610 isDemoShip = YES;
14611 [self setPitch: 0.0f];
14612 [self setRoll: 0.0f];
14613}
BOOL isDemoShip
Definition ShipEntity.h:493
Quaternion demoStartOrientation
Definition ShipEntity.h:496
OOScalar demoRate
Definition ShipEntity.h:494

◆ setDemoStartTime:

- (void) setDemoStartTime: (OOTimeAbsolute) time

Definition at line 14073 of file ShipEntity.m.

14620 : (OOTimeAbsolute) time
14621{
14622 demoStartTime = time;
14623}

◆ setDesiredRange:

- (void) setDesiredRange: (double) amount

Definition at line 7619 of file ShipEntity.m.

8602 :(double) amount
8603{
8604 desired_range = amount;
8605}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setDesiredRangeForWaypoint

- (void) setDesiredRangeForWaypoint
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setDesiredRangeTo:

- (void) setDesiredRangeTo: (NSString *) rangeString
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

911 :(NSString *)rangeString
912{
913 desired_range = [rangeString doubleValue];
914}

◆ setDesiredSpeed:

- (void) setDesiredSpeed: (double) amount

Definition at line 7619 of file ShipEntity.m.

8584 :(double) amount
8585{
8586 desired_speed = amount;
8587}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setDestination:

- (void) setDestination: (HPVector) dest

Definition at line 9593 of file ShipEntity.m.

13675 :(HPVector) dest
13676{
13677 _destination = dest;
13678 frustration = 0.0; // new destination => no frustration!
13679}

◆ setDestinationFromCoordinates

- (void) setDestinationFromCoordinates
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1220{
1221 _destination = coordinates;
1222}

◆ setDestinationSystem:

- (void) setDestinationSystem: (OOSystemID) s

Definition at line 7619 of file ShipEntity.m.

7923 :(OOSystemID)s
7924{
7926}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setDestinationToCurrentLocation

- (void) setDestinationToCurrentLocation
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

897{
898 // randomly add a .5m variance
899 _destination = HPvector_add(position, OOHPVectorRandomSpatial(0.5));
900}
HPVector OOHPVectorRandomSpatial(OOHPScalar maxLength)
Definition OOHPVector.m:82

◆ setDestinationToDockingAbort

- (void) setDestinationToDockingAbort
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2212{
2213 Entity *the_target = [self targetStation];
2214 if (!the_target) {
2215 /* Probably the player trying to dock with docking computer
2216 * from out of scanner range */
2217 the_target = [UNIVERSE station];
2218 }
2219 double bo_distance = 8000; // 8km back off
2220 HPVector v0 = position;
2221 HPVector d0 = (the_target) ? the_target->position : kZeroHPVector;
2222 v0.x += (randf() - 0.5)*collision_radius; v0.y += (randf() - 0.5)*collision_radius; v0.z += (randf() - 0.5)*collision_radius;
2223 v0.x -= d0.x; v0.y -= d0.y; v0.z -= d0.z;
2224 v0 = HPvector_normal_or_fallback(v0, make_HPvector(0, 0, -1));
2225
2226 v0.x *= bo_distance; v0.y *= bo_distance; v0.z *= bo_distance;
2227 v0.x += d0.x; v0.y += d0.y; v0.z += d0.z;
2228 coordinates = v0;
2229 _destination = v0;
2230}

◆ setDestinationToJinkPosition

- (void) setDestinationToJinkPosition
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setDestinationToStationBeacon

- (void) setDestinationToStationBeacon
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1621{
1622 if ([UNIVERSE station])
1623 {
1624 _destination = [[UNIVERSE station] beaconPosition];
1625 }
1626}

◆ setDestinationToTarget

- (void) setDestinationToTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1426{
1427 Entity *the_target = [self primaryTarget];
1428 if (the_target)
1429 _destination = the_target->position;
1430}

◆ setDestinationToWitchpoint

- (void) setDestinationToWitchpoint
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1615{
1616 _destination = [UNIVERSE getWitchspaceExitPosition];
1617}

◆ setDestinationWithinTarget

- (void) setDestinationWithinTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1434{
1435 Entity *the_target = [self primaryTarget];
1436 if (the_target)
1437 {
1438 HPVector pos = the_target->position;
1439 Quaternion q; quaternion_set_random(&q);
1440 Vector v = vector_forward_from_quaternion(q);
1441 GLfloat d = (randf() - randf()) * the_target->collision_radius;
1442 _destination = make_HPvector(pos.x + d * v.x, pos.y + d * v.y, pos.z + d * v.z);
1443 }
1444}

◆ setDisplayName:

- (void) setDisplayName: (NSString *) inName

Definition at line 6496 of file ShipEntity.m.

7229 :(NSString *)inName
7230{
7231 [displayName release];
7232 displayName = [inName copy];
7233}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setEnergyRechargeRate:

- (void) setEnergyRechargeRate: (GLfloat) new

Definition at line 7411 of file ShipEntity.m.

7508 :(GLfloat)new
7509{
7511}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setEntityPersonalityInt:

- (void) setEntityPersonalityInt: (uint16_t) value

Definition at line 9593 of file ShipEntity.m.

9784 :(uint16_t)value
9785{
9786 if (value <= ENTITY_PERSONALITY_MAX)
9787 {
9788 entity_personality = value;
9789 [[self mesh] rebindMaterials];
9790 }
9791}

Referenced by MissionRunScreen(), PlayerReplaceShip(), and ShipSetProperty().

+ Here is the caller graph for this function:

◆ setEscortDestination:

- (void) setEscortDestination: (HPVector) dest

Definition at line 9593 of file ShipEntity.m.

13682 :(HPVector) dest
13683{
13684 _destination = dest; // don't reset frustration for escorts.
13685}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setEscortGroup:

- (void) setEscortGroup: (OOShipGroup *) group

Definition at line 6496 of file ShipEntity.m.

6944 :(OOShipGroup *)group
6945{
6946 if (group != _escortGroup)
6947 {
6948 [_escortGroup release];
6949 _escortGroup = [group retain];
6950 [group setLeader:self]; // A ship is always leader of its own escort group.
6951 [self updateEscortFormation];
6952 }
6953}
void setLeader:(ShipEntity *leader)

◆ setEvasiveJink:

- (void) setEvasiveJink: (GLfloat) z

Definition at line 9593 of file ShipEntity.m.

10409 :(GLfloat) z
10410{
10412 {
10413 jink = kZeroVector;
10414 }
10415 else
10416 {
10417 jink.x = (ranrot_rand() % 256) - 128.0;
10418 jink.y = (ranrot_rand() % 256) - 128.0;
10419 jink.z = z;
10420
10421 // make sure we don't accidentally have near-zero jink
10422 if (jink.x < 0.0)
10423 {
10424 jink.x -= 128.0;
10425 }
10426 else
10427 {
10428 jink.x += 128.0;
10429 }
10430 if (jink.y < 0)
10431 {
10432 jink.y -= 128.0;
10433 }
10434 else
10435 {
10436 jink.y += 128.0;
10437 }
10438 }
10439}

◆ setExhaustEmissiveColor:

- (void) setExhaustEmissiveColor: (OOColor *) color

Definition at line 9593 of file ShipEntity.m.

11707 :(OOColor *) color
11708{
11709 if (color)
11710 {
11711 [exhaust_emissive_color release];
11712 exhaust_emissive_color = [color retain];
11713 }
11714}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setFoundTarget:

- (void) setFoundTarget: (Entity *) targetEntity

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

9930 :(Entity *) targetEntity
9931{
9932 [_foundTarget release];
9933 _foundTarget = [targetEntity weakRetain];
9934}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setFuel:

- (void) setFuel: (OOFuelQuantity) amount

Definition at line 7619 of file ShipEntity.m.

8110 :(OOFuelQuantity) amount
8111{
8112 if (amount > [self fuelCapacity]) amount = [self fuelCapacity];
8113
8114 fuel = amount;
8115}
uint16_t OOFuelQuantity
Definition OOTypes.h:179

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setGroup:

- (void) setGroup: (OOShipGroup *) group

Definition at line 6496 of file ShipEntity.m.

6914 :(OOShipGroup *)group
6915{
6916 if (group != _group)
6917 {
6918 if (_escortGroup != _group)
6919 {
6920 if (self == [_group leader]) [_group setLeader:nil];
6921 [_group removeShip:self];
6922 }
6923 [_group release];
6924 [group addShip:self];
6925 _group = [group retain];
6926
6927 [[group leader] updateEscortFormation];
6928 }
6929}
BOOL addShip:(ShipEntity *ship)
ShipEntity * leader()
void updateEscortFormation()

Referenced by ShipGroupAddShip(), and ShipSetProperty().

+ Here is the caller graph for this function:

◆ setHeatInsulation:

- (void) setHeatInsulation: (GLfloat) value

Definition at line 7619 of file ShipEntity.m.

8827 :(GLfloat) value
8828{
8829 _heatInsulation = value;
8830}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setHomeSystem:

- (void) setHomeSystem: (OOSystemID) s

Definition at line 7619 of file ShipEntity.m.

7917 :(OOSystemID)s
7918{
7919 home_system = s;
7920}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setHulk:

- (void) setHulk: (BOOL) isNowHulk

Definition at line 7619 of file ShipEntity.m.

8966 :(BOOL)isNowHulk
8967{
8968 if (![self isSubEntity])
8969 {
8970 isHulk = isNowHulk;
8971 }
8972}

◆ setHyperspaceSpinTime:

- (void) setHyperspaceSpinTime: (float) new

Definition at line 2093 of file ShipEntity.m.

3219 :(float)new
3220{
3222}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setIsBoulder:

- (void) setIsBoulder: (BOOL) flag

Definition at line 14954 of file ShipEntity.m.

1659 :(BOOL)flag
1660{
1661 if (flag) [self addRole:kBoulderRole];
1662 else [self removeRole:kBoulderRole];
1663}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setIsMissileFlag:

- (void) setIsMissileFlag: (BOOL) newValue

Definition at line 9593 of file ShipEntity.m.

12323 :(BOOL)newValue
12324{
12325 isMissile = !!newValue; // set the isMissile flag, used for tracking submunitions and preventing collisions at launch.
12326}

◆ setIsWreckage:

- (void) setIsWreckage: (BOOL) isw

Definition at line 7619 of file ShipEntity.m.

9158 :(BOOL)isw
9159{
9160 isWreckage = isw;
9161}

◆ setLaserColor:

- (void) setLaserColor: (OOColor *) color

Definition at line 9593 of file ShipEntity.m.

11697 :(OOColor *) color
11698{
11699 if (color)
11700 {
11701 [laser_color release];
11702 laser_color = [color retain];
11703 }
11704}

◆ setLastAegisLock:

- (void) setLastAegisLock: (Entity<OOStellarBody> *) lastAegisLock

Definition at line 7619 of file ShipEntity.m.

7899{
7900 [_lastAegisLock release];
7901 _lastAegisLock = [lastAegisLock weakRetain];
7902}

◆ setLastEscortTarget:

- (void) setLastEscortTarget: (Entity *) targetEntity

Definition at line 9593 of file ShipEntity.m.

9968 :(Entity *) targetEntity
9969{
9970 [_lastEscortTarget release];
9971 _lastEscortTarget = [targetEntity weakRetain];
9972}

◆ setLaunchDelay:

- (void) setLaunchDelay: (double) delay

Definition at line 7619 of file ShipEntity.m.

7939 :(double)delay
7940{
7941 launch_delay = delay;
7942}
double launch_delay
Definition ShipEntity.h:345

◆ setMaxAvailableCargoSpace:

- (void) setMaxAvailableCargoSpace: (OOCargoQuantity) new

Definition at line 7619 of file ShipEntity.m.

8374 :(OOCargoQuantity)new
8375{
8377}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setMaxEscortCount:

- (void) setMaxEscortCount: (uint8_t) newCount

Definition at line 6496 of file ShipEntity.m.

7022 :(uint8_t)newCount
7023{
7024 _maxEscortCount = newCount;
7025}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setMaxFlightPitch:

- (void) setMaxFlightPitch: (GLfloat) new

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8753 :(GLfloat)new
8754{
8755 max_flight_pitch = new;
8756}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setMaxFlightRoll:

- (void) setMaxFlightRoll: (GLfloat) new

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8765 :(GLfloat)new
8766{
8767 max_flight_roll = new;
8768}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setMaxFlightSpeed:

- (void) setMaxFlightSpeed: (GLfloat) new

Definition at line 7619 of file ShipEntity.m.

8759 :(GLfloat)new
8760{
8761 maxFlightSpeed = new;
8762}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setMaxFlightYaw:

- (void) setMaxFlightYaw: (GLfloat) new

Reimplemented in PlayerEntity.

Definition at line 7619 of file ShipEntity.m.

8771 :(GLfloat)new
8772{
8773 max_flight_yaw = new;
8774}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setMaxThrust:

- (void) setMaxThrust: (GLfloat) new

Definition at line 2093 of file ShipEntity.m.

4125 :(GLfloat)new
4126{
4127 max_thrust = new;
4128}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setMesh:

- (void) setMesh: (OOMesh *) mesh

Definition at line 14954 of file ShipEntity.m.

1254 :(OOMesh *)mesh
1255{
1256 if (mesh != [self mesh])
1257 {
1258 [self setDrawable:mesh];
1259 [octree autorelease];
1260 octree = [[mesh octree] retain];
1261 }
1262}
Octree * octree
Definition OOMesh.h:122

Referenced by ShipSetMaterialsInternal().

+ Here is the caller graph for this function:

◆ setMessageTime:

- (void) setMessageTime: (double) value

Definition at line 6496 of file ShipEntity.m.

6902 :(double) value
6903{
6904 messageTime = value;
6905}

◆ setMissileLoadTime:

- (void) setMissileLoadTime: (OOTimeDelta) newMissileLoadTime

Definition at line 9593 of file ShipEntity.m.

12335 :(OOTimeDelta)newMissileLoadTime
12336{
12337 missile_load_time = fmax(0.0, newMissileLoadTime);
12338}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setName:

- (void) setName: (NSString *) inName

Reimplemented in PlayerEntity.

Definition at line 6496 of file ShipEntity.m.

7208 :(NSString *)inName
7209{
7210 [name release];
7211 name = [inName copy];
7212}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setNextBeacon:

- (void) setNextBeacon: (Entity <OOBeaconEntity> *) beaconShip
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1647 :(Entity <OOBeaconEntity> *)beaconShip
1648{
1649 if (beaconShip != [self nextBeacon])
1650 {
1651 [_nextBeacon release];
1652 _nextBeacon = [beaconShip weakRetain];
1653 }
1654}
Entity< OOBeaconEntity > * nextBeacon()
OOWeakReference * _nextBeacon
Definition ShipEntity.h:487

◆ setOwner:

- (void) setOwner: (Entity *) who_owns_entity
implementation

Reimplemented from Entity.

Definition at line 6496 of file ShipEntity.m.

6721 :(Entity *)who_owns_entity
6722{
6723 [super setOwner:who_owns_entity];
6724
6725 /* Reset shader binding target so that bind-to-super works.
6726 This is necessary since we don't know about the owner in
6727 setUpShipFromDictionary:, when the mesh is initially set up.
6728 -- Ahruman 2008-04-19
6729 */
6730 if (isSubEntity)
6731 {
6732 [[self drawable] setBindingTarget:self];
6733 }
6734}

◆ setPendingEscortCount:

- (void) setPendingEscortCount: (uint8_t) count

Definition at line 6496 of file ShipEntity.m.

7010 :(uint8_t)count
7011{
7013}

◆ setPitch:

- (void) setPitch: (double) amount

Definition at line 7619 of file ShipEntity.m.

8222 :(double) amount
8223{
8224 flightPitch = amount * M_PI / 2.0;
8225}
#define M_PI
Definition OOMaths.h:73

◆ setPlanetPatrolCoordinates

- (void) setPlanetPatrolCoordinates
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setPrevBeacon:

- (void) setPrevBeacon: (Entity <OOBeaconEntity> *) beaconShip
implementation

Reimplemented from <OOBeaconEntity>.

Definition at line 14954 of file ShipEntity.m.

1637 :(Entity <OOBeaconEntity> *)beaconShip
1638{
1639 if (beaconShip != [self prevBeacon])
1640 {
1641 [_prevBeacon release];
1642 _prevBeacon = [beaconShip weakRetain];
1643 }
1644}
OOWeakReference * _prevBeacon
Definition ShipEntity.h:486
Entity< OOBeaconEntity > * prevBeacon()

◆ setPrimaryAggressor:

- (void) setPrimaryAggressor: (Entity *) targetEntity

Definition at line 9593 of file ShipEntity.m.

9949 :(Entity *) targetEntity
9950{
9951 [_primaryAggressor release];
9952 _primaryAggressor = [targetEntity weakRetain];
9953}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setPrimaryRole:

- (void) setPrimaryRole: (NSString *) role

Definition at line 6496 of file ShipEntity.m.

7317 :(NSString *)role
7318{
7319 if (![role isEqual:primaryRole])
7320 {
7321 [primaryRole release];
7322 primaryRole = [role copy];
7323 }
7324}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setProximityAlert:

- (void) setProximityAlert: (ShipEntity *) targetEntity

Definition at line 6496 of file ShipEntity.m.

7055 :(ShipEntity*) other
7056{
7057 if (!other)
7058 {
7060 return;
7061 }
7062
7063 if ([other mass] < 2000) // we are not alerted by small objects. (a cargopod has a mass of about 1000)
7064 return;
7065
7066
7067 if (isStation) // stations don't worry about colliding with things
7068 return;
7069
7070 /* Ignore station collision warnings if launching or docking */
7071 if ((other->isStation) && ([self status] == STATUS_LAUNCHING ||
7073 {
7074 return;
7075 }
7076
7077 if (!crew) // Ships without pilot (cargo, rocks, missiles, buoys etc) will not get alarmed. (escape-pods have pilots)
7078 return;
7079
7080 // check vectors
7081 Vector vdiff = HPVectorToVector(HPvector_between(position, other->position));
7082 GLfloat d_forward = dot_product(vdiff, v_forward);
7083 GLfloat d_up = dot_product(vdiff, v_up);
7084 GLfloat d_right = dot_product(vdiff, v_right);
7085 if ((d_forward > 0.0)&&(flightSpeed > 0.0)) // it's ahead of us and we're moving forward
7086 d_forward *= 0.25 * maxFlightSpeed / flightSpeed; // extend the collision zone forward up to 400%
7087 double d2 = d_forward * d_forward + d_up * d_up + d_right * d_right;
7088 double cr2 = collision_radius * 2.0 + other->collision_radius; cr2 *= cr2; // check with twice the combined radius
7089
7090 if (d2 > cr2) // we're okay
7091 return;
7092
7093 if (behaviour == BEHAVIOUR_AVOID_COLLISION) // already avoiding something
7094 {
7095 ShipEntity* prox = (ShipEntity*)[self proximityAlert];
7096 if ((prox)&&(prox != other))
7097 {
7098 // check which subtends the greatest angle
7099 GLfloat sa_prox = prox->collision_radius * prox->collision_radius / HPdistance2(position, prox->position);
7100 GLfloat sa_other = other->collision_radius * other->collision_radius / HPdistance2(position, other->position);
7101 if (sa_prox < sa_other) return;
7102 }
7103 }
7104 [_proximityAlert release];
7105 _proximityAlert = [other weakRetain];
7106}

◆ setRacepointsFromTarget

- (void) setRacepointsFromTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2711{
2712 // two point - one at z - cr one at z + cr
2713 ShipEntity *ship = [self primaryTarget];
2714 if (ship == nil)
2715 {
2716 [shipAI message:@"NOTHING_FOUND"];
2717 return;
2718 }
2719 Vector k = ship->v_forward;
2720 GLfloat c = ship->collision_radius;
2721 HPVector o = ship->position;
2722 navpoints[0] = make_HPvector(o.x - c * k.x, o.y - c * k.y, o.z - c * k.z);
2723 navpoints[1] = make_HPvector(o.x + c * k.x, o.y + c * k.y, o.z + c * k.z);
2724 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);
2725 number_of_navpoints = 2;
2726 next_navpoint_index = 0;
2727 _destination = navpoints[0];
2728 [shipAI message:@"RACEPOINTS_SET"];
2729}

◆ setRawRoll:

- (void) setRawRoll: (double) amount

Definition at line 7619 of file ShipEntity.m.

8216 :(double) amount
8217{
8218 flightRoll = amount;
8219}

Referenced by StationSetProperty().

+ Here is the caller graph for this function:

◆ setReactionTime:

- (void) setReactionTime: (float) newReactionTime

Definition at line 2093 of file ShipEntity.m.

6293 : (float) newReactionTime
6294{
6295 reactionTime = newReactionTime;
6296}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setReference:

- (void) setReference: (Vector) v

Definition at line 7411 of file ShipEntity.m.

7556 :(Vector) v
7557{
7558 reference = v;
7559}

◆ setRememberedShip:

- (void) setRememberedShip: (Entity *) targetEntity

Definition at line 9593 of file ShipEntity.m.

10006 :(Entity *) targetEntity
10007{
10008 [_rememberedShip release];
10009 _rememberedShip = [targetEntity weakRetain];
10010}

◆ setReportAIMessages:

- (void) setReportAIMessages: (BOOL) yn

Definition at line 7411 of file ShipEntity.m.

7568 :(BOOL) yn
7569{
7570 reportAIMessages = yn;
7571}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setRoll:

- (void) setRoll: (double) amount

Definition at line 7619 of file ShipEntity.m.

8210 :(double) amount
8211{
8212 flightRoll = amount * M_PI / 2.0;
8213}

◆ setScanDescription:

- (void) setScanDescription: (NSString *) inName

Definition at line 6496 of file ShipEntity.m.

7236 :(NSString *)inName
7237{
7238 [scan_description release];
7239 scan_description = [inName copy];
7240}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setScannerDisplayColor1:

- (void) setScannerDisplayColor1: (OOColor *) color1

Definition at line 6496 of file ShipEntity.m.

6610 :(OOColor *)color
6611{
6613
6614 if (color == nil) color = [OOColor colorWithDescription:[[self shipInfoDictionary] objectForKey:@"scanner_display_color1"]];
6615 scanner_display_color1 = [color retain];
6616}
OOColor * colorWithDescription:(id description)
Definition OOColor.m:127

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setScannerDisplayColor2:

- (void) setScannerDisplayColor2: (OOColor *) color2

Definition at line 6496 of file ShipEntity.m.

6619 :(OOColor *)color
6620{
6622
6623 if (color == nil) color = [OOColor colorWithDescription:[[self shipInfoDictionary] objectForKey:@"scanner_display_color2"]];
6624 scanner_display_color2 = [color retain];
6625}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setScannerDisplayColorHostile1:

- (void) setScannerDisplayColorHostile1: (OOColor *) color1

Definition at line 6496 of file ShipEntity.m.

6640 :(OOColor *)color
6641{
6643
6644 if (color == nil) color = [OOColor colorWithDescription:[[self shipInfoDictionary] objectForKey:@"scanner_hostile_display_color1"]];
6645 scanner_display_color_hostile1 = [color retain];
6646}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setScannerDisplayColorHostile2:

- (void) setScannerDisplayColorHostile2: (OOColor *) color2

Definition at line 6496 of file ShipEntity.m.

6649 :(OOColor *)color
6650{
6652
6653 if (color == nil) color = [OOColor colorWithDescription:[[self shipInfoDictionary] objectForKey:@"scanner_hostile_display_color2"]];
6654 scanner_display_color_hostile2 = [color retain];
6655}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setScannerRange:

- (void) setScannerRange: (GLfloat) value

Definition at line 7411 of file ShipEntity.m.

7544 : (GLfloat) value
7545{
7546 scannerRange = value;
7547}

◆ setScriptedMisjump:

- (void) setScriptedMisjump: (BOOL) newValue

Definition at line 14954 of file ShipEntity.m.

1295 :(BOOL)newValue
1296{
1297 scripted_misjump = !!newValue;
1298}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setScriptedMisjumpRange:

- (void) setScriptedMisjumpRange: (GLfloat) newValue

Definition at line 14954 of file ShipEntity.m.

1307 :(GLfloat)newValue
1308{
1309 _scriptedMisjumpRange = newValue;
1310}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setShipClassName:

- (void) setShipClassName: (NSString *) inName

Definition at line 6496 of file ShipEntity.m.

7222 :(NSString *)inName
7223{
7224 [shipClassName release];
7225 shipClassName = [inName copy];
7226}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setShipDataKey:

- (void) setShipDataKey: (NSString *) key

Definition at line 14954 of file ShipEntity.m.

1986 :(NSString *)key
1987{
1989 _shipKey = [key copy];
1990}

◆ setShipHitByLaser:

- (void) setShipHitByLaser: (ShipEntity *) ship
implementation

Provided by category ShipEntity(Private).

Definition at line 9593 of file ShipEntity.m.

10182 :(ShipEntity *)ship
10183{
10184 if (ship != [self shipHitByLaser])
10185 {
10186 [_shipHitByLaser release];
10187 _shipHitByLaser = [ship weakRetain];
10188 }
10189}
OOWeakReference * _shipHitByLaser
Definition ShipEntity.h:481
ShipEntity * shipHitByLaser()

◆ setShipScript:

- (void) setShipScript: (NSString *) script_name

Definition at line 7619 of file ShipEntity.m.

8038 :(NSString *)script_name
8039{
8040 NSMutableDictionary *properties = nil;
8041 NSArray *actions = nil;
8042
8043 properties = [NSMutableDictionary dictionary];
8044 [properties setObject:self forKey:@"ship"];
8045
8046 [script autorelease];
8047 script = [OOScript jsScriptFromFileNamed:script_name properties:properties];
8048
8049 if (script == nil)
8050 {
8051 actions = [shipinfoDictionary oo_arrayForKey:@"launch_actions"];
8052 if (actions)
8053 {
8054 OOStandardsDeprecated([NSString stringWithFormat:@"The launch_actions ship key is deprecated on %@.",[self displayName]]);
8055 if (!OOEnforceStandards())
8056 {
8057 [properties setObject:actions forKey:@"legacy_launchActions"];
8058 }
8059 }
8060
8061 actions = [shipinfoDictionary oo_arrayForKey:@"script_actions"];
8062 if (actions)
8063 {
8064 OOStandardsDeprecated([NSString stringWithFormat:@"The script_actions ship key is deprecated on %@.",[self displayName]]);
8065 if (!OOEnforceStandards())
8066 {
8067 [properties setObject:actions forKey:@"legacy_scriptActions"];
8068 }
8069 }
8070
8071 actions = [shipinfoDictionary oo_arrayForKey:@"death_actions"];
8072 if (actions)
8073 {
8074 OOStandardsDeprecated([NSString stringWithFormat:@"The death_actions ship key is deprecated on %@.",[self displayName]]);
8075 if (!OOEnforceStandards())
8076 {
8077 [properties setObject:actions forKey:@"legacy_deathActions"];
8078 }
8079 }
8080
8081 actions = [shipinfoDictionary oo_arrayForKey:@"setup_actions"];
8082 if (actions)
8083 {
8084 OOStandardsDeprecated([NSString stringWithFormat:@"The setup_actions ship key is deprecated on %@.",[self displayName]]);
8085 if (!OOEnforceStandards())
8086 {
8087 [properties setObject:actions forKey:@"legacy_setupActions"];
8088 }
8089 }
8090
8091 script = [OOScript jsScriptFromFileNamed:@"oolite-default-ship-script.js"
8092 properties:properties];
8093 }
8094 [script retain];
8095}
BOOL OOEnforceStandards(void)
id jsScriptFromFileNamed:properties:(NSString *fileName,[properties] NSDictionary *properties)
Definition OOScript.m:192

Referenced by ShipSetScript().

+ Here is the caller graph for this function:

◆ setShipUniqueName:

- (void) setShipUniqueName: (NSString *) inName

Definition at line 6496 of file ShipEntity.m.

7215 :(NSString *)inName
7216{
7217 [shipUniqueName release];
7218 shipUniqueName = [inName copy];
7219}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setSingleCrewWithRole:

- (void) setSingleCrewWithRole: (NSString *) crewRole

Convenience to set the crew to a single character of the given role, originating in the ship's home system. Does nothing if unpiloted.

Definition at line 7619 of file ShipEntity.m.

7967 :(NSString *)crewRole
7968{
7969 if (![self isUnpiloted])
7970 {
7971 OOCharacter *crewMember = [OOCharacter randomCharacterWithRole:crewRole
7972 andOriginalSystem:[self homeSystem]];
7973 [self setCrew:[NSArray arrayWithObject:crewMember]];
7974 }
7975}
BOOL isUnpiloted()

◆ setSpeed:

- (void) setSpeed: (double) amount

Definition at line 7619 of file ShipEntity.m.

8578 :(double) amount
8579{
8580 flightSpeed = amount;
8581}

◆ setSpeedFactorTo:

- (void) setSpeedFactorTo: (NSString *) speedString
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

927 :(NSString *)speedString
928{
929 desired_speed = maxFlightSpeed * [speedString doubleValue];
930}

◆ setSpeedTo:

- (void) setSpeedTo: (NSString *) speedString
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

921 :(NSString *)speedString
922{
923 desired_speed = [speedString doubleValue];
924}

◆ setSpeedToCruiseSpeed

- (void) setSpeedToCruiseSpeed
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

933{
934 desired_speed = cruiseSpeed;
935}

◆ setStateMachine:

- (void) setStateMachine: (NSString *) ai_desc

Definition at line 7619 of file ShipEntity.m.

7996 :(NSString *)smName
7997{
7998 [self setAITo:smName];
7999}

◆ setStateTo:

- (void) setStateTo: (NSString *) state
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

845 :(NSString *)state
846{
847 [[self getAI] setState:state];
848}

◆ setStatus:

- (void) setStatus: (OOEntityStatus) stat
implementation

Reimplemented from Entity.

Definition at line 7619 of file ShipEntity.m.

7929 :(OOEntityStatus) stat
7930{
7931 if ([self status] == stat) return;
7932 [super setStatus:stat];
7933 if (stat == STATUS_LAUNCHING)
7934 {
7935 launch_time = [UNIVERSE getTime];
7936 }
7937}
double launch_time
Definition ShipEntity.h:344

Referenced by PlayerShipBeginGalacticHyperspaceCountdown().

+ Here is the caller graph for this function:

◆ setSubEntityRotationalVelocity:

- (void) setSubEntityRotationalVelocity: (Quaternion) rv

Definition at line 14954 of file ShipEntity.m.

1175 :(Quaternion)rv
1176{
1178}
Quaternion subentityRotationalVelocity
Definition ShipEntity.h:219

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setSubEntityTakingDamage:

- (void) setSubEntityTakingDamage: (ShipEntity *) sub

Definition at line 14954 of file ShipEntity.m.

1372 :(ShipEntity *)sub
1373{
1374#ifndef NDEBUG
1375 // Sanity checks: sub must be a ship subentity of self, or nil.
1376 if (sub != nil)
1377 {
1378 if (![self hasSubEntity:sub])
1379 {
1380 OOLog(@"ship.subentity.sanityCheck.failed.details", @"Attempt to set subentity taking damage of %@ to %@, which is not a subentity.", [self shortDescription], sub);
1381 sub = nil;
1382 }
1383 else if (![sub isShip])
1384 {
1385 OOLog(@"ship.subentity.sanityCheck.failed", @"Attempt to set subentity taking damage of %@ to %@, which is not a ship.", [self shortDescription], sub);
1386 sub = nil;
1387 }
1388 }
1389#endif
1390
1391 [_subEntityTakingDamage release];
1392 _subEntityTakingDamage = [sub weakRetain];
1393}
OOWeakReference * _subEntityTakingDamage
Definition ShipEntity.h:457

◆ setSubIdx:

- (void) setSubIdx: (NSUInteger) value

Definition at line 14954 of file ShipEntity.m.

780 :(NSUInteger)value
781{
782 _subIdx = value;
783}
NSUInteger _subIdx
Definition ShipEntity.h:342

◆ setSunGlareFilter:

- (void) setSunGlareFilter: (GLfloat) newValue

Definition at line 14954 of file ShipEntity.m.

1211 :(GLfloat)newValue
1212{
1213 sunGlareFilter = OOClamp_0_1_f(newValue);
1214}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setSunSkimEndCoordinates

- (void) setSunSkimEndCoordinates
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2028{
2029 if ([UNIVERSE sun] == nil)
2030 {
2031 [shipAI message:@"NO_SUN_FOUND"];
2032 return;
2033 }
2034
2035 coordinates = [UNIVERSE getSunSkimEndPositionForShip:self];
2036 [shipAI message:@"APPROACH_COORDINATES"];
2037}

◆ setSunSkimExitCoordinates

- (void) setSunSkimExitCoordinates
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2041{
2042 Entity *the_sun = [UNIVERSE sun];
2043 if (the_sun == nil) return;
2044 HPVector v1 = [UNIVERSE getSunSkimEndPositionForShip:self];
2045 HPVector vs = the_sun->position;
2046 HPVector vout = HPvector_subtract(v1,vs);
2047 if (vout.x||vout.y||vout.z)
2048 vout = HPvector_normal(vout);
2049 else
2050 vout.z = 1.0;
2051 v1.x += 10000 * vout.x; v1.y += 10000 * vout.y; v1.z += 10000 * vout.z;
2052 coordinates = v1;
2053 [shipAI message:@"APPROACH_COORDINATES"];
2054}

◆ setSunSkimStartCoordinates

- (void) setSunSkimStartCoordinates
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2006{
2007 if ([UNIVERSE sun] == nil)
2008 {
2009 [shipAI message:@"NO_SUN_FOUND"];
2010 return;
2011 }
2012
2013 HPVector v0 = [UNIVERSE getSunSkimStartPositionForShip:self];
2014
2015 if (!HPvector_equal(v0, kZeroHPVector))
2016 {
2017 coordinates = v0;
2018 [shipAI message:@"APPROACH_COORDINATES"];
2019 }
2020 else
2021 {
2022 [shipAI message:@"WAIT_FOR_SUN"];
2023 }
2024}

◆ setSuppressExplosion:

- (void) setSuppressExplosion: (BOOL) suppress

Definition at line 9593 of file ShipEntity.m.

9794 :(BOOL)suppress
9795{
9796 suppressExplosion = !!suppress;
9797}

◆ setTakeOffFromPlanet

- (void) setTakeOffFromPlanet
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setTargetForScript:

- (void) setTargetForScript: (ShipEntity *) target

Provided by category ShipEntity(OOJavaScriptExtensions).

Definition at line 1 of file EntityOOJavaScriptExtensions.m.

140 :(ShipEntity *)target
141{
142 ShipEntity *me = self;
143
144 // Ensure coherence by not fiddling with subentities.
145 while ([me isSubEntity])
146 {
147 if (me == [me owner] || [me owner] == nil) break;
148 me = (ShipEntity *)[me owner];
149 }
150 while ([target isSubEntity])
151 {
152 if (target == [target owner] || [target owner] == nil) break;
153 target = (ShipEntity *)[target owner];
154 }
155 if (![me isKindOfClass:[ShipEntity class]]) return;
156 if (target != nil)
157 {
158 [me addTarget:target];
159 }
160 else [me removeTarget:[me primaryTarget]];
161}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setTargetStation:

- (void) setTargetStation: (Entity *) targetEntity

Definition at line 9593 of file ShipEntity.m.

10025 :(Entity *) targetEntity
10026{
10027 [_targetStation release];
10028 _targetStation = [targetEntity weakRetain];
10029}
OOWeakReference * _targetStation
Definition ShipEntity.h:439

◆ setTargetToFoundTarget

- (void) setTargetToFoundTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setTargetToLastStation

- (void) setTargetToLastStation
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2544{
2545 Entity *station = [self targetStation];
2546
2547 if (station != nil && [station isStation])
2548 {
2549 [self addTarget:station];
2550 }
2551 else
2552 {
2553 [shipAI message:@"NO_STATION_FOUND"];
2554 [self setTargetStation:nil];
2555 }
2556
2557}

◆ setTargetToNearestFriendlyStation

- (void) setTargetToNearestFriendlyStation

Definition at line 9593 of file ShipEntity.m.

13986{
13987 [self setTargetToNearestStationIncludingHostiles:NO];
13988}

◆ setTargetToNearestStation

- (void) setTargetToNearestStation

Definition at line 9593 of file ShipEntity.m.

13993{
13994 [self setTargetToNearestStationIncludingHostiles:YES];
13995}

◆ setTargetToNearestStationIncludingHostiles:

- (void) setTargetToNearestStationIncludingHostiles: (BOOL) includeHostiles
implementation

Definition at line 9593 of file ShipEntity.m.

13934 :(BOOL) includeHostiles
13935{
13936 // check if the groupID (parent ship) points to a station...
13937 Entity *mother = [[self group] leader];
13938 if ([mother isStation])
13939 {
13940 [self addTarget:mother];
13941 [self setTargetStation:mother];
13942 return; // head for mother!
13943 }
13944
13945 /*- selects the nearest station it can find -*/
13946 if (!UNIVERSE)
13947 return;
13948 int ent_count = UNIVERSE->n_entities;
13949 Entity **uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
13950 Entity *my_entities[ent_count];
13951 int i;
13952 int station_count = 0;
13953 for (i = 0; i < ent_count; i++)
13954 if (uni_entities[i]->isStation)
13955 my_entities[station_count++] = [uni_entities[i] retain]; // retained
13956 //
13957 StationEntity *thing = nil, *station = nil;
13958 double range2, nearest2 = SCANNER_MAX_RANGE2 * 1000000.0; // 1000x typical scanner range (25600 km), squared.
13959 for (i = 0; i < station_count; i++)
13960 {
13961 thing = (StationEntity *)my_entities[i];
13962 range2 = HPdistance2(position, thing->position);
13963 if (range2 < nearest2 && (includeHostiles || ![thing isHostileTo:self]))
13964 {
13965 station = thing;
13966 nearest2 = range2;
13967 }
13968 }
13969 for (i = 0; i < station_count; i++)
13970 [my_entities[i] release]; // released
13971 //
13972 if (station)
13973 {
13974 [self addTarget:station];
13975 [self setTargetStation:station];
13976 }
13977 else
13978 {
13979 [shipAI message:@"NO_STATION_FOUND"];
13980 }
13981}

◆ setTargetToPrimaryAggressor

- (void) setTargetToPrimaryAggressor
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setTargetToRandomStation

- (void) setTargetToRandomStation
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ setTargetToSystemStation

- (void) setTargetToSystemStation

Definition at line 9593 of file ShipEntity.m.

14000{
14001 StationEntity* system_station = [UNIVERSE station];
14002
14003 if (!system_station)
14004 {
14005 [shipAI message:@"NOTHING_FOUND"];
14006 [shipAI message:@"NO_STATION_FOUND"];
14008 [self setTargetStation:nil];
14009 return;
14010 }
14011
14012 if (!system_station->isStation)
14013 {
14014 [shipAI message:@"NOTHING_FOUND"];
14015 [shipAI message:@"NO_STATION_FOUND"];
14017 [self setTargetStation:nil];
14018 return;
14019 }
14020
14021 [self addTarget:system_station];
14022 [self setTargetStation:system_station];
14023 return;
14024}

◆ setTemperature:

- (void) setTemperature: (GLfloat) value

Definition at line 7619 of file ShipEntity.m.

8790 :(GLfloat) value
8791{
8792 ship_temperature = value;
8793}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setThankedShip:

- (void) setThankedShip: (Entity *) targetEntity

Definition at line 9593 of file ShipEntity.m.

9987 :(Entity *) targetEntity
9988{
9989 [_thankedShip release];
9990 _thankedShip = [targetEntity weakRetain];
9991}
OOWeakReference * _thankedShip
Definition ShipEntity.h:442

◆ setThrust:

- (void) setThrust: (double) amount

Definition at line 7619 of file ShipEntity.m.

8234 :(double) amount
8235{
8236 thrust = amount;
8237}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setThrustFactorTo:

- (void) setThrustFactorTo: (NSString *) thrustFactorString
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

937 :(NSString *)thrustFactorString
938{
939 thrust = OOClamp_0_1_f([thrustFactorString doubleValue]) * max_thrust;
940}

◆ setThrustForDemo:

- (void) setThrustForDemo: (float) factor

Definition at line 7619 of file ShipEntity.m.

8240 :(float) factor
8241{
8242 flightSpeed = factor * maxFlightSpeed;
8243}

◆ setTotalVelocity:

- (void) setTotalVelocity: (Vector) vel

Definition at line 9593 of file ShipEntity.m.

12843 :(Vector)vel
12844{
12845 [self setVelocity:vector_subtract(vel, [self thrustVector])];
12846}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setTrackCloseContacts:

- (void) setTrackCloseContacts: (BOOL) value

Definition at line 14073 of file ShipEntity.m.

14392 :(BOOL) value
14393{
14394 if (value == (BOOL)trackCloseContacts) return;
14395
14396 trackCloseContacts = value;
14397 [closeContactsInfo release];
14398
14400 {
14401 closeContactsInfo = [[NSMutableDictionary alloc] init];
14402 }
14403 else
14404 {
14406 }
14407}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setUpCargoType:

- (void) setUpCargoType: (NSString *) cargoString

Definition at line 14954 of file ShipEntity.m.

1023 :(NSString *) cargoString
1024{
1025 cargo_type = StringToCargoType(cargoString);
1026
1027 switch (cargo_type)
1028 {
1029 case CARGO_SLAVES:
1030 commodity_amount = 1;
1032 commodity_type = @"slaves";
1033 cargo_type = CARGO_RANDOM; // not realy random, but it tells that cargo is selected.
1034 break;
1035
1036 case CARGO_ALLOY:
1037 commodity_amount = 1;
1039 commodity_type = @"alloys";
1041 break;
1042
1043 case CARGO_MINERALS:
1044 commodity_amount = 1;
1046 commodity_type = @"minerals";
1048 break;
1049
1050 case CARGO_THARGOID:
1051 commodity_amount = 1;
1053 commodity_type = @"alien_items";
1055 break;
1056
1058 commodity_amount = 1; // value > 0 is needed to be recognised as cargo by scripts;
1059 DESTROY(commodity_type); // will be defined elsewhere when needed.
1060 break;
1061
1062 case CARGO_RANDOM:
1063 // Could already be set by the cargo_carried key. If not, ensure at least one.
1064 if (commodity_amount == 0) commodity_amount = 1;
1065 break;
1066
1067 default:
1068 break;
1069 }
1070}
OOCargoType StringToCargoType(NSString *string) PURE_FUNC
@ CARGO_THARGOID
Definition OOTypes.h:74
@ CARGO_SLAVES
Definition OOTypes.h:71
@ CARGO_ALLOY
Definition OOTypes.h:72
@ CARGO_MINERALS
Definition OOTypes.h:73

◆ setUpEscorts

- (void) setUpEscorts

Definition at line 14954 of file ShipEntity.m.

1692{
1693 // Ensure that we do not try to create escorts if we are an escort ship ourselves.
1694 // This could lead to circular reference memory overflows (e.g. "boa-mk2" trying to create 4 "boa-mk2"
1695 // escorts or the case of two ships specifying eachother as escorts) - Nikos 20090510
1696 if ([self isEscort])
1697 {
1698 OOLogWARN(@"ship.setUp.escortShipCircularReference",
1699 @"Ship %@ requested escorts, when it is an escort ship itself. Avoiding possible circular reference overflow by ignoring escort setup.", self);
1700 return;
1701 }
1702
1703 if ([shipinfoDictionary objectForKey:@"escort_roles"] != nil)
1704 {
1705 [self setUpMixedEscorts];
1706 return;
1707 }
1708
1709 NSString *defaultRole = @"escort";
1710 NSString *escortRole = nil;
1711 NSString *escortShipKey = nil;
1712
1713 if (_pendingEscortCount == 0) return;
1714
1716 {
1717 if ([self hasPrimaryRole:@"police"] || [self hasPrimaryRole:@"hunter"])
1718 {
1719 _maxEscortCount = MAX_ESCORTS; // police and hunters get up to MAX_ESCORTS, overriding the 'escorts' key.
1720 [self updateEscortFormation];
1721 }
1722 else
1723 {
1724 _pendingEscortCount = _maxEscortCount; // other ships can only get what's defined inside their 'escorts' key.
1725 }
1726 }
1727
1728 if ([self isPolice]) defaultRole = @"wingman";
1729
1730 escortRole = [shipinfoDictionary oo_stringForKey:@"escort_role" defaultValue:nil];
1731 if (escortRole == nil)
1732 escortRole = [shipinfoDictionary oo_stringForKey:@"escort-role" defaultValue:defaultRole];
1733 if (![escortRole isEqualToString: defaultRole])
1734 {
1735 if (![[UNIVERSE newShipWithRole:escortRole] autorelease])
1736 {
1737 escortRole = defaultRole;
1738 }
1739 }
1740
1741 escortShipKey = [shipinfoDictionary oo_stringForKey:@"escort_ship" defaultValue:nil];
1742 if (escortShipKey == nil)
1743 escortShipKey = [shipinfoDictionary oo_stringForKey:@"escort-ship"];
1744
1745 if (escortShipKey != nil)
1746 {
1747 if (![[UNIVERSE newShipWithName:escortShipKey] autorelease])
1748 {
1749 escortShipKey = nil;
1750 }
1751 else
1752 {
1753 escortRole = [NSString stringWithFormat:@"[%@]",escortShipKey];
1754 }
1755 }
1756
1757 OOShipGroup *escortGroup = [self escortGroup];
1758 if ([self group] == nil)
1759 {
1760 [self setGroup:escortGroup]; // should probably become a copy of the escortGroup post NMSR.
1761 }
1762 [escortGroup setLeader:self];
1763
1764 [self refreshEscortPositions];
1765
1766 uint8_t currentEscortCount = [escortGroup count] - 1; // always at least 0.
1767
1768 while (_pendingEscortCount > 0 && ([self isThargoid] || currentEscortCount < _maxEscortCount))
1769 {
1770 // The following line adds escort 1 in position 1, etc... up to MAX_ESCORTS.
1771 HPVector ex_pos = [self coordinatesForEscortPosition:currentEscortCount];
1772
1773 ShipEntity *escorter = nil;
1774
1775 escorter = [UNIVERSE newShipWithRole:escortRole]; // retained
1776
1777 if (escorter == nil) break;
1778 [self setUpOneEscort:escorter inGroup:escortGroup withRole:escortRole atPosition:ex_pos andCount:currentEscortCount];
1779
1780 [escorter release];
1781
1783 currentEscortCount = [escortGroup count] - 1;
1784 }
1785 // done assigning escorts
1787}

◆ setUpFromDictionary:

- (BOOL) setUpFromDictionary: (NSDictionary *) shipDict

Definition at line 14954 of file ShipEntity.m.

240 :(NSDictionary *) shipDict
241{
243
244 // Settings shared by players & NPCs.
245 //
246 // In order for default values to work and float values to not be junk,
247 // replace nil with empty dictionary. -- Ahruman 2008-04-28
248 shipinfoDictionary = [shipDict copy];
249 if (shipinfoDictionary == nil) shipinfoDictionary = [[NSDictionary alloc] init];
250 shipDict = shipinfoDictionary; // Ensure no mutation.
251
252 // set these flags explicitly.
254 haveStartedJSAI = NO;
255 scripted_misjump = NO;
257 being_fined = NO;
260 isMissile = NO;
262 _lightsActive = YES;
263
264
265 // set things from dictionary from here out - default values might require adjustment -- Kaks 20091130
266 _scaleFactor = [shipDict oo_floatForKey:@"model_scale_factor" defaultValue:1.0f];
267
268
269 float defaultSpeed = isStation ? 0.0f : 160.0f;
270 maxFlightSpeed = [shipDict oo_floatForKey:@"max_flight_speed" defaultValue:defaultSpeed];
271 max_flight_roll = [shipDict oo_floatForKey:@"max_flight_roll" defaultValue:2.0f];
272 max_flight_pitch = [shipDict oo_floatForKey:@"max_flight_pitch" defaultValue:1.0f];
273 max_flight_yaw = [shipDict oo_floatForKey:@"max_flight_yaw" defaultValue:max_flight_pitch]; // Note by default yaw == pitch
275
276 max_thrust = [shipDict oo_floatForKey:@"thrust" defaultValue:15.0f];
278
279 afterburner_rate = [shipDict oo_floatForKey:@"injector_burn_rate" defaultValue:AFTERBURNER_BURNRATE];
280 afterburner_speed_factor = [shipDict oo_floatForKey:@"injector_speed_factor" defaultValue:7.0f];
281 if (afterburner_speed_factor < 1.0)
282 {
283 OOLog(@"ship.setup.injectorSpeed",@"injector_speed_factor cannot be lower than 1.0 for %@",self);
285 }
286#if OO_VARIABLE_TORUS_SPEED
288 {
289 OOLog(@"ship.setup.injectorSpeed",@"injector_speed_factor cannot be higher than minimum torus speed factor (%f) for %@.",MIN_HYPERSPEED_FACTOR,self);
291 }
292#else
294 {
295 OOLog(@"ship.setup.injectorSpeed",@"injector_speed_factor cannot be higher than torus speed factor (%f) for %@.",HYPERSPEED_FACTOR,self);
297 }
298#endif
299
300 maxEnergy = [shipDict oo_floatForKey:@"max_energy" defaultValue:200.0f];
301 energy_recharge_rate = [shipDict oo_floatForKey:@"energy_recharge_rate" defaultValue:1.0f];
302
303 _showDamage = [shipDict oo_boolForKey:@"show_damage" defaultValue:(energy_recharge_rate > 0)];
304 // Each new ship should start in seemingly good operating condition, unless specifically told not to - this does not affect the ship's energy levels
305 [self setThrowSparks:[shipDict oo_boolForKey:@"throw_sparks" defaultValue:NO]];
306
307 weapon_facings = [shipDict oo_intForKey:@"weapon_facings" defaultValue:VALID_WEAPON_FACINGS] & VALID_WEAPON_FACINGS;
309 forward_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"forward_weapon_type" defaultValue:@"EQ_WEAPON_NONE"]);
311 aft_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"aft_weapon_type" defaultValue:@"EQ_WEAPON_NONE"]);
313 port_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"port_weapon_type" defaultValue:@"EQ_WEAPON_NONE"]);
315 starboard_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"starboard_weapon_type" defaultValue:@"EQ_WEAPON_NONE"]);
316
319 cloakPassive = [shipDict oo_boolForKey:@"cloak_passive" defaultValue:YES]; // Nikos - switched passive cloak default to YES 20120523
320 cloakAutomatic = [shipDict oo_boolForKey:@"cloak_automatic" defaultValue:YES];
321
322 missiles = [shipDict oo_intForKey:@"missiles" defaultValue:0];
323 /* TODO: The following initializes the missile list to be blank, which prevents a crash caused by hasOneEquipmentItem trying to access a missile list
324 previously initialized but then released. See issue #204. We need to investigate further the cause of the missile list being released.
325 - kanthoney 10/03/2017
326 Update 20170818: The issue seems to have been resolved properly using the fix below and the problem was apparently an access of the
327 missile_list array elements before their initialization and while we were checking whether equipment can be added or not. There is
328 probably not much more that can be done here, unless someone would like to have a go at refactoring the entire ship initialization
329 code. In any case, the crash is no more and the applied solution is both simple and logical - Nikos
330 */
331 unsigned i;
332 for (i = 0; i < missiles; i++)
333 {
334 missile_list[i] = nil;
335 }
336 max_missiles = [shipDict oo_intForKey:@"max_missiles" defaultValue:missiles];
339 missile_load_time = fmax(0.0, [shipDict oo_doubleForKey:@"missile_load_time" defaultValue:0.0]); // no negative load times
340 missile_launch_time = [UNIVERSE getTime] + missile_load_time;
341
342 // upgrades:
343 equipment_weight = 0;
344 if ([shipDict oo_fuzzyBooleanForKey:@"has_ecm"]) [self addEquipmentItem:@"EQ_ECM" inContext:@"npc"];
345 if ([shipDict oo_fuzzyBooleanForKey:@"has_scoop"]) [self addEquipmentItem:@"EQ_FUEL_SCOOPS" inContext:@"npc"];
346 if ([shipDict oo_fuzzyBooleanForKey:@"has_escape_pod"]) [self addEquipmentItem:@"EQ_ESCAPE_POD" inContext:@"npc"];
347 if ([shipDict oo_fuzzyBooleanForKey:@"has_cloaking_device"]) [self addEquipmentItem:@"EQ_CLOAKING_DEVICE" inContext:@"npc"];
348 if ([shipDict oo_floatForKey:@"has_energy_bomb"] > 0)
349 {
350 /* NOTE: has_energy_bomb actually refers to QC mines.
351
352 max_missiles for NPCs is a newish addition, and ships have
353 traditionally not needed to reserve a slot for a Q-mine added this
354 way. If has_energy_bomb is possible, and max_missiles is not
355 explicit, we add an extra missile slot to compensate.
356 -- Ahruman 2011-03-25
357 */
358 if ([shipDict oo_fuzzyBooleanForKey:@"has_energy_bomb"])
359 {
360 if (max_missiles == missiles && max_missiles < SHIPENTITY_MAX_MISSILES && [shipDict objectForKey:@"max_missiles"] == nil)
361 {
362 max_missiles++;
363 }
364 [self addEquipmentItem:@"EQ_QC_MINE" inContext:@"npc"];
365 }
366 }
367
368 if ([shipDict oo_fuzzyBooleanForKey:@"has_fuel_injection"]) [self addEquipmentItem:@"EQ_FUEL_INJECTION" inContext:@"npc"];
369
370#if USEMASC
371 if ([shipDict oo_fuzzyBooleanForKey:@"has_military_jammer"]) [self addEquipmentItem:@"EQ_MILITARY_JAMMER" inContext:@"npc"];
372 if ([shipDict oo_fuzzyBooleanForKey:@"has_military_scanner_filter"]) [self addEquipmentItem:@"EQ_MILITARY_SCANNER_FILTER" inContext:@"npc"];
373#endif
374
375
376 // can it be 'mined' for alloys?
377 canFragment = [shipDict oo_fuzzyBooleanForKey:@"fragment_chance" defaultValue:0.9];
378 isWreckage = NO;
379
380 // can subentities be destroyed separately?
381 isFrangible = [shipDict oo_boolForKey:@"frangible" defaultValue:YES];
382
383 max_cargo = [shipDict oo_unsignedIntForKey:@"max_cargo"];
384 extra_cargo = [shipDict oo_unsignedIntForKey:@"extra_cargo" defaultValue:15];
385
386 hyperspaceMotorSpinTime = [shipDict oo_floatForKey:@"hyperspace_motor_spin_time" defaultValue:DEFAULT_HYPERSPACE_SPIN_TIME];
387 if(![shipDict oo_boolForKey:@"hyperspace_motor" defaultValue:YES]) hyperspaceMotorSpinTime = -1;
388
389 [name autorelease];
390 name = [[shipDict oo_stringForKey:@"name" defaultValue:@"?"] copy];
391
392 [shipUniqueName autorelease];
393 shipUniqueName = [[shipDict oo_stringForKey:@"ship_name" defaultValue:@""] copy];
394
395 [shipClassName autorelease];
396 shipClassName = [[shipDict oo_stringForKey:@"ship_class_name" defaultValue:name] copy];
397
398 [displayName autorelease];
399 displayName = [[shipDict oo_stringForKey:@"display_name" defaultValue:nil] copy];
400
401 // Load the model (must be before subentities)
402 NSString *modelName = [shipDict oo_stringForKey:@"model"];
403 if (modelName != nil)
404 {
405 OOMesh *mesh = nil;
406
407 mesh = [OOMesh meshWithName:modelName
408 cacheKey:[NSString stringWithFormat:@"%@-%.3f",_shipKey,_scaleFactor]
409 materialDictionary:[shipDict oo_dictionaryForKey:@"materials"]
410 shadersDictionary:[shipDict oo_dictionaryForKey:@"shaders"]
411 smooth:[shipDict oo_boolForKey:@"smooth" defaultValue:NO]
412 shaderMacros:OODefaultShipShaderMacros()
414 scaleFactor:_scaleFactor
415 cacheWriteable:YES];
416
417 if (mesh == nil) return NO;
418 [self setMesh:mesh];
419 }
420
421 float density = [shipDict oo_floatForKey:@"density" defaultValue:1.0f];
422 if (octree) mass = (GLfloat)(density * 20.0f * [octree volume]);
423
425 default_laser_color = [[OOColor brightColorWithDescription:[shipDict objectForKey:@"laser_color"]] retain];
426
427 if (default_laser_color == nil)
428 {
429 [self setLaserColor:[OOColor redColor]];
430 }
431 else
432 {
433 [self setLaserColor:default_laser_color];
434 }
435 // exhaust emissive color
436 OORGBAComponents defaultExhaustEmissiveColorComponents; // pale blue is exhaust default color
437 defaultExhaustEmissiveColorComponents.r = 0.7f;
438 defaultExhaustEmissiveColorComponents.g = 0.9f;
439 defaultExhaustEmissiveColorComponents.b = 1.0f;
440 defaultExhaustEmissiveColorComponents.a = 0.9f;
441 OOColor *color = [OOColor brightColorWithDescription:[shipDict objectForKey:@"exhaust_emissive_color"]];
442 if (color == nil) color = [OOColor colorWithRGBAComponents:defaultExhaustEmissiveColorComponents];
443 [self setExhaustEmissiveColor:color];
444
445 [self clearSubEntities];
446 [self setUpSubEntities];
447
448// correctly initialise weaponRange, etc. (must be after subentity setup)
450 {
451 OOWeaponType weapon_type = nil;
452 BOOL hasTurrets = NO;
453 NSEnumerator *subEnum = [self shipSubEntityEnumerator];
454 ShipEntity *se = nil;
455 while (isWeaponNone(weapon_type) && (se = [subEnum nextObject]))
456 {
457 weapon_type = se->forward_weapon_type;
458 if (se->behaviour == BEHAVIOUR_TRACK_AS_TURRET)
459 {
460 hasTurrets = YES;
461 }
462 }
463 if (isWeaponNone(weapon_type) && hasTurrets)
464 { /* safety for ships only equipped with turrets
465 note: this was hard-coded to 10000.0, although turrets have a notably
466 shorter range. We are using a multiplier of 1.667 in order to not change
467 something that already works, but probably it would be best to use
468 TURRET_SHOT_RANGE * COMBAT_WEAPON_RANGE_FACTOR here
469 */
471 }
472 else
473 {
474 [self setWeaponDataFromType:weapon_type];
475 }
476 }
477 else
478 {
479 [self setWeaponDataFromType:forward_weapon_type];
480 }
481
482 // rotating subentities
484 if ([shipDict objectForKey:@"rotational_velocity"])
485 {
486 subentityRotationalVelocity = [shipDict oo_quaternionForKey:@"rotational_velocity"];
487 }
488
489 // set weapon offsets
490 NSString *weaponMountMode = [shipDict oo_stringForKey:@"weapon_mount_mode" defaultValue:@"single"];
491 _multiplyWeapons = [weaponMountMode isEqualToString:@"multiply"];
492 forwardWeaponOffset = [[self getWeaponOffsetFrom:shipDict withKey:@"weapon_position_forward" inMode:weaponMountMode] retain];
493 aftWeaponOffset = [[self getWeaponOffsetFrom:shipDict withKey:@"weapon_position_aft" inMode:weaponMountMode] retain];
494 portWeaponOffset = [[self getWeaponOffsetFrom:shipDict withKey:@"weapon_position_port" inMode:weaponMountMode] retain];
495 starboardWeaponOffset = [[self getWeaponOffsetFrom:shipDict withKey:@"weapon_position_starboard" inMode:weaponMountMode] retain];
496
497
498 tractor_position = vector_multiply_scalar([shipDict oo_vectorForKey:@"scoop_position"],_scaleFactor);
499
500
501
502 // sun glare filter - default is high filter, both for HDR and SDR
503 [self setSunGlareFilter:[shipDict oo_floatForKey:@"sun_glare_filter" defaultValue:0.97f]];
504
505 // Get scriptInfo dictionary, containing arbitrary stuff scripts might be interested in.
506 scriptInfo = [[shipDict oo_dictionaryForKey:@"script_info" defaultValue:nil] retain];
507
508 explosionType = [[shipDict oo_arrayForKey:@"explosion_type" defaultValue:nil] retain];
509
510 isDemoShip = NO;
511
512 return YES;
513
515}
#define VALID_WEAPON_FACINGS
Definition OOTypes.h:239
#define HYPERSPEED_FACTOR
#define SHIPENTITY_MAX_MISSILES
Definition ShipEntity.h:77
OOWeaponType OOWeaponTypeFromString(NSString *string) PURE_FUNC
OOColor * colorWithRGBAComponents:(OORGBAComponents components)
Definition OOColor.m:109
OOColor * brightColorWithDescription:(id description)
Definition OOColor.m:205
OOColor * redColor()
Definition OOColor.m:268
OOWeaponFacingSet weapon_facings
Definition ShipEntity.h:304
unsigned haveStartedJSAI
Definition ShipEntity.h:280
unsigned _showDamage
Definition ShipEntity.h:270
unsigned haveExecutedSpawnAction
Definition ShipEntity.h:279

◆ setUpMixedEscorts

- (void) setUpMixedEscorts
implementation

Provided by category ShipEntity(Private).

Definition at line 14954 of file ShipEntity.m.

1791{
1792 NSArray *escortRoles = [shipinfoDictionary oo_arrayForKey:@"escort_roles" defaultValue:nil];
1793 if (escortRoles == nil)
1794 {
1795 OOLogWARN(@"eship.setUp.escortShipRoles",
1796 @"Ship %@ has bad escort_roles definition.", self);
1797 return;
1798 }
1799 NSEnumerator *edefEnumerator = nil;
1800 NSDictionary *escortDefinition = nil;
1801 NSDictionary *systeminfo = nil;
1802 OOGovernmentID government;
1803
1804 systeminfo = [UNIVERSE currentSystemData];
1805 government = [systeminfo oo_unsignedCharForKey:KEY_GOVERNMENT];
1806
1807 OOShipGroup *escortGroup = [self escortGroup];
1808 if ([self group] == nil)
1809 {
1810 [self setGroup:escortGroup]; // should probably become a copy of the escortGroup post NMSR.
1811 }
1812 [escortGroup setLeader:self];
1814 [self refreshEscortPositions];
1815
1816 uint8_t currentEscortCount = [escortGroup count] - 1; // always at least 0
1817
1818 _maxEscortCount = 0;
1819 int8_t i = 0;
1820 for (edefEnumerator = [escortRoles objectEnumerator]; (escortDefinition = [edefEnumerator nextObject]); )
1821 {
1822 if (currentEscortCount >= MAX_ESCORTS)
1823 {
1824 break;
1825 }
1826 // int rather than uint because, at least for min, there is a
1827 // use to giving a negative value
1828 int8_t min = [escortDefinition oo_intForKey:@"min" defaultValue:0];
1829 int8_t max = [escortDefinition oo_intForKey:@"max" defaultValue:2];
1830 NSString *escortRole = [escortDefinition oo_stringForKey:@"role" defaultValue:@"escort"];
1831 int8_t desired = max;
1832 if (min < desired)
1833 {
1834 for (i = min ; i < max ; i++)
1835 {
1836 if (Ranrot()%11 < government+2)
1837 {
1838 desired--;
1839 }
1840 }
1841 }
1842 for (i = 0; i < desired; i++)
1843 {
1844 if (currentEscortCount >= MAX_ESCORTS)
1845 {
1846 break;
1847 }
1848 if (![escortRole isEqualToString:@""])
1849 {
1850 HPVector ex_pos = [self coordinatesForEscortPosition:currentEscortCount];
1851 ShipEntity *escorter = [UNIVERSE newShipWithRole:escortRole]; // retained
1852 if (escorter == nil)
1853 {
1854 break;
1855 }
1856 [self setUpOneEscort:escorter inGroup:escortGroup withRole:escortRole atPosition:ex_pos andCount:currentEscortCount];
1857 [escorter release];
1858 }
1859 currentEscortCount++;
1861 }
1862 }
1863 // done assigning escorts
1865}
uint8_t OOGovernmentID
Definition OOTypes.h:206

◆ setUpOneEscort:inGroup:withRole:atPosition:andCount:

- (void) setUpOneEscort: (ShipEntity *) escorter
inGroup: (OOShipGroup *) escortGroup
withRole: (NSString *) escortRole
atPosition: (HPVector) ex_pos
andCount: (uint8_t) currentEscortCount 
implementation

Provided by category ShipEntity(Private).

Definition at line 14954 of file ShipEntity.m.

1868 :(ShipEntity *)escorter inGroup:(OOShipGroup *)escortGroup withRole:(NSString *)escortRole atPosition:(HPVector)ex_pos andCount:(uint8_t)currentEscortCount
1869{
1870 NSString *autoAI = nil;
1871 NSString *pilotRole = nil;
1872 NSDictionary *autoAIMap = nil;
1873 NSDictionary *escortShipDict = nil;
1874 AI *escortAI = nil;
1875 NSString *defaultRole = @"escort";
1876
1877 if ([self isPolice])
1878 {
1879 defaultRole = @"wingman";
1880 pilotRole = @"police"; // police are always insured.
1881 }
1882 else
1883 {
1884 pilotRole = bounty ? @"pirate" : @"hunter"; // hunters have insurancies, pirates not.
1885 }
1886
1887 double dd = escorter->collision_radius;
1888
1889 if (EXPECT(currentEscortCount < (uint8_t)MAX_ESCORTS))
1890 {
1891 // spread them around a little randomly
1892 ex_pos.x += dd * 6.0 * (randf() - 0.5);
1893 ex_pos.y += dd * 6.0 * (randf() - 0.5);
1894 ex_pos.z += dd * 6.0 * (randf() - 0.5);
1895 }
1896 else
1897 {
1898 // Thargoid armada(!) Add more distance between the 'escorts'.
1899 ex_pos.x += dd * 12.0 * (randf() - 0.5);
1900 ex_pos.y += dd * 12.0 * (randf() - 0.5);
1901 ex_pos.z += dd * 12.0 * (randf() - 0.5);
1902 }
1903
1904 [escorter setPosition:ex_pos]; // minimise lollipop flash
1905
1906 if ([escorter crew] == nil)
1907 {
1908 [escorter setSingleCrewWithRole:pilotRole];
1909 }
1910
1911 [escorter setPrimaryRole:defaultRole]; //for mothership
1912 // in case this hasn't yet been set, make sure escorts get a real scan class
1913 // shouldn't happen very often, but is possible
1914 if (scanClass == CLASS_NOT_SET)
1915 {
1916 scanClass = CLASS_NEUTRAL;
1917 }
1918 [escorter setScanClass:scanClass]; // you are the same as I
1919
1920 if ([self bounty] == 0) [escorter setBounty:0 withReason:kOOLegalStatusReasonSetup]; // Avoid dirty escorts for clean mothers
1921
1922 // find the right autoAI.
1923 escortShipDict = [escorter shipInfoDictionary];
1924 autoAIMap = [ResourceManager dictionaryFromFilesNamed:@"autoAImap.plist" inFolder:@"Config" andMerge:YES];
1925 autoAI = [autoAIMap oo_stringForKey:defaultRole];
1926 if (autoAI==nil) // no 'wingman' defined in autoAImap?
1927 {
1928 autoAI = [autoAIMap oo_stringForKey:@"escort" defaultValue:@"nullAI.plist"];
1929 }
1930
1931 escortAI = [escorter getAI];
1932
1933 // Let the populator decide which AI to use, unless we have a working alternative AI & we specify auto_ai = NO !
1934 if ( (escortRole && [escortShipDict oo_fuzzyBooleanForKey:@"auto_ai" defaultValue:YES])
1935 || ([[escortAI name] isEqualToString: @"nullAI.plist"] && ![autoAI isEqualToString:@"nullAI.plist"]) )
1936 {
1937 [escorter switchAITo:autoAI];
1938 }
1939
1940 [escorter setGroup:escortGroup];
1941 [escorter setOwner:self]; // mark self as group leader
1942
1943
1944 if ([self status] == STATUS_DOCKED)
1945 {
1946 [[self owner] addShipToLaunchQueue:escorter withPriority:NO];
1947 }
1948 else
1949 {
1950 [UNIVERSE addEntity:escorter]; // STATUS_IN_FLIGHT, AI state GLOBAL
1951 [escortAI setState:@"FLYING_ESCORT"]; // Begin escort flight. (If the AI doesn't define FLYING_ESCORT, this has no effect.)
1952 [escorter doScriptEvent:OOJSID("spawnedAsEscort") withArgument:self];
1953 }
1954
1955 if([escorter heatInsulation] < [self heatInsulation]) [escorter setHeatInsulation:[self heatInsulation]]; // give escorts same protection as mother.
1956 if(([escorter maxFlightSpeed] < cruiseSpeed) && ([escorter maxFlightSpeed] > cruiseSpeed * 0.3))
1957 cruiseSpeed = [escorter maxFlightSpeed] * 0.99; // adapt patrolSpeed to the slowest escort but ignore the very slow ones.
1958
1959
1960 if (bounty)
1961 {
1962 int extra = 1 | (ranrot_rand() & 15);
1963 // if mothership is offender, make sure escorter is too.
1964 [escorter markAsOffender:extra withReason:kOOLegalStatusReasonSetup];
1965 }
1966 else
1967 {
1968 // otherwise force the escort to be clean
1969 [escorter setBounty:0 withReason:kOOLegalStatusReasonSetup];
1970 }
1971
1972}
void setState:(NSString *stateName)
Definition AI.m:334
NSDictionary * dictionaryFromFilesNamed:inFolder:andMerge:(NSString *fileName,[inFolder] NSString *folderName,[andMerge] BOOL mergeFiles)
void setSingleCrewWithRole:(NSString *crewRole)
void setPrimaryRole:(NSString *role)

◆ setUpOneFlasher:

- (BOOL) setUpOneFlasher: (NSDictionary *) subentDict
implementation

Provided by category ShipEntity(Private).

Definition at line 14954 of file ShipEntity.m.

926 :(NSDictionary *) subentDict
927{
929 [flasher setPosition:HPvector_multiply_scalar([subentDict oo_hpvectorForKey:@"position"],_scaleFactor)];
930 [flasher rescaleBy:_scaleFactor];
931 [self addSubEntity:flasher];
932 return YES;
933}
instancetype flasherWithDictionary:(NSDictionary *dictionary)
void rescaleBy:(GLfloat factor)

◆ setUpOneStandardSubentity:asTurret:

- (BOOL) setUpOneStandardSubentity: (NSDictionary *) subentDict
asTurret: (BOOL) asTurret 

Definition at line 14954 of file ShipEntity.m.

936 :(NSDictionary *)subentDict asTurret:(BOOL)asTurret
937{
938 ShipEntity *subentity = nil;
939 NSString *subentKey = nil;
940 HPVector subPosition;
941 Quaternion subOrientation;
942
943 subentKey = [subentDict oo_stringForKey:@"subentity_key"];
944 if (subentKey == nil) {
945 OOLog(@"setup.ship.badEntry.subentities",@"Failed to set up entity - no subentKey in %@",subentDict);
946 return NO;
947 }
948
949 if (!asTurret && [self isStation] && [subentDict oo_boolForKey:@"is_dock"])
950 {
951 subentity = [UNIVERSE newDockWithName:subentKey andScaleFactor:_scaleFactor];
952 }
953 else
954 {
955 subentity = [UNIVERSE newSubentityWithName:subentKey andScaleFactor:_scaleFactor];
956 }
957 if (subentity == nil) {
958 OOLog(@"setup.ship.badEntry.subentities",@"Failed to set up entity %@",subentKey);
959 return NO;
960 }
961
962 subPosition = HPvector_multiply_scalar([subentDict oo_hpvectorForKey:@"position"],_scaleFactor);
963 subOrientation = [subentDict oo_quaternionForKey:@"orientation"];
964
965 [subentity setPosition:subPosition];
966 [subentity setOrientation:subOrientation];
967 [subentity setReference:vector_forward_from_quaternion(subOrientation)];
968 // subentities inherit parent personality
969 [subentity setEntityPersonalityInt:[self entityPersonalityInt]];
970
971 if (asTurret)
972 {
973 [subentity setBehaviour:BEHAVIOUR_TRACK_AS_TURRET];
974 [subentity setWeaponRechargeRate:[subentDict oo_floatForKey:@"fire_rate" defaultValue:TURRET_SHOT_FREQUENCY]];
975 [subentity setWeaponEnergy:[subentDict oo_floatForKey:@"weapon_energy" defaultValue:TURRET_TYPICAL_ENERGY]];
976 [subentity setWeaponRange:[subentDict oo_floatForKey:@"weapon_range" defaultValue:TURRET_SHOT_RANGE]];
977 [subentity setStatus: STATUS_ACTIVE];
978 }
979 else
980 {
981 [subentity setStatus:STATUS_INACTIVE];
982 }
983
984 [subentity overrideScriptInfo:[subentDict oo_dictionaryForKey:@"script_info"]];
985
986 [self addSubEntity:subentity];
987 [subentity setSubIdx:_maxShipSubIdx];
989
990 // update subentities
991 BoundingBox sebb = [subentity findSubentityBoundingBox];
992 bounding_box_add_vector(&totalBoundingBox, sebb.max);
993 bounding_box_add_vector(&totalBoundingBox, sebb.min);
994
995 if (!asTurret && [self isStation] && [subentDict oo_boolForKey:@"is_dock"])
996 {
997 BOOL allow_docking = [subentDict oo_boolForKey:@"allow_docking" defaultValue:YES];
998 BOOL ddc = [subentDict oo_boolForKey:@"disallowed_docking_collides" defaultValue:NO];
999 BOOL allow_launching = [subentDict oo_boolForKey:@"allow_launching" defaultValue:YES];
1000 // do not include this key in OOShipRegistry; should never be set by shipdata
1001 BOOL virtual_dock = [subentDict oo_boolForKey:@"_is_virtual_dock" defaultValue:NO];
1002 if (virtual_dock)
1003 {
1004 [(DockEntity *)subentity setVirtual];
1005 }
1006
1007 [(DockEntity *)subentity setDimensionsAndCorridor:allow_docking:ddc:allow_launching];
1008 [subentity setDisplayName:[subentDict oo_stringForKey:@"dock_label" defaultValue:@"the docking bay"]];
1009 }
1010
1011 [subentity release];
1012
1013 return YES;
1014}
void setWeaponEnergy:(float value)
void setDisplayName:(NSString *inName)
void setWeaponRange:(GLfloat value)
void setWeaponRechargeRate:(float value)
void setEntityPersonalityInt:(uint16_t value)
void setSubIdx:(NSUInteger value)
Definition ShipEntity.m:780
void overrideScriptInfo:(NSDictionary *override)
BoundingBox findSubentityBoundingBox()
void setReference:(Vector v)

◆ setUpOneSubentity:

- (BOOL) setUpOneSubentity: (NSDictionary *) subentDict
implementation

Provided by category ShipEntity(Private).

Definition at line 14954 of file ShipEntity.m.

906 :(NSDictionary *) subentDict
907{
909
910 NSString *type = nil;
911
912 type = [subentDict oo_stringForKey:@"type"];
913 if ([type isEqualToString:@"flasher"])
914 {
915 return [self setUpOneFlasher:subentDict];
916 }
917 else
918 {
919 return [self setUpOneStandardSubentity:subentDict asTurret:[type isEqualToString:@"ball_turret"]];
920 }
921
923}

◆ setUpShipFromDictionary:

- (BOOL) setUpShipFromDictionary: (NSDictionary *) shipDict

Reimplemented in DockEntity, PlayerEntity, and StationEntity.

Definition at line 14954 of file ShipEntity.m.

519 :(NSDictionary *) shipDict
520{
522
523 if (![self setUpFromDictionary:shipDict]) return NO;
524
525 // NPC-only settings.
526 //
532 reference = v_forward; // reference vector for (* turrets *)
533
534 isShip = YES;
535
536 // scan class settings. 'scanClass' is in common usage, but we could also have a more standard 'scan_class' key with higher precedence. Kaks 20090810
537 // let's see if scan_class is set...
538 scanClass = OOScanClassFromString([shipDict oo_stringForKey:@"scan_class" defaultValue:@"CLASS_NOT_SET"]);
539
540 // if not, try 'scanClass'. NOTE: non-standard capitalization is documented and entrenched.
541 if (scanClass == CLASS_NOT_SET)
542 {
543 scanClass = OOScanClassFromString([shipDict oo_stringForKey:@"scanClass" defaultValue:@"CLASS_NOT_SET"]);
544 }
545
546 [scan_description autorelease];
547 scan_description = [[shipDict oo_stringForKey:@"scan_description" defaultValue:nil] copy];
548
549 // FIXME: give NPCs shields instead.
550
551 if ([shipDict oo_fuzzyBooleanForKey:@"has_shield_booster"]) [self addEquipmentItem:@"EQ_SHIELD_BOOSTER" inContext:@"npc"];
552 if ([shipDict oo_fuzzyBooleanForKey:@"has_shield_enhancer"]) [self addEquipmentItem:@"EQ_SHIELD_ENHANCER" inContext:@"npc"];
553
554 // Start with full energy banks.
556 weapon_temp = 0.0f;
557 forward_weapon_temp = 0.0f;
558 aft_weapon_temp = 0.0f;
559 port_weapon_temp = 0.0f;
561
562 // setWeaponDataFromType inside setUpFromDictionary should set weapon_damage from the front laser.
563 // no weapon_damage? It's a missile: set weapon_damage from shipdata!
564 if (weapon_damage == 0.0)
565 {
566 weapon_damage_override = weapon_damage = [shipDict oo_floatForKey:@"weapon_energy" defaultValue:0]; // any damage value for missiles/bombs
567 }
568 else
569 {
571 }
572
573 scannerRange = [shipDict oo_floatForKey:@"scanner_range" defaultValue:(float)SCANNER_MAX_RANGE];
574
575 fuel = [shipDict oo_unsignedShortForKey:@"fuel"]; // Does it make sense that this defaults to 0? Should it not be 70? -- Ahruman
576
577 fuel_accumulator = 1.0;
578
579 [self setBounty:[shipDict oo_unsignedIntForKey:@"bounty" defaultValue:0] withReason:kOOLegalStatusReasonSetup];
580
581 [shipAI autorelease];
582 shipAI = [[AI alloc] init];
583 [shipAI setOwner:self];
584 [self setAITo:[shipDict oo_stringForKey:@"ai_type" defaultValue:@"nullAI.plist"]];
585
586 likely_cargo = [shipDict oo_unsignedIntForKey:@"likely_cargo"];
587 noRocks = [shipDict oo_fuzzyBooleanForKey:@"no_boulders"];
588
591 NSString *cargoString = [shipDict oo_stringForKey:@"cargo_carried"];
592 if (cargoString != nil)
593 {
594 if ([cargoString isEqualToString:@"SCARCE_GOODS"])
595 {
597 }
598 else if ([cargoString isEqualToString:@"PLENTIFUL_GOODS"])
599 {
601 }
602 else
603 {
605
606 OOCommodityType c_commodity = nil;
607 int c_amount = 1;
608 NSScanner *scanner = [NSScanner scannerWithString:cargoString];
609 if ([scanner scanInt:&c_amount])
610 {
611 [scanner ooliteScanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:NULL]; // skip whitespace
612 c_commodity = [[scanner string] substringFromIndex:[scanner scanLocation]];
613 if ([[UNIVERSE commodities] goodDefined:c_commodity])
614 {
615 [self setCommodityForPod:c_commodity andAmount:c_amount];
616 }
617 else
618 {
619 c_commodity = [[UNIVERSE commodities] goodNamed:c_commodity];
620 if ([[UNIVERSE commodities] goodDefined:c_commodity])
621 {
622 [self setCommodityForPod:c_commodity andAmount:c_amount];
623 }
624 }
625 }
626 else
627 {
628 c_amount = 1;
629 c_commodity = [shipDict oo_stringForKey:@"cargo_carried"];
630 if ([[UNIVERSE commodities] goodDefined:c_commodity])
631 {
632 [self setCommodityForPod:c_commodity andAmount:c_amount];
633 }
634 else
635 {
636 c_commodity = [[UNIVERSE commodities] goodNamed:c_commodity];
637 if ([[UNIVERSE commodities] goodDefined:c_commodity])
638 {
639 [self setCommodityForPod:c_commodity andAmount:c_amount];
640 }
641 }
642 }
643 }
644 }
645
646 cargoString = [shipDict oo_stringForKey:@"cargo_type"];
647 if (cargoString)
648 {
649 if (cargo != nil) [cargo autorelease];
650 cargo = [[NSMutableArray alloc] initWithCapacity:max_cargo]; // alloc retains;
651
652 [self setUpCargoType:cargoString];
653 }
654 else if (scanClass != CLASS_CARGO)
655 {
656 if (cargo != nil) [cargo autorelease];
657 cargo = [[NSMutableArray alloc] initWithCapacity:max_cargo]; // alloc retains;
658 // if not CLASS_CARGO, and no cargo type set, default to CARGO_NOT_CARGO
660 }
661
662 hasScoopMessage = [shipDict oo_boolForKey:@"has_scoop_message" defaultValue:YES];
663
664
665 [roleSet release];
666 roleSet = [[[OORoleSet roleSetWithString:[shipDict oo_stringForKey:@"roles"]] roleSetWithRemovedRole:@"player"] retain];
667 [primaryRole release];
669
670 [self setOwner:self];
671 [self setHulk:[shipDict oo_boolForKey:@"is_hulk"]];
672
673 // these are the colors used for the "lollipop" of the ship. Any of the two (or both, for flash effect) can be defined. nil means use default from shipData.
674 [self setScannerDisplayColor1:nil];
675 [self setScannerDisplayColor2:nil];
676 // and the same for the "hostile" colours
677 [self setScannerDisplayColorHostile1:nil];
678 [self setScannerDisplayColorHostile2:nil];
679
680
681 // Populate the missiles here. Must come after scanClass.
682 _missileRole = [shipDict oo_stringForKey:@"missile_role"];
683 unsigned i, j;
684 for (i = 0, j = 0; i < missiles; i++)
685 {
686 missile_list[i] = [self selectMissile];
687 // could loop forever (if missile_role is badly defined, selectMissile might return nil in some cases) . Try 3 times, and if no luck, skip
688 if (missile_list[i] == nil && j < 3)
689 {
690 j++;
691 i--;
692 }
693 else
694 {
695 j = 0;
696 if (missile_list[i] == nil)
697 {
698 missiles--;
699 }
700 }
701 }
702
703 // accuracy. Must come after scanClass, because we are using scanClass to determine if this is a missile.
704
705// missiles: range 0 to +10
706// ships: range -5 to +10, but randomly only -5 <= accuracy < +5
707// enables "better" AIs at +5 and above
708// police and military always have positive accuracy
709
710 accuracy = [shipDict oo_floatForKey:@"accuracy" defaultValue:-100.0f]; // Out-of-range default
712 {
713 accuracy = (randf() * 10.0)-5.0;
714
715 if (accuracy < 0.0f && (scanClass == CLASS_MILITARY || scanClass == CLASS_POLICE))
716 { // police and military pilots have a better average skill.
718 }
719 }
720 if (scanClass == CLASS_MISSILE)
721 { // missile accuracy range is 0 to 10
722 accuracy = OOClamp_0_max_f(accuracy, 10.0f);
723 }
724 [self setAccuracy:accuracy]; // set derived variables
725 _missed_shots = 0;
726
727 // escorts
728 _maxEscortCount = MIN([shipDict oo_unsignedCharForKey:@"escorts" defaultValue:0], (uint8_t)MAX_ESCORTS);
730 if (_pendingEscortCount == 0 && [shipDict oo_arrayForKey:@"escort_roles" defaultValue:nil] != nil)
731 {
732 // mostly ignored by setUpMixedEscorts, but needs to be high
733 // enough that it doesn't end up at zero (e.g. by governmental
734 // reductions in [Universe addShipAt]
736 }
737
738
739 // beacons
740 [self setBeaconCode:[shipDict oo_stringForKey:@"beacon"]];
741 [self setBeaconLabel:[shipDict oo_stringForKey:@"beacon_label" defaultValue:[shipDict oo_stringForKey:@"beacon"]]];
742
743
744 // contact tracking entities
745 [self setTrackCloseContacts:[shipDict oo_boolForKey:@"track_contacts" defaultValue:NO]];
746
747 // ship skin insulation factor (1.0 is normal)
748 [self setHeatInsulation:[shipDict oo_floatForKey:@"heat_insulation" defaultValue:[self hasHeatShield] ? 2.0 : 1.0]];
749
750 // unpiloted (like missiles asteroids etc.)
751 _explicitlyUnpiloted = [shipDict oo_fuzzyBooleanForKey:@"unpiloted"];
753 {
754 [self setCrew:nil];
755 }
756 else
757 {
758 // crew and passengers
759 NSDictionary *cdict = [[UNIVERSE characters] objectForKey:[shipDict oo_stringForKey:@"pilot"]];
760 if (cdict != nil)
761 {
763 [self setCrew:[NSArray arrayWithObject:pilot]];
764 }
765 }
766
767 [self setShipScript:[shipDict oo_stringForKey:@"script"]];
768
769 home_system = [UNIVERSE currentSystemID];
770 destination_system = [UNIVERSE currentSystemID];
771
772 reactionTime = [shipDict oo_floatForKey: @"reaction_time" defaultValue: COMBAT_AI_STANDARD_REACTION_TIME];
773
774 return YES;
775
777}
OOScanClass OOScanClassFromString(NSString *string) PURE_FUNC
const OOMatrix kIdentityMatrix
Definition OOMatrix.m:31
OOCharacter * characterWithDictionary:(NSDictionary *c_dict)
instancetype roleSetWithString:(NSString *roleString)
Definition OORoleSet.m:44
unsigned hasScoopMessage
Definition ShipEntity.h:275
GLfloat weapon_damage_override
Definition ShipEntity.h:310

◆ setUpSubEntities

- (BOOL) setUpSubEntities

Reimplemented in StationEntity.

Definition at line 14954 of file ShipEntity.m.

856{
858
859 unsigned int i;
860 NSDictionary *shipDict = [self shipInfoDictionary];
861 NSArray *plumes = [shipDict oo_arrayForKey:@"exhaust"];
862
864 _maxShipSubIdx = 0;
865
866 for (i = 0; i < [plumes count]; i++)
867 {
868 NSArray *definition = ScanTokensFromString([plumes oo_stringAtIndex:i]);
869 OOExhaustPlumeEntity *exhaust = [OOExhaustPlumeEntity exhaustForShip:self withDefinition:definition andScale:_scaleFactor];
870 [self addSubEntity:exhaust];
871 }
872
873 NSArray *subs = [shipDict oo_arrayForKey:@"subentities"];
874
876
877 for (i = 0; i < [subs count]; i++)
878 {
879 [self setUpOneSubentity:[subs oo_dictionaryAtIndex:i]];
880 }
881
883
884 return YES;
885
887}
#define NO_DRAW_DISTANCE_FACTOR
Definition Entity.h:46
id exhaustForShip:withDefinition:andScale:(ShipEntity *ship,[withDefinition] NSArray *definition,[andScale] float scale)

Referenced by ShipRestoreSubEntities().

+ Here is the caller graph for this function:

◆ setWeaponDataFromType:

- (void) setWeaponDataFromType: (OOWeaponType) weapon_type

Definition at line 7411 of file ShipEntity.m.

7482 : (OOWeaponType) weapon_type
7483{
7484 weaponRange = getWeaponRangeFromType(weapon_type);
7485 weapon_energy_use = [weapon_type weaponEnergyUse];
7488 weapon_damage = [weapon_type weaponDamage];
7489
7490 if (default_laser_color == nil)
7491 {
7492 OOColor *wcol = [weapon_type weaponColor];
7493 if (wcol != nil)
7494 {
7495 [self setLaserColor:wcol];
7496 }
7497 }
7498
7499}
GLfloat weaponShotTemperature()
OOColor * weaponColor()
GLfloat weaponRechargeRate()

◆ setWeaponEnergy:

- (void) setWeaponEnergy: (float) value

Definition at line 7411 of file ShipEntity.m.

7526 :(float)value
7527{
7528 weapon_damage = value;
7529}

◆ setWeaponMount:toWeapon:

- (BOOL) setWeaponMount: (OOWeaponFacing) facing
toWeapon: (NSString *) eqKey 

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3494 :(OOWeaponFacing)facing toWeapon:(NSString *)eqKey
3495{
3496 // sets WEAPON_NONE if not recognised
3497 if (weapon_facings & facing)
3498 {
3500 switch (facing)
3501 {
3503 forward_weapon_type = chosen_weapon;
3504 break;
3505
3506 case WEAPON_FACING_AFT:
3507 aft_weapon_type = chosen_weapon;
3508 break;
3509
3510 case WEAPON_FACING_PORT:
3511 port_weapon_type = chosen_weapon;
3512 break;
3513
3515 starboard_weapon_type = chosen_weapon;
3516 break;
3517
3518 case WEAPON_FACING_NONE:
3519 break;
3520 }
3521
3522 return YES;
3523 }
3524 else
3525 {
3526 return NO;
3527 }
3528}

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ setWeaponRange:

- (void) setWeaponRange: (GLfloat) value

Definition at line 7411 of file ShipEntity.m.

7476 : (GLfloat) value
7477{
7478 weaponRange = value;
7479}

◆ setWeaponRechargeRate:

- (void) setWeaponRechargeRate: (float) value

Definition at line 7411 of file ShipEntity.m.

7520 :(float)value
7521{
7522 weapon_recharge_rate = value;
7523}

◆ setYaw:

- (void) setYaw: (double) amount

Definition at line 7619 of file ShipEntity.m.

8228 :(double) amount
8229{
8230 flightYaw = amount * M_PI / 2.0;
8231}

◆ shieldBoostFactor

- (float) shieldBoostFactor

Definition at line 2093 of file ShipEntity.m.

4061{
4062 float boostFactor = 1.0f;
4063 if ([self hasShieldBooster]) boostFactor += 1.0f;
4064 if ([self hasMilitaryShieldEnhancer]) boostFactor += 1.0f;
4065
4066 return boostFactor;
4067}
BOOL hasMilitaryShieldEnhancer()
BOOL hasShieldBooster()

◆ shieldRechargeRate

- (float) shieldRechargeRate

Definition at line 2093 of file ShipEntity.m.

4085{
4086 return [self hasMilitaryShieldEnhancer] ? 3.0f : 2.0f;
4087}

◆ shipAIScript

- (OOScript *) shipAIScript

Definition at line 14954 of file ShipEntity.m.

1403{
1404 return aiScript;
1405}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ shipAIScriptWakeTime

- (OOTimeAbsolute) shipAIScriptWakeTime

Definition at line 14954 of file ShipEntity.m.

1409{
1410 return aiScriptWakeTime;
1411}

◆ shipClassName

- (NSString *) shipClassName

◆ shipDataKey

- (NSString *) shipDataKey

Definition at line 14954 of file ShipEntity.m.

1975{
1976 return _shipKey;
1977}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ shipDataKeyAutoRole

- (NSString *) shipDataKeyAutoRole

Definition at line 14954 of file ShipEntity.m.

1981{
1982 return [[[NSString alloc] initWithFormat:@"[%@]",[self shipDataKey]] autorelease];
1983}

◆ shipHitByLaser

- (ShipEntity *) shipHitByLaser

Definition at line 9593 of file ShipEntity.m.

10177{
10178 return [_shipHitByLaser weakRefUnderlyingObject];
10179}

◆ shipInfoDictionary

- (NSDictionary *) shipInfoDictionary

Definition at line 14954 of file ShipEntity.m.

1994{
1995 return shipinfoDictionary;
1996}

Referenced by ShipSetMaterialsInternal().

+ Here is the caller graph for this function:

◆ shipRestoredFromDictionary:useFallback:context:

+ (id) shipRestoredFromDictionary: (NSDictionary *) dictionary
useFallback: (BOOL) fallback
context: (NSMutableDictionary *) context 

Provided by category ShipEntity(LoadRestore).

Definition at line 365 of file ShipEntityLoadRestore.m.

173 :(NSDictionary *)dict
174 useFallback:(BOOL)fallback
175 context:(NSMutableDictionary *)context
176{
177 if (dict == nil) return nil;
178 if (context == nil) context = [NSMutableDictionary dictionary];
179
180 ShipEntity *ship = nil;
181
182 NSString *shipKey = [dict oo_stringForKey:KEY_SHIP_KEY];
183 NSDictionary *shipData = [[OOShipRegistry sharedRegistry] shipInfoForKey:shipKey];
184
185 if (shipData != nil)
186 {
187 NSMutableDictionary *mergedData = [NSMutableDictionary dictionaryWithDictionary:shipData];
188
189 StripIgnoredKeys(mergedData);
190 NSArray *deletes = [dict oo_arrayForKey:KEY_SHIPDATA_DELETES];
191 if (deletes != nil) [mergedData removeObjectsForKeys:deletes];
192 [mergedData addEntriesFromDictionary:[dict oo_dictionaryForKey:KEY_SHIPDATA_OVERRIDES]];
193 [mergedData oo_setBool:NO forKey:@"auto_ai"];
194 [mergedData oo_setUnsignedInteger:0 forKey:@"escorts"];
195
196 Class shipClass = [UNIVERSE shipClassForShipDictionary:mergedData];
197 ship = [[[shipClass alloc] initWithKey:shipKey definition:mergedData] autorelease];
198
199 // FIXME: restore AI.
200 [ship setAITo:[dict oo_stringForKey:KEY_AI defaultValue:@"nullAI.plist"]];
201
202 [ship setPrimaryRole:[dict oo_stringForKey:KEY_PRIMARY_ROLE]];
203
204 }
205 else
206 {
207 // Unknown ship; fall back on role if desired and possible.
208 NSString *shipPrimaryRole = [dict oo_stringForKey:KEY_PRIMARY_ROLE];
209 if (!fallback || shipPrimaryRole == nil) return nil;
210
211 ship = [[UNIVERSE newShipWithRole:shipPrimaryRole] autorelease];
212 if (ship == nil) return nil;
213 }
214
215 // The following stuff is deliberately set up the same way even if using role fallback.
216 [ship setPosition:[dict oo_hpvectorForKey:KEY_POSITION]];
217 [ship setNormalOrientation:[dict oo_quaternionForKey:KEY_ORIENTATION]];
218
219 float energyLevel = [dict oo_floatForKey:KEY_ENERGY_LEVEL defaultValue:1.0f];
220 [ship setEnergy:energyLevel * [ship maxEnergy]];
221
222 [ship removeAllEquipment];
223 NSEnumerator *eqEnum = nil;
224 NSString *eqKey = nil;
225 for (eqEnum = [[dict oo_arrayForKey:KEY_EQUIPMENT] objectEnumerator]; (eqKey = [eqEnum nextObject]); )
226 {
227 [ship addEquipmentItem:eqKey withValidation:NO inContext:@"loading"];
228 }
229
230 [ship removeMissiles];
231 for (eqEnum = [[dict oo_arrayForKey:KEY_MISSILES] objectEnumerator]; (eqKey = [eqEnum nextObject]); )
232 {
233 [ship addEquipmentItem:eqKey withValidation:NO inContext:@"loading"];
234 }
235
236 // Groups.
237 NSUInteger groupID = [dict oo_integerForKey:KEY_GROUP_ID defaultValue:NSNotFound];
238 if (groupID != NSNotFound)
239 {
240 OOShipGroup *group = GroupForGroupID(groupID, context);
241 [ship setGroup:group]; // Handles adding to group
242 if ([dict oo_boolForKey:KEY_IS_GROUP_LEADER]) [group setLeader:ship];
243 NSString *groupName = [dict oo_stringForKey:KEY_GROUP_NAME];
244 if (groupName != nil) [group setName:groupName];
245 if ([ship hasPrimaryRole:@"escort"] && ship != [group leader])
246 {
247 [ship setOwner:[group leader]];
248 }
249 }
250
251 groupID = [dict oo_integerForKey:KEY_ESCORT_GROUP_ID defaultValue:NSNotFound];
252 if (groupID != NSNotFound)
253 {
254 OOShipGroup *group = GroupForGroupID(groupID, context);
255 [group setLeader:ship];
256 [group setName:@"escort group"];
257 [ship setEscortGroup:group];
258 }
259
260 return ship;
261}
#define KEY_EQUIPMENT
#define KEY_MISSILES
static void StripIgnoredKeys(NSMutableDictionary *dict)
#define KEY_IS_GROUP_LEADER
static OOShipGroup * GroupForGroupID(NSUInteger groupID, NSMutableDictionary *context)
void setNormalOrientation:(Quaternion quat)
Definition Entity.m:744
void setName:(NSString *name)
NSDictionary * shipInfoForKey:(NSString *key)
BOOL addEquipmentItem:withValidation:inContext:(NSString *equipmentKey,[withValidation] BOOL validateAddition,[inContext] NSString *context)
OOCreditsQuantity removeMissiles()
void removeAllEquipment()
void setEscortGroup:(OOShipGroup *group)

◆ shipScript

- (OOScript *) shipScript

Definition at line 14954 of file ShipEntity.m.

1397{
1398 return script;
1399}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ shipSubEntityEnumerator

- (NSEnumerator *) shipSubEntityEnumerator

Definition at line 14954 of file ShipEntity.m.

1338{
1339 return [[self subEntities] objectEnumeratorFilteredWithSelector:@selector(isShip)];
1340}

◆ shipUniqueName

- (NSString *) shipUniqueName

◆ shortDescriptionComponents

- (NSString *) shortDescriptionComponents
implementation

Definition at line 14954 of file ShipEntity.m.

1200{
1201 return [NSString stringWithFormat:@"\"%@\"", [self name]];
1202}

◆ shotTime

- (OOTimeDelta) shotTime

Definition at line 9593 of file ShipEntity.m.

11633{
11634 return shot_time;
11635}

◆ showDamage

- (BOOL) showDamage

Definition at line 7619 of file ShipEntity.m.

9165{
9166 return _showDamage;
9167}

◆ showScoopMessage

- (BOOL) showScoopMessage

Definition at line 7619 of file ShipEntity.m.

8506{
8507 return hasScoopMessage;
8508}

◆ simplifyShipdata:andGetDeletes:

- (void) simplifyShipdata: (NSMutableDictionary *) data
andGetDeletes: (NSArray **) deletes 
implementation

Provided by category ShipEntity(LoadRestoreInternal).

Definition at line 365 of file ShipEntityLoadRestore.m.

264 :(NSMutableDictionary *)data andGetDeletes:(NSArray **)deletes
265{
266 NSParameterAssert(data != nil && deletes != NULL);
267 *deletes = nil;
268
269 // Get original ship data.
270 NSMutableDictionary *referenceData = [NSMutableDictionary dictionaryWithDictionary:[[OOShipRegistry sharedRegistry] shipInfoForKey:[self shipDataKey]]];
271
272 // Discard stuff that we handle separately.
273 StripIgnoredKeys(referenceData);
274 StripIgnoredKeys(data);
275
276 // Note items that are in referenceData, but not data.
277 NSMutableArray *foundDeletes = [NSMutableArray array];
278 NSEnumerator *enumerator = nil;
279 NSString *key = nil;
280 for (enumerator = [referenceData keyEnumerator]; (key = [enumerator nextObject]); )
281 {
282 if ([data objectForKey:key] == nil)
283 {
284 [foundDeletes addObject:key];
285 }
286 }
287 if ([foundDeletes count] != 0) *deletes = foundDeletes;
288
289 // after rev3010 this loop was using cycles without doing anything - commenting this whole loop out for now. -- kaks 20100207
290/*
291 // Discard anything that hasn't changed.
292 for (enumerator = [data keyEnumerator]; (key = [enumerator nextObject]); )
293 {
294 id referenceVal = [referenceData objectForKey:key];
295 id myVal = [data objectForKey:key];
296 if ([referenceVal isEqual:myVal])
297 {
298 // [data removeObjectForKey:key];
299 }
300 }
301*/
302}

◆ spawn:

- (void) spawn: (NSString *) roles_number

Definition at line 14073 of file ShipEntity.m.

14321 :(NSString *)roles_number
14322{
14323 NSArray *tokens = ScanTokensFromString(roles_number);
14324 NSString *roleString = nil;
14325 NSString *numberString = nil;
14326 NSUInteger number;
14327
14328 if ([tokens count] != 2)
14329 {
14330 OOLog(kOOLogSyntaxAddShips, @"***** Could not spawn: \"%@\" (must be two tokens, role and number)",roles_number);
14331 return;
14332 }
14333
14334 roleString = [tokens oo_stringAtIndex:0];
14335 numberString = [tokens oo_stringAtIndex:1];
14336
14337 number = [numberString intValue];
14338
14339 [self spawnShipsWithRole:roleString count:number];
14340}
static NSString *const kOOLogSyntaxAddShips

◆ spawnShipsWithRole:count:

- (NSArray *) spawnShipsWithRole: (NSString *) role
count: (NSUInteger) count 

Provided by category ShipEntity(ScriptMethods).

Definition at line 31 of file ShipEntityScriptMethods.m.

64 :(NSString *)role count:(NSUInteger)count
65{
66 ShipEntity *ship = [self rootShipEntity]; // FIXME: (EMMSTRAN) implement an -absolutePosition method, use that in spawnShipWithRole:near:, and use self instead of root.
67 ShipEntity *spawned = nil;
68 NSMutableArray *result = nil;
69
70 if (count == 0) return [NSArray array];
71
72 OOLog(kOOLogNoteAddShips, @"Spawning %ld x '%@' near %@ %d", count, role, [self shortDescription], [self universalID]);
73
74 result = [NSMutableArray arrayWithCapacity:count];
75
76 do
77 {
78 spawned = [UNIVERSE spawnShipWithRole:role near:ship];
79 if (spawned != nil)
80 {
81 [spawned setTemperature:[self randomEjectaTemperature]];
82 if ([self isMissileFlagSet] && [[spawned shipInfoDictionary] oo_boolForKey:@"is_submunition"])
83 {
84 [spawned setOwner:[self owner]];
85 [spawned addTarget:[self primaryTarget]];
86 [spawned setIsMissileFlag:YES];
87 }
88 [result addObject:spawned];
89 }
90 }
91 while (--count);
92
93 return result;
94}
static NSString *const kOOLogNoteAddShips

Referenced by ShipSpawn().

+ Here is the caller graph for this function:

◆ speedFactor

- (GLfloat) speedFactor

Definition at line 7619 of file ShipEntity.m.

8778{
8779 if (maxFlightSpeed <= 0.0) return 0.0;
8780 return flightSpeed / maxFlightSpeed;
8781}

◆ starboardWeaponOffset

- (NSArray *) starboardWeaponOffset

◆ startTrackingCurve

- (void) startTrackingCurve

Definition at line 2093 of file ShipEntity.m.

6316{
6317 Entity *target = [self primaryTarget];
6318 if (target == nil)
6319 {
6320 return;
6321 }
6322 OOTimeAbsolute now = [UNIVERSE getTime];
6323 trackingCurvePositions[0] = [target position];
6324 trackingCurvePositions[1] = [target position];
6325 trackingCurvePositions[2] = [target position];
6326 trackingCurvePositions[3] = [target position];
6327 trackingCurveTimes[0] = now;
6328 trackingCurveTimes[1] = now - reactionTime/3.0;
6329 trackingCurveTimes[2] = now - reactionTime*2.0/3.0;
6331 [self calculateTrackingCurve];
6332 return;
6333}

◆ stationGroup

- (OOShipGroup *) stationGroup

Definition at line 6496 of file ShipEntity.m.

6965{
6966 if (_group == nil)
6967 {
6968 _group = [[OOShipGroup alloc] initWithName:@"station group"];
6969 [_group setLeader:self];
6970 }
6971
6972 return _group;
6973}

◆ storeTarget

- (void) storeTarget
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2126{
2127 Entity *target = [self primaryTarget];
2128
2129 if (target)
2130 {
2131 [self setRememberedShip:target];
2132 }
2133 else
2134 {
2135 DESTROY(_rememberedShip);
2136 }
2137
2138}

◆ subEntities

- (NSArray *) subEntities

◆ subEntitiesForScript

- (NSArray *) subEntitiesForScript

Provided by category ShipEntity(OOJavaScriptExtensions).

Definition at line 1 of file EntityOOJavaScriptExtensions.m.

135{
136 return [[self shipSubEntityEnumerator] allObjects];
137}

Referenced by ShipGetProperty(), and ShipRestoreSubEntities().

+ Here is the caller graph for this function:

◆ subEntityCount

- (NSUInteger) subEntityCount

Definition at line 14954 of file ShipEntity.m.

1320{
1321 return [subEntities count];
1322}

◆ subEntityDied:

- (void) subEntityDied: (ShipEntity *) sub
implementation

Provided by category ShipEntity(Private).

Definition at line 7619 of file ShipEntity.m.

9520 :(ShipEntity *)sub
9521{
9522 if ([self subEntityTakingDamage] == sub) [self setSubEntityTakingDamage:nil];
9523
9524 [sub setOwner:nil];
9525 // TODO? Recalculating collision radius should increase collision testing efficiency,
9526 // but for most ship models the difference would be marginal. -- Kaks 20110429
9527 mass -= [sub mass]; // missing subents affect fuel charge rate, etc..
9528 [subEntities removeObject:sub];
9529}

◆ subEntityEnumerator

- (NSEnumerator *) subEntityEnumerator

Definition at line 14954 of file ShipEntity.m.

1332{
1333 return [[self subEntities] objectEnumerator];
1334}

◆ subEntityReallyDied:

- (void) subEntityReallyDied: (ShipEntity *) sub
implementation

Reimplemented from Entity.

Provided by category ShipEntity(Private).

Definition at line 7619 of file ShipEntity.m.

9532 :(ShipEntity *)sub
9533{
9534 if ([self subEntityTakingDamage] == sub) [self setSubEntityTakingDamage:nil];
9535
9536 if ([self hasSubEntity:sub])
9537 {
9538 OOLogERR(@"shipEntity.bug.subEntityRetainUnderflow", @"Subentity of %@ died while still in subentity list! This is bad. Leaking subentity list to avoid crash. %@", self, @"This is an internal error, please report it.");
9539
9540 // Leak subentity list.
9541 subEntities = nil;
9542 }
9543}

◆ subEntityRotationalVelocity

- (Quaternion) subEntityRotationalVelocity

Definition at line 14954 of file ShipEntity.m.

1170{
1172}

◆ subEntityTakingDamage

- (ShipEntity *) subEntityTakingDamage

Definition at line 14954 of file ShipEntity.m.

1356{
1357 ShipEntity *result = [_subEntityTakingDamage weakRefUnderlyingObject];
1358
1359#ifndef NDEBUG
1360 // Sanity check - there have been problems here, see fireLaserShotInDirection:
1361 // -parentEntity will take care of reporting insanity.
1362 if ([result parentEntity] != self) result = nil;
1363#endif
1364
1365 // Clear the weakref if the subentity is dead.
1366 if (result == nil) [self setSubEntityTakingDamage:nil];
1367
1368 return result;
1369}

◆ subIdx

- (NSUInteger) subIdx

Definition at line 14954 of file ShipEntity.m.

787{
788 return _subIdx;
789}

◆ suggestEscort

- (void) suggestEscort
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1833{
1834 ShipEntity *mother = [self primaryTarget];
1835 [self suggestEscortTo:mother];
1836}

◆ suggestEscortTo:

- (BOOL) suggestEscortTo: (ShipEntity *) mother

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

720 :(ShipEntity *)mother
721{
722 if (mother)
723 {
724#ifndef NDEBUG
725 if (reportAIMessages)
726 {
727 OOLog(@"ai.suggestEscort", @"DEBUG: %@ suggests escorting %@", self, mother);
728 }
729#endif
730
731 if ([mother acceptAsEscort:self])
732 {
733 // copy legal status across
734 if (([mother legalStatus] > 0)&&(bounty <= 0))
735 {
736 int extra = 1 | (ranrot_rand() & 15);
737// [mother setBounty: [mother legalStatus] + extra withReason:kOOLegalStatusReasonAssistingOffender];
738 [self markAsOffender:extra withReason:kOOLegalStatusReasonAssistingOffender];
739 // bounty += extra; // obviously we're dodgier than we thought!
740 }
741
742 [self setOwner:mother];
743 [self setGroup:[mother escortGroup]];
744 [shipAI message:@"ESCORTING"];
745 return YES;
746 }
747
748#ifndef NDEBUG
749 if (reportAIMessages)
750 {
751 OOLog(@"ai.suggestEscort.refused", @"DEBUG: %@ refused by %@", self, mother);
752 }
753#endif
754
755 }
756 [self setOwner:self];
757 [shipAI message:@"NOT_ESCORTING"];
758 [self doScriptEvent:OOJSID("escortRejected") withArgument:mother];
759 return NO;
760}

◆ sunGlareFilter

- (GLfloat) sunGlareFilter

◆ suppressFlightNotifications

- (BOOL) suppressFlightNotifications

Definition at line 14954 of file ShipEntity.m.

2058{
2059 return suppressAegisMessages;
2060}

◆ suppressTargetLost

- (void) suppressTargetLost
implementation

Reimplemented in PlayerEntity.

Definition at line 9593 of file ShipEntity.m.

12914{
12915
12916}

◆ SurfaceDistanceSqared

+ (static float) SurfaceDistanceSqared (Entity *) reference
(Entity< OOStellarBody > *) stellar 
implementation

Definition at line 7613 of file ShipEntity.m.

7614{
7615 return SurfaceDistanceSqaredV([reference position], stellar);
7616}

◆ SurfaceDistanceSqaredV

+ (static float) SurfaceDistanceSqaredV (HPVector) reference
(Entity< OOStellarBody > *) stellar 
implementation

Definition at line 7602 of file ShipEntity.m.

7603{
7604 float centerDistance = HPmagnitude2(HPvector_subtract([stellar position], reference));
7605 float r = [stellar radius];
7606 /* 1.35: empirical value used to help determine proximity when non-nested
7607 planets are close to each other
7608 */
7609 return centerDistance - 1.35 * r * r;
7610}

◆ switchAITo:

- (void) switchAITo: (NSString *) aiString

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

307 :(NSString *)aiString
308{
309 [self setAITo:aiString];
310 [[self getAI] clearStack];
311}

Referenced by ShipSwitchAI().

+ Here is the caller graph for this function:

◆ switchLightsOff

- (void) switchLightsOff

Definition at line 9593 of file ShipEntity.m.

13651{
13652 NSEnumerator *subEnum = nil;
13653 OOFlasherEntity *se = nil;
13654 ShipEntity *sub = nil;
13655
13656 _lightsActive = NO;
13657
13658 for (subEnum = [self flasherEnumerator]; (se = [subEnum nextObject]); )
13659 {
13660 [se setActive:NO];
13661 }
13662 for (subEnum = [self shipSubEntityEnumerator]; (sub = [subEnum nextObject]); )
13663 {
13664 [sub switchLightsOff];
13665 }
13666}
void setActive:(BOOL active)
NSEnumerator * flasherEnumerator()
void switchLightsOff()

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ switchLightsOn

- (void) switchLightsOn

Definition at line 9593 of file ShipEntity.m.

13632{
13633 NSEnumerator *subEnum = nil;
13634 OOFlasherEntity *se = nil;
13635 ShipEntity *sub = nil;
13636
13637 _lightsActive = YES;
13638
13639 for (subEnum = [self flasherEnumerator]; (se = [subEnum nextObject]); )
13640 {
13641 [se setActive:YES];
13642 }
13643 for (subEnum = [self shipSubEntityEnumerator]; (sub = [subEnum nextObject]); )
13644 {
13645 [sub switchLightsOn];
13646 }
13647}
void switchLightsOn()

Referenced by ShipSetProperty().

+ Here is the caller graph for this function:

◆ takeEnergyDamage:from:becauseOf:weaponIdentifier:

- (void) takeEnergyDamage: (double) amount
from: (Entity *) ent
becauseOf: (Entity *) other
weaponIdentifier: (NSString *) weaponIdentifier 
implementation

Reimplemented from Entity.

Reimplemented in DockEntity, PlayerEntity, and StationEntity.

Definition at line 9593 of file ShipEntity.m.

13126 :(double)amount from:(Entity *)ent becauseOf:(Entity *)other weaponIdentifier:(NSString *)weaponIdentifier
13127{
13128 if ([self status] == STATUS_DEAD) return;
13129 if (amount <= 0.0) return;
13130
13131 BOOL energyMine = [ent isCascadeWeapon];
13132 BOOL cascade = NO;
13133 if (energyMine)
13134 {
13135 cascade = [self cascadeIfAppropriateWithDamageAmount:amount cascadeOwner:[ent owner]];
13136 }
13137
13138 energy -= amount;
13139 /* Heat increase from energy impacts will never directly cause
13140 * overheating - too easy for missile hits to cause an uncredited
13141 * death by overheating - CIM */
13143 {
13146 {
13148 }
13149 }
13150
13151
13152 being_mined = NO;
13153 ShipEntity *hunter = nil;
13154
13155 hunter = [other rootShipEntity];
13156 if (hunter == nil && [other isShip]) hunter = (ShipEntity *)other;
13157
13158 // must check for this before potentially deleting 'other' for cloaking
13159 if ((other)&&([other isShip]))
13160 {
13161 being_mined = [(ShipEntity *)other isMining];
13162 }
13163
13164 if (hunter !=nil && [self owner] != hunter) // our owner could be the same entity as the one responsible for our taking damage in the case of submunitions
13165 {
13166 if ([hunter isCloaked])
13167 {
13168 [self doScriptEvent:OOJSID("shipBeingAttackedByCloaked") andReactToAIMessage:@"ATTACKED_BY_CLOAKED"];
13169
13170 // lose it!
13171 other = nil;
13172 hunter = nil;
13173 }
13174 }
13175 else
13176 {
13177 hunter = nil;
13178 }
13179
13180 // if the other entity is a ship note it as an aggressor
13181 if (hunter != nil)
13182 {
13183 BOOL iAmTheLaw = [self isPolice];
13184 BOOL uAreTheLaw = [hunter isPolice];
13185
13186 DESTROY(_lastEscortTarget); // we're being attacked, escorts can scramble!
13187
13188 [self setPrimaryAggressor:hunter];
13189 [self setFoundTarget:hunter];
13190
13191 // firing on an innocent ship is an offence
13192 [self broadcastHitByLaserFrom: hunter];
13193
13194 // tell ourselves we've been attacked
13195 if (energy > 0)
13196 {
13197 [self respondToAttackFrom:ent becauseOf:hunter];
13198 }
13199
13200 OOShipGroup *group = [self group];
13201 // JSAIs manage group notifications themselves
13202 if (![self hasNewAI])
13203 {
13204 // additionally, tell our group we've been attacked
13205 if (group != nil && group != [hunter group] && !(iAmTheLaw || uAreTheLaw))
13206 {
13207 if ([self isTrader] || [self isEscort])
13208 {
13209 ShipEntity *groupLeader = [group leader];
13210 if (groupLeader != self)
13211 {
13212 [groupLeader setFoundTarget:hunter];
13213 [groupLeader setPrimaryAggressor:hunter];
13214 [groupLeader respondToAttackFrom:ent becauseOf:hunter];
13215 //unsetting group leader for carriers can break stuff
13216 }
13217 }
13218 if ([self isPirate])
13219 {
13220 NSEnumerator *groupEnum = nil;
13221 ShipEntity *otherPirate = nil;
13222
13223 for (groupEnum = [group mutationSafeEnumerator]; (otherPirate = [groupEnum nextObject]); )
13224 {
13225 if (otherPirate != self && randf() < 0.5) // 50% chance they'll help
13226 {
13227 [otherPirate setFoundTarget:hunter];
13228 [otherPirate setPrimaryAggressor:hunter];
13229 [otherPirate respondToAttackFrom:ent becauseOf:hunter];
13230 }
13231 }
13232 }
13233 else if (iAmTheLaw)
13234 {
13235 NSEnumerator *groupEnum = nil;
13236 ShipEntity *otherPolice = nil;
13237
13238 for (groupEnum = [group mutationSafeEnumerator]; (otherPolice = [groupEnum nextObject]); )
13239 {
13240 if (otherPolice != self)
13241 {
13242 [otherPolice setFoundTarget:hunter];
13243 [otherPolice setPrimaryAggressor:hunter];
13244 [otherPolice respondToAttackFrom:ent becauseOf:hunter];
13245 }
13246 }
13247 }
13248 }
13249 }
13250
13251 // if I'm a copper and you're not, then mark the other as an offender!
13252 if (iAmTheLaw && !uAreTheLaw)
13253 {
13254 // JSAI's can choose not to do this for friendly fire purposes
13255 if (![self hasNewAI])
13256 {
13257 [hunter markAsOffender:64 withReason:kOOLegalStatusReasonAttackedPolice];
13258 }
13259 }
13260
13261 if ((group != nil && [hunter group] == group) || (iAmTheLaw && uAreTheLaw))
13262 {
13263 // avoid shooting each other
13264 if ([hunter behaviour] == BEHAVIOUR_ATTACK_FLY_TO_TARGET) // avoid me please!
13265 {
13266 [hunter setBehaviour:BEHAVIOUR_ATTACK_FLY_FROM_TARGET];
13267 [hunter setDesiredSpeed:[hunter maxFlightSpeed]];
13268 }
13269 }
13270
13271 }
13272
13273 OOShipDamageType damageType = kOODamageTypeEnergy;
13274 if (suppressExplosion) damageType = kOODamageTypeRemoved;
13275 else if (energyMine) damageType = kOODamageTypeCascadeWeapon;
13276
13277 if (!suppressExplosion)
13278 {
13279 [self noteTakingDamage:amount from:other type:damageType];
13280 if (cascade) energy = 0.0; // explicit set energy to zero in case an oxp raised the energy in previous line.
13281 }
13282
13283 // die if I'm out of energy
13284 if (energy <= 0.0)
13285 {
13286 // backup check just in case scripts have reduced energy
13287 if (self != [UNIVERSE station])
13288 {
13289 if (hunter != nil) [hunter noteTargetDestroyed:self];
13290 [self getDestroyedBy:other damageType:damageType];
13291 }
13292 }
13293 else
13294 {
13295 // warn if I'm low on energy
13296 if (energy < maxEnergy * 0.25)
13297 {
13298 [self doScriptEvent:OOJSID("shipEnergyIsLow") andReactToAIMessage:@"ENERGY_LOW"];
13299 }
13300 if ((energy < maxEnergy *0.125 || (energy < 64 && energy < amount*2)) && [self hasEscapePod] && (ranrot_rand() & 3) == 0) // 25% chance he gets to an escape pod
13301 {
13302 [self abandonShip];
13303 }
13304 }
13305}
#define SHIP_ENERGY_DAMAGE_TO_HEAT_FACTOR
Definition ShipEntity.h:65
ShipEntity * rootShipEntity()
Definition Entity.m:603
BOOL isPirate()
void setDesiredSpeed:(double amount)
BOOL isTrader()
void noteTargetDestroyed:(ShipEntity *target)

◆ takeHeatDamage:

- (void) takeHeatDamage: (double) amount

Reimplemented in PlayerEntity, and StationEntity.

Definition at line 9593 of file ShipEntity.m.

13424 :(double)amount
13425{
13426 if ([self status] == STATUS_DEAD) return;
13427
13428 if ([self isSubEntity])
13429 {
13430 ShipEntity* owner = [self owner];
13431 if (![owner isFrangible])
13432 {
13433 return;
13434 }
13435 }
13436
13437 energy -= amount;
13438 throw_sparks = YES;
13439
13440 [self noteTakingDamage:amount from:nil type:kOODamageTypeHeat];
13441
13442 // oops we're burning up!
13443 if (energy <= 0.0)
13444 {
13445 [self getDestroyedBy:nil damageType:kOODamageTypeHeat];
13446 }
13447 else
13448 {
13449 // warn if I'm low on energy
13450 if (energy < maxEnergy * 0.25)
13451 {
13452 [self doScriptEvent:OOJSID("shipEnergyIsLow") andReactToAIMessage:@"ENERGY_LOW"];
13453 }
13454 }
13455}
unsigned throw_sparks
Definition Entity.h:101

◆ takeScrapeDamage:from:

- (void) takeScrapeDamage: (double) amount
from: (Entity *) ent 

Reimplemented in PlayerEntity, and StationEntity.

Definition at line 9593 of file ShipEntity.m.

13380 :(double) amount from:(Entity *)ent
13381{
13382 if ([self status] == STATUS_DEAD) return;
13383
13384 if ([self status] == STATUS_LAUNCHING|| [ent status] == STATUS_LAUNCHING)
13385 {
13386 // no collisions during launches please
13387 return;
13388 }
13389
13390 energy -= amount;
13391 [self noteTakingDamage:amount from:ent type:kOODamageTypeScrape];
13392
13393 // oops we hit too hard!!!
13394 if (energy <= 0.0)
13395 {
13396 float frag_chance = [ent mass]*10/[self mass];
13397 /* impacts from heavier entities produce fragments
13398 * impacts from lighter entities might do but not always
13399 * asteroid-asteroid impacts likely to fragment
13400 * ship-asteroid impacts might, or might just vaporise it
13401 * projectile weapons just get the default chance
13402 */
13403 if (randf() < frag_chance)
13404 {
13405 being_mined = YES; // same as using a mining laser
13406 }
13407 if ([ent isShip])
13408 {
13409 [(ShipEntity *)ent noteTargetDestroyed:self];
13410 }
13411 [self getDestroyedBy:ent damageType:kOODamageTypeScrape];
13412 }
13413 else
13414 {
13415 // warn if I'm low on energy
13416 if (energy < maxEnergy * 0.25)
13417 {
13418 [self doScriptEvent:OOJSID("shipEnergyIsLow") andReactToAIMessage:@"ENERGY_LOW"];
13419 }
13420 }
13421}

◆ targetFirstBeaconWithCode:

- (void) targetFirstBeaconWithCode: (NSString *) code
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

2660 :(NSString*) code
2661{
2662 NSArray *all_beacons = [UNIVERSE listBeaconsWithCode: code];
2663 if ([all_beacons count])
2664 {
2665 [self addTarget:(ShipEntity*)[all_beacons objectAtIndex:0]];
2666 [shipAI message:@"TARGET_FOUND"];
2667 }
2668 else
2669 [shipAI message:@"NOTHING_FOUND"];
2670}

◆ targetNextBeaconWithCode:

- (void) targetNextBeaconWithCode: (NSString *) code
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ targetStation

- (StationEntity *) targetStation

Definition at line 9593 of file ShipEntity.m.

10014{
10015 StationEntity *result = [_targetStation weakRefUnderlyingObject];
10016 if (result == nil || ![self isValidTarget:result])
10017 {
10019 return nil;
10020 }
10021 return result;
10022}

◆ temperature

- (GLfloat) temperature

Definition at line 7619 of file ShipEntity.m.

8785{
8786 return ship_temperature;
8787}

◆ thankedShip

- (Entity *) thankedShip

Definition at line 9593 of file ShipEntity.m.

9976{
9977 Entity *result = [_thankedShip weakRefUnderlyingObject];
9978 if (result == nil || ![self isValidTarget:result])
9979 {
9981 return nil;
9982 }
9983 return result;
9984}

◆ thargonCheckMother

- (void) thargonCheckMother
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

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

◆ throwSparks

- (void) throwSparks
implementation

Reimplemented from Entity.

Definition at line 9593 of file ShipEntity.m.

12099{
12100 Vector offset =
12101 {
12102 randf() * (boundingBox.max.x - boundingBox.min.x) + boundingBox.min.x,
12103 randf() * (boundingBox.max.y - boundingBox.min.y) + boundingBox.min.y,
12104 randf() * boundingBox.max.z + boundingBox.min.z // rear section only
12105 };
12106 HPVector origin = HPvector_add(position, vectorToHPVector(quaternion_rotate_vector([self normalOrientation], offset)));
12107
12108 float w = boundingBox.max.x - boundingBox.min.x;
12109 float h = boundingBox.max.y - boundingBox.min.y;
12110 float m = (w < h) ? 0.25 * w: 0.25 * h;
12111
12112 float sz = m * (1 + randf() + randf()); // half minimum dimension on average
12113
12114 Vector vel = vector_multiply_scalar(HPVectorToVector(HPvector_subtract(origin, position)), 2.0);
12115
12116 OOColor *color = [OOColor colorWithHue:0.08 + 0.17 * randf() saturation:1.0 brightness:1.0 alpha:1.0];
12117
12118 OOSparkEntity *spark = [[OOSparkEntity alloc] initWithPosition:origin
12119 velocity:vel
12120 duration:2.0 + 3.0 * randf()
12121 size:sz
12122 color:color];
12123
12124 [spark setOwner:self];
12125 [UNIVERSE addEntity:spark];
12126 [spark release];
12127
12129}
double next_spark_time
Definition ShipEntity.h:384

◆ thrust

- (float) thrust

◆ thrustVector

- (Vector) thrustVector

Definition at line 9593 of file ShipEntity.m.

12832{
12833 return vector_multiply_scalar(v_forward, flightSpeed);
12834}

◆ totalBoundingBox

- (BoundingBox) totalBoundingBox

◆ trackCloseContacts

- (BOOL) trackCloseContacts

◆ trackDestination:delta_t:

- (double) trackDestination: (double)
delta_t: (BOOL) retreat 

Definition at line 9593 of file ShipEntity.m.

10930 :(double) delta_t :(BOOL) retreat
10931{
10932 Vector relPos;
10933 GLfloat d_forward, d_up, d_right;
10934
10935 BOOL we_are_docking = (nil != dockingInstructions);
10936
10937 stick_roll = 0.0; //desired roll and pitch
10938 stick_pitch = 0.0;
10939 stick_yaw = 0.0;
10940
10941 double reverse = 1.0;
10942 double reversePlayer = 1.0;
10943
10944 double min_d = 0.004;
10945 double max_cos = MAX_COS; // should match default value of max_cos in behaviour_fly_to_destination!
10946 double precision = we_are_docking ? 0.25 : 0.9025; // lower values force a direction closer to the target. (resp. 50% and 95% within range)
10947
10948 if (retreat)
10949 reverse = -reverse;
10950
10951 if (isPlayer)
10952 {
10953 reverse = -reverse;
10954 reversePlayer = -1;
10955 }
10956
10957 relPos = HPVectorToVector(HPvector_subtract(_destination, position));
10958 double range2 = magnitude2(relPos);
10959 double desired_range2 = desired_range*desired_range;
10960
10961 /* 2009-7-18 Eric: We need to aim well inide the desired_range sphere round the target and not at the surface of the sphere.
10962 Because of the framerate most ships normally overshoot the target and they end up flying clearly on a path
10963 through the sphere. Those ships give no problems, but ships with a very low turnrate will aim close to the surface and will than
10964 have large trouble with reaching their destination. When those ships enter the slowdown range, they have almost no speed vector
10965 in the direction of the target. I now used 95% of desired_range to aim at, but a smaller value might even be better.
10966 */
10967 if (range2 > desired_range2)
10968 {
10969 max_cos = sqrt(1 - precision * desired_range2/range2); // Head for a point within 95% of desired_range.
10970 if (max_cos >= 0.99999)
10971 {
10972 max_cos = 0.99999;
10973 }
10974 }
10975
10976 if (!vector_equal(relPos, kZeroVector)) relPos = vector_normal(relPos);
10977 else relPos.z = 1.0;
10978
10979 d_right = dot_product(relPos, v_right);
10980 d_up = dot_product(relPos, v_up);
10981 d_forward = dot_product(relPos, v_forward); // == cos of angle between v_forward and vector to target
10982
10983 // begin rule-of-thumb manoeuvres
10984 stick_pitch = 0.0;
10985 stick_roll = 0.0;
10986
10987 // pitching_over is currently only set in behaviour_formation_form_up, for escorts and in avoidCollision.
10988 // This allows for immediate pitch corrections instead of first waiting untill roll has completed.
10989 if (pitching_over)
10990 {
10991 if (reverse * d_up > 0) // pitch up
10993 else
10995 pitching_over = (reverse * d_forward < 0.707);
10996 }
10997
10998 // check if we are flying toward (or away from) the destination..
10999 if ((d_forward < max_cos)||(retreat)) // not on course so we must adjust controls..
11000 {
11001
11002 if (d_forward <= -max_cos || (retreat && d_forward >= max_cos)) // hack to avoid just flying away from the destination
11003 {
11004 d_up = min_d * 2.0;
11005 }
11006
11007 if (d_up > min_d)
11008 {
11009 int factor = sqrt(fabs(d_right) / fabs(min_d));
11010 if (factor > 8)
11011 factor = 8;
11012 if (d_right > min_d)
11013 stick_roll = - max_flight_roll * reversePlayer * 0.125 * factor; // only reverse sign for the player;
11014 if (d_right < -min_d)
11015 stick_roll = + max_flight_roll * reversePlayer * 0.125 * factor;
11016 if (fabs(d_right) < fabs(stick_roll) * delta_t)
11017 stick_roll = fabs(d_right) / delta_t * (stick_roll<0 ? -1 : 1); // don't overshoot heading
11018 }
11019
11020 if (d_up < -min_d)
11021 {
11022 int factor = sqrt(fabs(d_right) / fabs(min_d));
11023 if (factor > 8)
11024 factor = 8;
11025 if (d_right > min_d)
11026 stick_roll = + max_flight_roll * reversePlayer * 0.125 * factor; // only reverse sign for the player;
11027 if (d_right < -min_d)
11028 stick_roll = - max_flight_roll * reversePlayer * 0.125 * factor;
11029 if (fabs(d_right) < fabs(stick_roll) * delta_t)
11030 stick_roll = fabs(d_right) / delta_t * (stick_roll<0 ? -1 : 1); // don't overshoot heading
11031 }
11032
11033 if (stick_roll == 0.0)
11034 {
11035 int factor = sqrt(fabs(d_up) / fabs(min_d));
11036 if (factor > 8)
11037 factor = 8;
11038 if (d_up > min_d)
11039 stick_pitch = - max_flight_pitch * reverse * 0.125 * factor; //pitch_pitch * reverse;
11040 if (d_up < -min_d)
11041 stick_pitch = + max_flight_pitch * reverse * 0.125 * factor;
11042 if (fabs(d_up) < fabs(stick_pitch) * delta_t)
11043 stick_pitch = fabs(d_up) / delta_t * (stick_pitch<0 ? -1 : 1); // don't overshoot heading
11044 }
11045
11046 if (stick_pitch == 0.0)
11047 {
11048 // not sufficiently on course yet, but min_d is too high
11049 // turn anyway slightly to adjust
11050 stick_pitch = 0.01;
11051 }
11052 }
11053
11054 if (we_are_docking && docking_match_rotation && (d_forward > max_cos))
11055 {
11056 /* we are docking and need to consider the rotation/orientation of the docking port */
11057 StationEntity* station_for_docking = (StationEntity*)[self targetStation];
11058
11059 if ((station_for_docking)&&(station_for_docking->isStation))
11060 {
11061 stick_roll = [self rollToMatchUp:[station_for_docking portUpVectorForShip:self] rotating:[station_for_docking flightRoll]];
11062 }
11063 }
11064
11065 // end rule-of-thumb manoeuvres
11066
11067 [self applySticks:delta_t];
11068
11069 if (retreat)
11070 d_forward *= d_forward; // make positive AND decrease granularity
11071
11072 if (d_forward < 0.0)
11073 return 0.0;
11074
11075 if ((!flightRoll)&&(!flightPitch)) // no correction
11076 return 1.0;
11077
11078 return d_forward;
11079}
Vector portUpVectorForShip:(ShipEntity *ship)

◆ trackOntoTarget:withDForward:

- (void) trackOntoTarget: (double) delta_t
withDForward: (GLfloat) dp 

Definition at line 9593 of file ShipEntity.m.

10292 :(double) delta_t withDForward: (GLfloat) dp
10293{
10294 Vector vector_to_target;
10295 Quaternion q_minarc;
10296 //
10297 Entity* target = [self primaryTarget];
10298 //
10299 if (!target)
10300 return;
10301
10302 vector_to_target = [self vectorTo:target];
10303 //
10304 GLfloat range2 = magnitude2(vector_to_target);
10305 GLfloat targetRadius = 0.75 * target->collision_radius;
10306 GLfloat max_cos = sqrt(1 - targetRadius*targetRadius/range2);
10307
10308 if (dp > max_cos)
10309 return; // ON TARGET!
10310
10311 if (vector_to_target.x||vector_to_target.y||vector_to_target.z)
10312 vector_to_target = vector_normal(vector_to_target);
10313 else
10314 vector_to_target.z = 1.0;
10315
10316 q_minarc = quaternion_rotation_between(v_forward, vector_to_target);
10317
10319 [self orientationChanged];
10320
10321 flightRoll = 0.0;
10322 flightPitch = 0.0;
10323 flightYaw = 0.0;
10324 stick_roll = 0.0;
10325 stick_pitch = 0.0;
10326 stick_yaw = 0.0;
10327}

◆ trackPrimaryTarget:delta_t:

- (double) trackPrimaryTarget: (double)
delta_t: (BOOL) retreat 

Definition at line 9593 of file ShipEntity.m.

10477 :(double) delta_t :(BOOL) retreat
10478{
10479 Entity* target = [self primaryTarget];
10480
10481 if (!target) // leave now!
10482 {
10483 [self noteLostTargetAndGoIdle]; // NOTE: was AI message: rather than reactToMessage:
10484 return 0.0;
10485 }
10486
10487 if (![self canStillTrackPrimaryTarget])
10488 {
10489 [self noteLostTargetAndGoIdle]; // NOTE: was AI message: rather than reactToMessage:
10490 return 0.0;
10491 }
10492
10493 /* 1.81 change: do the above check first: if a missile can't be
10494 * fired outside scanner range it should self-destruct if the
10495 * target gets far enough away (it's going to miss anyway) -
10496 * CIM */
10497 if (scanClass == CLASS_MISSILE)
10498 return [self missileTrackPrimaryTarget: delta_t];
10499
10500 GLfloat d_forward, d_up, d_right;
10501
10502 Vector relPos = HPVectorToVector(HPvector_subtract([self calculateTargetPosition], position));
10503
10504 double range2 = HPmagnitude2(HPvector_subtract([target position], position));
10505
10506 //jink if retreating
10507 if (retreat) // calculate jink position when flying away from target.
10508 {
10509 Vector vx, vy, vz;
10510 if (target->isShip)
10511 {
10512 ShipEntity* targetShip = (ShipEntity*)target;
10513 vx = targetShip->v_right;
10514 vy = targetShip->v_up;
10515 vz = targetShip->v_forward;
10516 }
10517 else
10518 {
10519 Quaternion q = target->orientation;
10523 }
10524
10525 BOOL avoidCollision = NO;
10526 if (range2 < collision_radius * target->collision_radius * 100.0) // Check direction within 10 * collision radius.
10527 {
10528 Vector targetDirection = kBasisZVector;
10529 if (!vector_equal(relPos, kZeroVector)) targetDirection = vector_normal(relPos);
10530 avoidCollision = (dot_product(targetDirection, v_forward) > -0.1); // is flying toward target or only slightly outward.
10531 }
10532
10533 GLfloat dist_adjust_factor = 1.0;
10535 {
10536 double range = magnitude(relPos);
10537 if (range > 2000.0)
10538 {
10539 dist_adjust_factor = range / 2000.0;
10541 {
10542 dist_adjust_factor *= 3;
10543 }
10544 }
10545 if (jink.x == 0.0 && behaviour != BEHAVIOUR_RUNNING_DEFENSE)
10546 { // test for zero jink and correct
10547 [self setEvasiveJink:400.0];
10548 }
10549 }
10550
10551 if (!avoidCollision) // it is safe to jink
10552 {
10553 relPos.x += (jink.x * vx.x + jink.y * vy.x + jink.z * vz.x) * dist_adjust_factor;
10554 relPos.y += (jink.x * vx.y + jink.y * vy.y + jink.z * vz.y) * dist_adjust_factor;
10555 relPos.z += (jink.x * vx.z + jink.y * vy.z + jink.z * vz.z);
10556 }
10557
10558 }
10559
10560 if (!vector_equal(relPos, kZeroVector)) relPos = vector_normal(relPos);
10561 else relPos.z = 1.0;
10562
10563 double max_cos = [self currentAimTolerance];
10564
10565 stick_roll = 0.0; //desired roll and pitch
10566 stick_pitch = 0.0;
10567
10568 double reverse = (retreat)? -1.0: 1.0;
10569
10570 double min_d = 0.004; // ~= 40m at 10km
10571 int max_factor = 8;
10572 double r_max_factor = 0.125;
10573 if (!retreat)
10574 {
10576 {
10577 // much greater precision in combat
10578 if (max_flight_pitch > 1.0)
10579 {
10580 max_factor = floor(max_flight_pitch/0.125);
10581 r_max_factor = 1.0/max_factor;
10582 }
10583 min_d = 0.0004; // 10 times more precision ~= 4m at 10km
10584 max_factor *= 3;
10585 r_max_factor /= 3.0;
10586 }
10587 else if (accuracy >= COMBAT_AI_ISNT_AWFUL)
10588 {
10589 // slowly improve precision to target, but only if missing
10590 min_d -= 0.0001 * [self missedShots];
10591 if (min_d < 0.001)
10592 {
10593 min_d = 0.001;
10594 max_factor *= 2;
10595 r_max_factor /= 2.0;
10596 }
10597 }
10598 }
10599
10600 d_right = dot_product(relPos, v_right);
10601 d_up = dot_product(relPos, v_up);
10602 d_forward = dot_product(relPos, v_forward); // == cos of angle between v_forward and vector to target
10603
10604 if (d_forward * reverse > max_cos) // on_target!
10605 {
10606 return d_forward;
10607 }
10608
10609 // begin rule-of-thumb manoeuvres
10610 stick_pitch = 0.0;
10611 stick_roll = 0.0;
10612
10613
10614 if ((reverse * d_forward < -0.5) && !pitching_over) // we're going the wrong way!
10615 pitching_over = YES;
10616
10617 if (pitching_over)
10618 {
10619 if (reverse * d_up > 0) // pitch up
10621 else
10623 pitching_over = (reverse * d_forward < 0.707);
10624 }
10625
10626 // check if we are flying toward the destination..
10627 if ((d_forward < max_cos)||(retreat)) // not on course so we must adjust controls..
10628 {
10629 if (d_forward < -max_cos) // hack to avoid just flying away from the destination
10630 {
10631 d_up = min_d * 2.0;
10632 }
10633
10634 if (d_up > min_d)
10635 {
10636 int factor = sqrt(fabs(d_right) / fabs(min_d));
10637 if (factor > max_factor)
10638 factor = max_factor;
10639 if (d_right > min_d)
10640 stick_roll = - max_flight_roll * r_max_factor * factor; // note#
10641 if (d_right < -min_d)
10642 stick_roll = + max_flight_roll * r_max_factor * factor; // note#
10643 }
10644 if (d_up < -min_d)
10645 {
10646 int factor = sqrt(fabs(d_right) / fabs(min_d));
10647 if (factor > max_factor)
10648 factor = max_factor;
10649 if (d_right > min_d)
10650 stick_roll = + max_flight_roll * r_max_factor * factor; // note#
10651 if (d_right < -min_d)
10652 stick_roll = - max_flight_roll * r_max_factor * factor; // note#
10653 }
10654
10655 if (stick_roll == 0.0)
10656 {
10657 int factor = sqrt(fabs(d_up) / fabs(min_d));
10658 if (factor > max_factor)
10659 factor = max_factor;
10660 if (d_up > min_d)
10661 stick_pitch = - max_flight_pitch * reverse * r_max_factor * factor;
10662 if (d_up < -min_d)
10663 stick_pitch = + max_flight_pitch * reverse * r_max_factor * factor;
10664 }
10665
10667 {
10668 // don't overshoot target (helps accuracy at low frame rates)
10669 if (fabs(d_right) < fabs(stick_roll) * delta_t)
10670 {
10671 stick_roll = fabs(d_right) / delta_t * (stick_roll<0 ? -1 : 1);
10672 }
10673 if (fabs(d_up) < fabs(stick_pitch) * delta_t)
10674 {
10675 stick_pitch = fabs(d_up) / delta_t * (stick_pitch<0 ? -0.9 : 0.9);
10676 }
10677 }
10678
10679 }
10680 /* # note
10681 Eric 9-9-2010: Removed the "reverse" variable from the stick_roll calculation. This was mathematical wrong and
10682 made the ship roll in the wrong direction, preventing the ship to fly away in a straight line from the target.
10683 This means all the places were a jink was set, this jink never worked correctly. The main reason a ship still
10684 managed to turn at close range was probably by the fail-safe mechanisme with the "pitching_over" variable.
10685 The jink was programmed to do nothing within 500 meters of the ship and just fly away in direct line from the target
10686 in that range. Because of the bug the ships always rolled to the wrong side needed to fly away in direct line
10687 resulting in making it a difficult target.
10688 After fixing the bug, the ship realy flew away in direct line during the first 500 meters, making it a easy target
10689 for the player. All jink settings are retested and changed to give a turning behaviour that felt like the old
10690 situation, but now more deliberately set.
10691 */
10692
10693 // end rule-of-thumb manoeuvres
10694 stick_yaw = 0.0;
10695
10696 [self applySticks:delta_t];
10697
10698 if (retreat)
10699 d_forward *= d_forward; // make positive AND decrease granularity
10700
10701 if (d_forward < 0.0)
10702 return 0.0;
10703
10704 if ((!flightRoll)&&(!flightPitch)) // no correction
10705 return 1.0;
10706
10707 return d_forward;
10708}
void avoidCollision()

◆ trackSideTarget:delta_t:

- (double) trackSideTarget: (double)
delta_t: (BOOL) leftside 

Definition at line 9593 of file ShipEntity.m.

10711 :(double) delta_t :(BOOL) leftside
10712{
10713 Entity* target = [self primaryTarget];
10714
10715 if (!target) // leave now!
10716 {
10717 [self noteLostTargetAndGoIdle]; // NOTE: was AI message: rather than reactToMessage:
10718 return 0.0;
10719 }
10720
10721 if (![self canStillTrackPrimaryTarget])
10722 {
10723 [self noteLostTargetAndGoIdle]; // NOTE: was AI message: rather than reactToMessage:
10724 return 0.0;
10725 }
10726
10727
10728 if (scanClass == CLASS_MISSILE) // never?
10729 return [self missileTrackPrimaryTarget: delta_t];
10730
10731 GLfloat d_forward, d_up, d_right;
10732
10733 Vector relPos = HPVectorToVector(HPvector_subtract([self calculateTargetPosition], position));
10734
10735
10736 if (!vector_equal(relPos, kZeroVector)) relPos = vector_normal(relPos);
10737 else relPos.z = 1.0;
10738
10739// worse shots with side lasers than fore/aft, in general
10740
10741 double max_cos = [self currentAimTolerance];
10742
10743 stick_roll = 0.0; //desired roll and pitch
10744 stick_pitch = 0.0;
10745 stick_yaw = 0.0;
10746
10747 double reverse = (leftside)? -1.0: 1.0;
10748
10749 double min_d = 0.004;
10751 {
10752 min_d = 0.002;
10753 }
10754 int max_factor = 8;
10755 double r_max_factor = 0.125;
10756
10757 d_right = dot_product(relPos, v_right);
10758 d_up = dot_product(relPos, v_up);
10759 d_forward = dot_product(relPos, v_forward); // == cos of angle between v_forward and vector to target
10760
10761 if (d_right * reverse > max_cos) // on_target!
10762 {
10763 return d_right * reverse;
10764 }
10765
10766 // begin rule-of-thumb manoeuvres
10767 stick_pitch = 0.0;
10768 stick_roll = 0.0;
10769 stick_yaw = 0.0;
10770
10771 // check if we are flying toward the destination..
10772 if ((d_right * reverse < max_cos)) // not on course so we must adjust controls..
10773 {
10774 if (d_right < -max_cos) // hack to avoid just pointing away from the destination
10775 {
10776 d_forward = min_d * 2.0;
10777 }
10778
10779 if (d_forward > min_d)
10780 {
10781 int factor = sqrt(fabs(d_up) / fabs(min_d));
10782 if (factor > max_factor)
10783 factor = max_factor;
10784 if (d_up > min_d)
10785 stick_pitch = + max_flight_pitch * r_max_factor * factor; // note#
10786 if (d_up < -min_d)
10787 stick_pitch = - max_flight_pitch * r_max_factor * factor; // note#
10788 }
10789 if (d_forward < -min_d)
10790 {
10791 int factor = sqrt(fabs(d_up) / fabs(min_d));
10792 if (factor > max_factor)
10793 factor = max_factor;
10794 if (d_up > min_d)
10795 stick_pitch = + max_flight_pitch * r_max_factor * factor; // note#
10796 if (d_up < -min_d)
10797 stick_pitch = - max_flight_pitch * r_max_factor * factor; // note#
10798 }
10799
10800 if (fabs(stick_pitch) == 0.0 || fabs(d_forward) > 0.5)
10801 {
10802 stick_pitch = 0.0;
10803 int factor = sqrt(fabs(d_forward) / fabs(min_d));
10804 if (factor > max_factor)
10805 factor = max_factor;
10806 if (d_forward > min_d)
10807 stick_yaw = - max_flight_yaw * reverse * r_max_factor * factor;
10808 if (d_forward < -min_d)
10809 {
10810 if (factor < max_factor/2.0) // compensate for forward thrust
10811 factor *= 2.0;
10812 stick_yaw = + max_flight_yaw * reverse * r_max_factor * factor;
10813 }
10814 }
10815 }
10816
10817
10818 // end rule-of-thumb manoeuvres
10819
10820 [self applySticks:delta_t];
10821
10822 if ((!flightPitch)&&(!flightYaw)) // no correction
10823 return 1.0;
10824
10825 return d_right * reverse;
10826}

◆ transitionToAegisNone

- (void) transitionToAegisNone

Definition at line 7411 of file ShipEntity.m.

7575{
7577 {
7578 Entity<OOStellarBody> *lastAegisLock = [self lastAegisLock];
7579 if (lastAegisLock != nil)
7580 {
7581 [self doScriptEvent:OOJSID("shipExitedPlanetaryVicinity") withArgument:lastAegisLock];
7582
7583 if (lastAegisLock == [UNIVERSE sun])
7584 {
7585 [shipAI message:@"AWAY_FROM_SUN"];
7586 }
7587 else
7588 {
7589 [shipAI message:@"AWAY_FROM_PLANET"];
7590 }
7591 }
7592
7594 {
7595 [shipAI message:@"AEGIS_NONE"];
7596 }
7597 }
7599}

◆ turretCount

- (NSUInteger) turretCount

Definition at line 6496 of file ShipEntity.m.

7029{
7030 NSUInteger count = 0;
7031 NSEnumerator *subEnum = [self shipSubEntityEnumerator];
7032 ShipEntity *se = nil;
7033 while ((se = [subEnum nextObject]))
7034 {
7035 if ([se isTurret])
7036 {
7037 count ++;
7038 }
7039 }
7040 return count;
7041}
BOOL isTurret()

Referenced by OOShipLibraryTurrets().

+ Here is the caller graph for this function:

◆ update:

- (void) update: (OOTimeDelta) delta_t
implementation

Reimplemented from Entity.

Reimplemented in DockEntity, PlayerEntity, and StationEntity.

Definition at line 2093 of file ShipEntity.m.

2319 :(OOTimeDelta)delta_t
2320{
2321 if (shipinfoDictionary == nil)
2322 {
2323 OOLog(@"shipEntity.notDict", @"Ship %@ was not set up from dictionary.", self);
2324 [UNIVERSE removeEntity:self];
2325 return;
2326 }
2327
2328 if (!isfinite(maxFlightSpeed))
2329 {
2330 OOLog(@"ship.sanityCheck.failed", @"Ship %@ %@ infinite top speed, clamped to 300.", self, @"had");
2331 maxFlightSpeed = 300;
2332 }
2333
2334 bool isSubEnt = [self isSubEntity];
2335
2336 if (isDemoShip)
2337 {
2338 if (demoRate > 0)
2339 {
2340 OOScalar cos1 = cos(M_PI * ([UNIVERSE getTime] - demoStartTime) * demoRate / 11);
2341 OOScalar sin1 = sin(M_PI * ([UNIVERSE getTime] - demoStartTime) * demoRate / 11);
2342 OOScalar cos2 = cos(-M_PI * ([UNIVERSE getTime] - demoStartTime) * demoRate / 15);
2343 OOScalar sin2 = sin(-M_PI * ([UNIVERSE getTime] - demoStartTime) * demoRate / 15);
2344 Quaternion q1 = make_quaternion(cos1, sin1*sqrt(3)/2, sin1/2, 0);
2345 Quaternion q2 = make_quaternion(cos2, -sin2*sqrt(4)/sqrt(5), 0, sin2*sqrt(1)/sqrt(5));
2346 [self setOrientation: quaternion_multiply(q2, quaternion_multiply(q1, demoStartOrientation))];
2347 }
2348
2349 [super update:delta_t];
2350 if ([self subEntityCount] > 0)
2351 {
2352 // only copy the subent array if there are subentities
2353 ShipEntity *se = nil;
2354 foreach (se, [self subEntities])
2355 {
2356 [se update:delta_t];
2357 if ([se isShip])
2358 {
2359 BoundingBox sebb = [se findSubentityBoundingBox];
2360 bounding_box_add_vector(&totalBoundingBox, sebb.max);
2361 bounding_box_add_vector(&totalBoundingBox, sebb.min);
2362 }
2363 }
2364 }
2365 return;
2366 }
2367
2368
2369 if (!isSubEnt)
2370 {
2371 if (scanClass == CLASS_NOT_SET)
2372 {
2373 scanClass = CLASS_NEUTRAL;
2374 OOLog(@"ship.sanityCheck.failed", @"Ship %@ %@ with scanClass CLASS_NOT_SET; forced to CLASS_NEUTRAL.", self, [self primaryRole]);
2375 }
2376
2377 [self updateTrackingCurve];
2378
2379 //
2380 // deal with collisions
2381 //
2382 [self manageCollisions];
2383
2384 // subentity collisions managed via parent entity
2385
2386 //
2387 // reset any inadvertant legal mishaps
2388 //
2389 if (scanClass == CLASS_POLICE)
2390 {
2391 if (bounty > 0)
2392 {
2393 [self setBounty:0 withReason:kOOLegalStatusReasonPoliceAreClean];
2394 }
2395 ShipEntity* target = [self primaryTarget];
2396 if ((target)&&([target scanClass] == CLASS_POLICE))
2397 {
2398 [self noteLostTarget];
2399 }
2400 }
2401
2403 {
2404 // in checkCloseCollisionWith: we check if some thing has come within touch range (origin within our collision_radius)
2405 // here we check if it has gone outside that range
2406 NSString *other_key = nil;
2407
2408 // create a temp copy to iterate over, since we may want to
2409 // change the original
2410 NSDictionary *closeContactsTemp = [[NSDictionary alloc] initWithDictionary:closeContactsInfo];
2411 foreachkey (other_key, closeContactsTemp)
2412 {
2413 ShipEntity* other = [UNIVERSE entityForUniversalID:[other_key intValue]];
2414 if ((other != nil) && (other->isShip))
2415 {
2416 if (HPdistance2(position, other->position) > collision_radius * collision_radius) // moved beyond our sphere!
2417 {
2418 // calculate position with respect to our own position and orientation
2419 Vector dpos = HPVectorToVector(HPvector_between(position, other->position));
2420 Vector pos1 = make_vector(dot_product(dpos, v_right), dot_product(dpos, v_up), dot_product(dpos, v_forward));
2421 Vector pos0 = {0, 0, 0};
2422 ScanVectorFromString([closeContactsInfo objectForKey: other_key], &pos0);
2423 // send AI messages about the contact
2425 _primaryTarget = [other weakRetain];
2426 if ((pos0.x < 0.0)&&(pos1.x > 0.0))
2427 {
2428 [self doScriptEvent:OOJSID("shipTraversePositiveX") withArgument:other andReactToAIMessage:@"POSITIVE X TRAVERSE"];
2429 }
2430 if ((pos0.x > 0.0)&&(pos1.x < 0.0))
2431 {
2432 [self doScriptEvent:OOJSID("shipTraverseNegativeX") withArgument:other andReactToAIMessage:@"NEGATIVE X TRAVERSE"];
2433 }
2434 if ((pos0.y < 0.0)&&(pos1.y > 0.0))
2435 {
2436 [self doScriptEvent:OOJSID("shipTraversePositiveY") withArgument:other andReactToAIMessage:@"POSITIVE Y TRAVERSE"];
2437 }
2438 if ((pos0.y > 0.0)&&(pos1.y < 0.0))
2439 {
2440 [self doScriptEvent:OOJSID("shipTraverseNegativeY") withArgument:other andReactToAIMessage:@"NEGATIVE Y TRAVERSE"];
2441 }
2442 if ((pos0.z < 0.0)&&(pos1.z > 0.0))
2443 {
2444 [self doScriptEvent:OOJSID("shipTraversePositiveZ") withArgument:other andReactToAIMessage:@"POSITIVE Z TRAVERSE"];
2445 }
2446 if ((pos0.z > 0.0)&&(pos1.z < 0.0))
2447 {
2448 [self doScriptEvent:OOJSID("shipTraverseNegativeZ") withArgument:other andReactToAIMessage:@"NEGATIVE Z TRAVERSE"];
2449 }
2450 _primaryTarget = temp;
2451 [closeContactsInfo removeObjectForKey: other_key];
2452 }
2453 }
2454 else
2455 {
2456 [closeContactsInfo removeObjectForKey: other_key];
2457 }
2458 }
2459 [closeContactsTemp release];
2460 } // end if trackCloseContacts
2461
2462 } // end if !isSubEntity
2463
2464
2465#ifndef NDEBUG
2466 // DEBUGGING
2468 {
2469 OOLog(kOOLogEntityBehaviourChanged, @"%@ behaviour is now %@", self, OOStringFromBehaviour(behaviour));
2471 }
2472#endif
2473
2474 // cool all weapons.
2475 weapon_temp = fmaxf(weapon_temp - (float)(WEAPON_COOLING_FACTOR * delta_t), 0.0f);
2476 forward_weapon_temp = fmaxf(forward_weapon_temp - (float)(WEAPON_COOLING_FACTOR * delta_t), 0.0f);
2477 aft_weapon_temp = fmaxf(aft_weapon_temp - (float)(WEAPON_COOLING_FACTOR * delta_t), 0.0f);
2478 port_weapon_temp = fmaxf(port_weapon_temp - (float)(WEAPON_COOLING_FACTOR * delta_t), 0.0f);
2479 starboard_weapon_temp = fmaxf(starboard_weapon_temp - (float)(WEAPON_COOLING_FACTOR * delta_t), 0.0f);
2480
2481 // update time between shots
2482 shot_time += delta_t;
2483
2484 // handle radio message effects
2485 if (messageTime > 0.0)
2486 {
2487 messageTime -= delta_t;
2488 if (messageTime < 0.0) messageTime = 0.0;
2489 }
2490
2491 // temperature factors
2492 if(!isSubEnt)
2493 {
2494 double external_temp = 0.0;
2495 OOSunEntity *sun = [UNIVERSE sun];
2496 if (sun != nil)
2497 {
2498 // set the ambient temperature here
2499 double sun_zd = HPdistance2(position, [sun position]); // square of distance
2500 double sun_cr = sun->collision_radius;
2501 double alt1 = sun_cr * sun_cr / sun_zd;
2502 external_temp = SUN_TEMPERATURE * alt1;
2503 if ([sun goneNova]) external_temp *= 100;
2504
2505 if ([self hasFuelScoop] && alt1 > 0.75 && [self fuel] < [self fuelCapacity])
2506 {
2507 fuel_accumulator += (float)(delta_t * flightSpeed * 0.010 / [self fuelChargeRate]);
2508 // are we fast enough to collect any fuel?
2509 while (fuel_accumulator > 1.0f)
2510 {
2511 [self setFuel:[self fuel] + 1];
2512 fuel_accumulator -= 1.0f;
2513 [self doScriptEvent:OOJSID("shipScoopedFuel")];
2514 }
2515 }
2516 }
2517
2518 // work on the ship temperature
2519 //
2520 float heatThreshold = [self heatInsulation] * 100.0f;
2521 if (external_temp > heatThreshold && external_temp > ship_temperature)
2522 ship_temperature += (external_temp - ship_temperature) * delta_t * SHIP_INSULATION_FACTOR / [self heatInsulation];
2523 else
2524 {
2526 {
2527 ship_temperature += (external_temp - heatThreshold - ship_temperature) * delta_t * SHIP_COOLING_FACTOR / [self heatInsulation];
2529 }
2530 }
2531 }
2532 else //subents
2533 {
2534 ship_temperature = [[self owner] temperature];
2535 }
2536
2538 [self takeHeatDamage: delta_t * ship_temperature];
2539
2540 // are we burning due to low energy
2541 if ((energy < maxEnergy * 0.20)&&_showDamage) // prevents asteroid etc. from burning
2542 throw_sparks = YES;
2543
2544 // burning effects
2545 if (throw_sparks)
2546 {
2547 next_spark_time -= delta_t;
2548 if (next_spark_time < 0.0)
2549 {
2550 [self throwSparks];
2551 throw_sparks = NO; // until triggered again
2552 }
2553 }
2554
2555 if (!isSubEnt)
2556 {
2557
2558 // cloaking device
2559 if ([self hasCloakingDevice])
2560 {
2562 {
2565 {
2566 [self deactivateCloakingDevice];
2567 if (energy < 0) energy = 0;
2568 }
2569 }
2570 }
2571
2572 // military_jammer
2573 if ([self hasMilitaryJammer])
2574 {
2576 {
2579 {
2581 if (energy < 0) energy = 0;
2582 }
2583 }
2584 else
2585 {
2588 }
2589 }
2590
2591 // check outside factors
2592 /* aegis checks are expensive, so only do them once every km or so of flight
2593 * unlikely to be important otherwise. (every 100m if already close to
2594 * planet, to watch for surface)
2595
2596 * if have non-zero inertial velocity, need to check every frame,
2597 * as distanceTravelled does not include this component - CIM */
2598 if (_nextAegisCheck < distanceTravelled || !vector_equal([super velocity],kZeroVector))
2599 {
2600 aegis_status = [self checkForAegis]; // is a station or something nearby??
2601 if (aegis_status == AEGIS_NONE)
2602 {
2603 // in open space: check every km
2605 }
2606 else
2607 {
2608 // near planets: check every 100m
2610 }
2611 }
2612 } // end if !isSubEntity
2613
2614 // scripting
2616 {
2617 // When crashing into a boulder, STATUS_LAUNCHING is sometimes skipped on scooping the resulting splinters.
2618 OOEntityStatus status = [self status];
2619 if (script != nil && (status == STATUS_IN_FLIGHT ||
2620 status == STATUS_LAUNCHING ||
2621 status == STATUS_BEING_SCOOPED ||
2622 (status == STATUS_ACTIVE && self == [UNIVERSE station])
2623 ))
2624 {
2625 [PLAYER setScriptTarget:self];
2626 [self doScriptEvent:OOJSID("shipSpawned")];
2627 if ([self status] != STATUS_DEAD) [PLAYER doScriptEvent:OOJSID("shipSpawned") withArgument:self];
2628 }
2630 }
2631 /* No point in starting the AI if still launching */
2632 if (!haveStartedJSAI && [self status] != STATUS_LAUNCHING)
2633 {
2634 haveStartedJSAI = YES;
2635 [self doScriptEvent:OOJSID("aiStarted")];
2636 }
2637
2638 // behaviours according to status and behaviour
2639 //
2640 if ([self status] == STATUS_LAUNCHING)
2641 {
2642 if ([UNIVERSE getTime] > launch_time + launch_delay) // move for while before thinking
2643 {
2644 StationEntity *stationLaunchedFrom = [UNIVERSE nearestEntityMatchingPredicate:IsStationPredicate parameter:NULL relativeToEntity:self];
2645 [self setStatus:STATUS_IN_FLIGHT];
2646 // awaken JS-based AIs
2647 haveStartedJSAI = YES;
2648 [self doScriptEvent:OOJSID("aiStarted")];
2649 [self doScriptEvent:OOJSID("shipLaunchedFromStation") withArgument:stationLaunchedFrom];
2650 [shipAI reactToMessage:@"LAUNCHED OKAY" context:@"launched"];
2651 }
2652 else
2653 {
2654 // ignore behaviour just keep moving...
2655 flightYaw = 0.0;
2656 [self applyAttitudeChanges:delta_t];
2657 [self applyThrust:delta_t];
2658 if (energy < maxEnergy)
2659 {
2660 energy += energy_recharge_rate * delta_t;
2661 if (energy > maxEnergy)
2662 {
2663 energy = maxEnergy;
2664 [self doScriptEvent:OOJSID("shipEnergyBecameFull")];
2665 [shipAI message:@"ENERGY_FULL"];
2666 }
2667 }
2668
2669 if ([self subEntityCount] > 0)
2670 {
2671 // only copy the subent array if there are subentities
2672 ShipEntity *se = nil;
2673 foreach (se, [self subEntities])
2674 {
2675 [se update:delta_t];
2676 }
2677 }
2678 // super update
2679 [super update:delta_t];
2680
2681 return;
2682 }
2683 }
2684 //
2685 // double check scooped behaviour
2686 //
2687 if ([self status] == STATUS_BEING_SCOOPED)
2688 {
2689 //if we are being tractored, but we have no owner, then we have a problem
2690 if (behaviour != BEHAVIOUR_TRACTORED || [self owner] == nil || [self owner] == self || [self owner] == NO_TARGET)
2691 {
2692 // escaped tractor beam
2693 [self setStatus:STATUS_IN_FLIGHT]; // should correct 'uncollidable objects' bug
2694 behaviour = BEHAVIOUR_IDLE;
2695 frustration = 0.0;
2696 [self setOwner:self];
2697 [shipAI exitStateMachineWithMessage:nil]; // Escapepods and others should continue their old AI here.
2698 }
2699 }
2700
2701 if ([self status] == STATUS_COCKPIT_DISPLAY)
2702 {
2703 flightYaw = 0.0;
2704 [self applyAttitudeChanges:delta_t];
2705 GLfloat range2 = 0.1 * HPdistance2(position, _destination) / (collision_radius * collision_radius);
2706 if ((range2 > 1.0)||(velocity.z > 0.0)) range2 = 1.0;
2707 position = HPvector_add(position, vectorToHPVector(vector_multiply_scalar(velocity, range2 * delta_t)));
2708 }
2709 else
2710 {
2711 [self processBehaviour:delta_t];
2712
2713 // manage energy
2714 if (energy < maxEnergy)
2715 {
2716 energy += energy_recharge_rate * delta_t;
2717 if (energy > maxEnergy)
2718 {
2719 energy = maxEnergy;
2720 [self doScriptEvent:OOJSID("shipEnergyBecameFull")];
2721 [shipAI message:@"ENERGY_FULL"];
2722 }
2723 }
2724
2725 if (!isSubEnt)
2726 {
2727 // update destination position for escorts
2728 [self refreshEscortPositions];
2729 if ([self hasEscorts])
2730 {
2731 ShipEntity *escort = nil;
2732 unsigned i = 0;
2733 // Note: works on escortArray rather than escortEnumerator because escorts may be mutated.
2734 foreach(escort, [self escortArray])
2735 {
2736 [escort setEscortDestination:[self coordinatesForEscortPosition:i++]];
2737 }
2738
2739 ShipEntity *leader = [[self escortGroup] leader];
2740 if (leader != nil && ([leader scanClass] != [self scanClass])) {
2741 OOLog(@"ship.sanityCheck.failed", @"Ship %@ escorting %@ with wrong scanclass!", self, leader);
2742 [[self escortGroup] removeShip:self];
2743 [self setEscortGroup:nil];
2744 }
2745 }
2746 }
2747 }
2748
2749 // rotational velocity
2750 if (!quaternion_equal(subentityRotationalVelocity, kIdentityQuaternion) &&
2751 !quaternion_equal(subentityRotationalVelocity, kZeroQuaternion))
2752 {
2753 Quaternion qf = subentityRotationalVelocity;
2754 qf.w *= (1.0 - delta_t);
2755 qf.x *= delta_t;
2756 qf.y *= delta_t;
2757 qf.z *= delta_t;
2758 [self setOrientation:quaternion_multiply(qf, orientation)];
2759 }
2760
2761 // reset totalBoundingBox
2763
2764 // super update
2765 [super update:delta_t];
2766
2767 // update subentities
2768
2769 if ([self subEntityCount] > 0)
2770 {
2771 // only copy the subent array if there are subentities
2772 ShipEntity *se = nil;
2773 foreach (se, [self subEntities])
2774 {
2775 [se update:delta_t];
2776 if ([se isShip])
2777 {
2778 BoundingBox sebb = [se findSubentityBoundingBox];
2779 bounding_box_add_vector(&totalBoundingBox, sebb.max);
2780 bounding_box_add_vector(&totalBoundingBox, sebb.min);
2781 }
2782 }
2783 }
2784
2785 if (aiScriptWakeTime > 0 && [PLAYER clockTimeAdjusted] > aiScriptWakeTime)
2786 {
2787 aiScriptWakeTime = 0;
2788 [self doScriptEvent:OOJSID("aiAwoken")];
2789 }
2790}
#define foreachkey(VAR, DICT)
Definition OOCocoa.h:366
const Quaternion kZeroQuaternion
BOOL ScanVectorFromString(NSString *xyzString, Vector *outVector)
#define SHIP_COOLING_FACTOR
Definition ShipEntity.h:61
#define CLOAKING_DEVICE_MIN_ENERGY
Definition ShipEntity.h:48
#define MILITARY_JAMMER_ENERGY_RATE
Definition ShipEntity.h:51
#define CLOAKING_DEVICE_ENERGY_RATE
Definition ShipEntity.h:47
#define WEAPON_COOLING_FACTOR
Definition ShipEntity.h:114
#define MILITARY_JAMMER_MIN_ENERGY
Definition ShipEntity.h:52
#define SUN_TEMPERATURE
Definition ShipEntity.h:72
#define SHIP_INSULATION_FACTOR
Definition ShipEntity.h:66
static NSString *const kOOLogEntityBehaviourChanged
Definition ShipEntity.m:101
GLfloat distanceTravelled
Definition Entity.h:136
BOOL hasFuelScoop()
void setEscortDestination:(HPVector dest)
void update:(OOTimeDelta delta_t)
GLfloat fuelChargeRate()
OOBehaviour debugLastBehaviour
Definition ShipEntity.h:427

◆ updateEscortFormation

- (void) updateEscortFormation

Definition at line 9593 of file ShipEntity.m.

13780{
13782}

◆ updateTrackingCurve

- (void) updateTrackingCurve

Definition at line 2093 of file ShipEntity.m.

6337{
6338 Entity *target = [self primaryTarget];
6339 OOTimeAbsolute now = [UNIVERSE getTime];
6340 if (target == nil || reactionTime <= 0.0 || trackingCurveTimes[0] + reactionTime/3.0 > now) return;
6344 if (EXPECT_NOT([target isShip] && [(ShipEntity *)target isCloaked]))
6345 {
6346 // if target is cloaked, introduce some more inaccuracy
6347 // 0.02 seems to be enough to give them slight difficulty on
6348 // a straight-line target and real trouble on anything better
6349 trackingCurvePositions[0] = HPvector_add([target position],OOHPVectorRandomSpatial([(ShipEntity *)target flightSpeed]*reactionTime*0.02));
6350 }
6351 else
6352 {
6353 trackingCurvePositions[0] = [target position];
6354 }
6358 trackingCurveTimes[0] = now;
6359 [self calculateTrackingCurve];
6360 return;
6361}

◆ upVector

- (Vector) upVector

Definition at line 14954 of file ShipEntity.m.

1278{
1279 return v_up;
1280}

◆ validateDefenseTargets

- (void) validateDefenseTargets

Definition at line 9593 of file ShipEntity.m.

11200{
11201 if (_defenseTargets == nil)
11202 {
11203 return;
11204 }
11205 // get enumerator from array as we'll be modifying original during enumeration
11206 NSEnumerator *defTargets = [[self allDefenseTargets] objectEnumerator];
11207 Entity *target = nil;
11208 while ((target = [[defTargets nextObject] weakRefUnderlyingObject]))
11209 {
11210 if ([target status] == STATUS_DEAD)
11211 {
11212 [self removeDefenseTarget:target];
11213 }
11214 }
11215}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ validForAddToUniverse

- (BOOL) validForAddToUniverse
implementation

Reimplemented from Entity.

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

2309{
2310 if (shipinfoDictionary == nil)
2311 {
2312 OOLog(@"shipEntity.notDict", @"Ship %@ was not set up from dictionary.", self);
2313 return NO;
2314 }
2315 return [super validForAddToUniverse];
2316}

◆ velocity

- (Vector) velocity
implementation

Reimplemented from Entity.

Definition at line 9593 of file ShipEntity.m.

12838{
12839 return vector_add([super velocity], [self thrustVector]);
12840}
Vector thrustVector()

◆ verifiedMissileTypeFromRole:

- (OOEquipmentType *) verifiedMissileTypeFromRole: (NSString *) role
implementation

Definition at line 2093 of file ShipEntity.m.

3747 :(NSString *)role
3748{
3749 NSString *eqRole = nil;
3750 NSString *shipKey = nil;
3751 ShipEntity *missile = nil;
3752 OOEquipmentType *missileType = nil;
3753 BOOL isRandomMissile = [role isEqualToString:@"missile"];
3754
3755 if (isRandomMissile)
3756 {
3757 while (!shipKey)
3758 {
3759 shipKey = [UNIVERSE randomShipKeyForRoleRespectingConditions:role];
3760 if (!shipKey)
3761 {
3762 OOLogWARN(@"ship.setUp.missiles", @"%@ \"%@\" used in ship \"%@\" needs a valid %@.plist entry.%@", @"random missile", shipKey, [self name], @"shipdata", @"Trying another missile.");
3763 }
3764 }
3765 }
3766 else
3767 {
3768 shipKey = [UNIVERSE randomShipKeyForRoleRespectingConditions:role];
3769 if (!shipKey)
3770 {
3771 OOLogWARN(@"ship.setUp.missiles", @"%@ \"%@\" used in ship \"%@\" needs a valid %@.plist entry.%@", @"missile_role", role, [self name], @"shipdata", @" Using defaults instead.");
3772 return nil;
3773 }
3774 }
3775
3776 eqRole = [OOEquipmentType getMissileRegistryRoleForShip:shipKey]; // eqRole != role for generic missiles.
3777
3778 if (eqRole == nil)
3779 {
3780 missile = [UNIVERSE newShipWithName:shipKey];
3781 if (!missile)
3782 {
3783 if (isRandomMissile)
3784 OOLogWARN(@"ship.setUp.missiles", @"%@ \"%@\" used in ship \"%@\" needs a valid %@.plist entry.%@", @"random missile", shipKey, [self name], @"shipdata", @"Trying another missile.");
3785 else
3786 OOLogWARN(@"ship.setUp.missiles", @"%@ \"%@\" used in ship \"%@\" needs a valid %@.plist entry.%@", @"missile_role", role, [self name], @"shipdata", @" Using defaults instead.");
3787
3788 [OOEquipmentType setMissileRegistryRole:@"" forShip:shipKey]; // no valid role for this shipKey
3789 if (isRandomMissile) return [self verifiedMissileTypeFromRole:role];
3790 else return nil;
3791 }
3792
3793 if(isRandomMissile)
3794 {
3795 id value;
3796 NSEnumerator *enumerator = [[[missile roleSet] roles] objectEnumerator];
3797
3798 while ((value = [enumerator nextObject]))
3799 {
3800 role = (NSString *)value;
3801 missileType = [OOEquipmentType equipmentTypeWithIdentifier:role];
3802 // ensure that we have a missile or mine
3803 if ([missileType isMissileOrMine]) break;
3804 }
3805
3806 if (![missileType isMissileOrMine])
3807 {
3808 role = shipKey; // unique identifier to use in lieu of a valid equipment type if none are defined inside the generic missile roleset.
3809 }
3810 }
3811
3812 missileType = [OOEquipmentType equipmentTypeWithIdentifier:role];
3813
3814 if (!missileType)
3815 {
3816 OOLogWARN(@"ship.setUp.missiles", @"%@ \"%@\" used in ship \"%@\" needs a valid %@.plist entry.%@", (isRandomMissile ? @"random missile" : @"missile_role"), role, [self name], @"equipment", @" Enabling compatibility mode.");
3817 missileType = [self generateMissileEquipmentTypeFrom:role];
3818 }
3819
3821 [missile release];
3822 }
3823 else
3824 {
3825 if ([eqRole isEqualToString:@""])
3826 {
3827 // wrong ship definition, already written to the log in a previous call.
3828 if (isRandomMissile) return [self verifiedMissileTypeFromRole:role]; // try and find a valid missile with role 'missile'.
3829 return nil;
3830 }
3831 missileType = [OOEquipmentType equipmentTypeWithIdentifier:eqRole];
3832 }
3833
3834 return missileType;
3835}
void setMissileRegistryRole:forShip:(NSString *roles,[forShip] NSString *shipKey)
NSString * getMissileRegistryRoleForShip:(NSString *shipKey)
NSSet * roles()
Definition OORoleSet.m:171

◆ volume

- (float) volume

Definition at line 14954 of file ShipEntity.m.

1437{
1438 return [octree volume];
1439}

◆ wasAddedToUniverse

- (void) wasAddedToUniverse
implementation

Reimplemented from Entity.

Definition at line 14954 of file ShipEntity.m.

1504{
1505 [super wasAddedToUniverse];
1506
1507 // if we have a universal id then we can proceed to set up any
1508 // stuff that happens when we get added to the UNIVERSE
1509 if (universalID != NO_TARGET)
1510 {
1511 // set up escorts
1512 if (([self status] == STATUS_IN_FLIGHT || [self status] == STATUS_LAUNCHING) && _pendingEscortCount != 0) // just popped into existence
1513 {
1514 [self setUpEscorts];
1515 }
1516 else
1517 {
1518 /* Earlier there was a silly log message here because I thought
1519 this would never happen, but wasn't entirely sure. Turns out
1520 it did!
1521 -- Ahruman 2009-09-13
1522 */
1524 }
1525 }
1526
1527 // Tell subentities, too
1528 [subEntities makeObjectsPerformSelector:@selector(wasAddedToUniverse)];
1529
1530 [self resetExhaustPlumes];
1531}

◆ wasRemovedFromUniverse

- (void) wasRemovedFromUniverse
implementation

Reimplemented from Entity.

Definition at line 14954 of file ShipEntity.m.

1535{
1536 [subEntities makeObjectsPerformSelector:@selector(wasRemovedFromUniverse)];
1537}

◆ weaponFacings

- (OOWeaponFacingSet) weaponFacings

Definition at line 2093 of file ShipEntity.m.

3248{
3249 return weapon_facings;
3250}

Referenced by OOShipLibraryWeapons().

+ Here is the caller graph for this function:

◆ weaponRange

- (GLfloat) weaponRange

◆ weaponRechargeRate

- (float) weaponRechargeRate

Definition at line 7411 of file ShipEntity.m.

7515{
7516 return weapon_recharge_rate;
7517}

◆ weaponRecoveryTime

- (GLfloat) weaponRecoveryTime

Definition at line 9593 of file ShipEntity.m.

9704{
9706 return OOClamp_0_1_f(result);
9707}

◆ weaponTypeForFacing:strict:

- (OOEquipmentType *) weaponTypeForFacing: (OOWeaponFacing) facing
strict: (BOOL) strict 

Reimplemented in PlayerEntity.

Definition at line 2093 of file ShipEntity.m.

3294 :(OOWeaponFacing)facing strict:(BOOL)strict
3295{
3296// OOWeaponType weaponType = [self weaponTypeIDForFacing:facing strict:strict];
3297// return [OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(weaponType)];
3298 return [self weaponTypeIDForFacing:facing strict:strict];
3299}

Referenced by ShipGetProperty().

+ Here is the caller graph for this function:

◆ weaponTypeIDForFacing:strict:

- (OOWeaponType) weaponTypeIDForFacing: (OOWeaponFacing) facing
strict: (BOOL) strict 

Definition at line 2093 of file ShipEntity.m.

3253 :(OOWeaponFacing)facing strict:(BOOL)strict
3254{
3255 OOWeaponType weaponType = nil;
3256
3257 if (facing & weapon_facings)
3258 {
3259 switch (facing)
3260 {
3262 weaponType = forward_weapon_type;
3263 // if no forward weapon, and not carrying out a strict check, see if subentities have forward weapons, return the first one found.
3264 if (isWeaponNone(weaponType) && !strict)
3265 {
3266 NSEnumerator *subEntEnum = [self shipSubEntityEnumerator];
3267 ShipEntity *subEntity = nil;
3268 while (isWeaponNone(weaponType) && (subEntity = [subEntEnum nextObject]))
3269 {
3270 weaponType = subEntity->forward_weapon_type;
3271 }
3272 }
3273 break;
3274
3275 case WEAPON_FACING_AFT:
3276 weaponType = aft_weapon_type;
3277 break;
3278
3279 case WEAPON_FACING_PORT:
3280 weaponType = port_weapon_type;
3281 break;
3282
3284 weaponType = starboard_weapon_type;
3285 break;
3286
3287 case WEAPON_FACING_NONE:
3288 break;
3289 }
3290 }
3291 return weaponType;
3292}

◆ witchspaceLeavingEffects

- (BOOL) witchspaceLeavingEffects

Definition at line 9593 of file ShipEntity.m.

13564{
13565 // all ships exiting witchspace will share the same orientation.
13566 orientation = [UNIVERSE getWitchspaceExitRotation];
13567 flightRoll = 0.0;
13568 stick_roll = 0.0;
13569 flightPitch = 0.0;
13570 stick_pitch = 0.0;
13571 flightYaw = 0.0;
13572 stick_yaw = 0.0;
13573 flightSpeed = 50.0; // constant speed same for all ships
13574// was a quarter of max speed, so the Anaconda speeds up and most
13575// others slow down - CIM
13576// will be overridden if left witchspace via a genuine wormhole
13578 if (![UNIVERSE addEntity:self]) // AI and status get initialised here
13579 {
13580 return NO;
13581 }
13582 [self setStatus:STATUS_EXITING_WITCHSPACE];
13583 [shipAI message:@"EXITED_WITCHSPACE"];
13584
13585 [UNIVERSE addWitchspaceJumpEffectForShip:self];
13586 [self setStatus:STATUS_IN_FLIGHT];
13587 return YES;
13588}

◆ withinStationAegis

- (BOOL) withinStationAegis

Definition at line 7619 of file ShipEntity.m.

7880{
7882}

◆ wormholeEntireGroup

- (void) wormholeEntireGroup

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

714{
715 [self wormholeGroup];
716 [self wormholeEscorts];
717}

◆ wormholeEscorts

- (void) wormholeEscorts

Provided by category ShipEntity(AI).

Definition at line 1 of file ShipEntityAI.m.

685{
686 NSEnumerator *shipEnum = nil;
687 ShipEntity *ship = nil;
688 NSString *context = nil;
689 WormholeEntity *whole = nil;
690
691 whole = [self primaryTarget];
692 if (![whole isWormhole]) return;
693
694#ifndef NDEBUG
695 context = [NSString stringWithFormat:@"%@ wormholeEscorts", [self shortDescription]];
696#endif
697
698 for (shipEnum = [self escortEnumerator]; (ship = [shipEnum nextObject]); )
699 {
700 [ship addTarget:whole];
701 [ship reactToAIMessage:@"ENTER WORMHOLE" context:context];
702 [ship doScriptEvent:OOJSID("wormholeSuggested") withArgument:whole];
703 }
704
705 // We now have no escorts..
706
707 [_escortGroup release];
708 _escortGroup = nil;
709
710}

◆ wormholeGroup

- (void) wormholeGroup
implementation

Provided by category ShipEntity(PureAI).

Definition at line 1 of file ShipEntityAI.m.

1648{
1649 NSEnumerator *shipEnum = nil;
1650 ShipEntity *ship = nil;
1651 WormholeEntity *whole = nil;
1652
1653 whole = [self primaryTarget];
1654 if (![whole isWormhole]) return;
1655
1656 for (shipEnum = [[self group] mutationSafeEnumerator]; (ship = [shipEnum nextObject]); )
1657 {
1658 [ship addTarget:whole];
1659 [ship reactToAIMessage:@"ENTER WORMHOLE" context:@"wormholeGroup"];
1660 [ship doScriptEvent:OOJSID("wormholeSuggested") withArgument:whole];
1661 }
1662}

Member Data Documentation

◆ _beaconCode

- (NSString*) _beaconCode
private

Definition at line 484 of file ShipEntity.h.

◆ _beaconDrawable

- (id<OOHUDBeaconIcon>) _beaconDrawable
private

Definition at line 488 of file ShipEntity.h.

◆ _beaconLabel

- (NSString*) _beaconLabel
private

Definition at line 485 of file ShipEntity.h.

◆ _collisionExceptions

- (OOWeakSet*) _collisionExceptions
private

Definition at line 477 of file ShipEntity.h.

◆ _defenseTargets

- (OOWeakSet*) _defenseTargets
private

Definition at line 474 of file ShipEntity.h.

◆ _destination

- (HPVector) _destination

Definition at line 203 of file ShipEntity.h.

◆ _equipment

- (NSMutableArray*) _equipment
private

Definition at line 461 of file ShipEntity.h.

◆ _escortGroup

- (OOShipGroup*) _escortGroup
private

Definition at line 467 of file ShipEntity.h.

◆ _escortPositions

- (Vector _escortPositions[MAX_ESCORTS])
private

Definition at line 471 of file ShipEntity.h.

◆ _escortPositionsValid

- (BOOL) _escortPositionsValid
private

Definition at line 472 of file ShipEntity.h.

◆ _explicitlyUnpiloted

- (unsigned) _explicitlyUnpiloted
protected

Definition at line 274 of file ShipEntity.h.

◆ _foundTarget

- (OOWeakReference*) _foundTarget
protected

Definition at line 440 of file ShipEntity.h.

◆ _group

- (OOShipGroup*) _group
private

Definition at line 466 of file ShipEntity.h.

◆ _heatInsulation

- (float) _heatInsulation
private

Definition at line 462 of file ShipEntity.h.

◆ _lastAegisLock

- (OOWeakReference*) _lastAegisLock
private

Definition at line 464 of file ShipEntity.h.

◆ _lastEscortTarget

- (OOWeakReference*) _lastEscortTarget
protected

Definition at line 441 of file ShipEntity.h.

◆ _lightsActive

- (unsigned) _lightsActive
protected

Definition at line 282 of file ShipEntity.h.

◆ _maxEscortCount

- (uint8_t) _maxEscortCount
private

Definition at line 468 of file ShipEntity.h.

◆ _maxShipSubIdx

- (NSUInteger) _maxShipSubIdx
protected

Definition at line 343 of file ShipEntity.h.

◆ _missed_shots

- (int) _missed_shots
protected

Definition at line 376 of file ShipEntity.h.

◆ _missileRole

- (NSString*) _missileRole
protected

Definition at line 321 of file ShipEntity.h.

◆ _multiplyWeapons

- (BOOL) _multiplyWeapons
protected

Definition at line 391 of file ShipEntity.h.

◆ _nextAegisCheck

- (double) _nextAegisCheck
private

Definition at line 490 of file ShipEntity.h.

◆ _nextBeacon

- (OOWeakReference*) _nextBeacon
private

Definition at line 487 of file ShipEntity.h.

◆ _pendingEscortCount

- (uint8_t) _pendingEscortCount
private

Definition at line 469 of file ShipEntity.h.

◆ _prevBeacon

- (OOWeakReference*) _prevBeacon
private

Definition at line 486 of file ShipEntity.h.

◆ _primaryAggressor

- (OOWeakReference*) _primaryAggressor
protected

Definition at line 438 of file ShipEntity.h.

◆ _primaryTarget

- (OOWeakReference*) _primaryTarget
protected

Definition at line 437 of file ShipEntity.h.

◆ _profileRadius

- (GLfloat) _profileRadius
private

Definition at line 479 of file ShipEntity.h.

◆ _proximityAlert

- (OOWeakReference*) _proximityAlert
protected

Definition at line 444 of file ShipEntity.h.

◆ _rememberedShip

- (OOWeakReference*) _rememberedShip
protected

Definition at line 443 of file ShipEntity.h.

◆ _scaleFactor

- (GLfloat) _scaleFactor
protected

Definition at line 388 of file ShipEntity.h.

◆ _scriptedMisjumpRange

- (GLfloat) _scriptedMisjumpRange
protected

Definition at line 284 of file ShipEntity.h.

◆ _shipHitByLaser

- (OOWeakReference*) _shipHitByLaser
private

Definition at line 481 of file ShipEntity.h.

◆ _shipKey

- (NSString*) _shipKey
private

Definition at line 459 of file ShipEntity.h.

◆ _showDamage

- (unsigned) _showDamage
protected

Definition at line 270 of file ShipEntity.h.

◆ _subEntityTakingDamage

- (OOWeakReference*) _subEntityTakingDamage
private

Definition at line 457 of file ShipEntity.h.

◆ _subIdx

- (NSUInteger) _subIdx
protected

Definition at line 342 of file ShipEntity.h.

◆ _targetStation

- (OOWeakReference*) _targetStation
protected

Definition at line 439 of file ShipEntity.h.

◆ _thankedShip

- (OOWeakReference*) _thankedShip
protected

Definition at line 442 of file ShipEntity.h.

◆ accuracy

- (GLfloat) accuracy
protected

Definition at line 373 of file ShipEntity.h.

◆ aegis_status

- (OOAegisStatus) aegis_status
protected

Definition at line 378 of file ShipEntity.h.

◆ aft_weapon_temp

- (GLfloat) aft_weapon_temp
protected

Definition at line 315 of file ShipEntity.h.

◆ aft_weapon_type

- (OOWeaponType) aft_weapon_type
protected

Definition at line 306 of file ShipEntity.h.

◆ afterburner_rate

- (GLfloat) afterburner_rate
protected

Definition at line 291 of file ShipEntity.h.

◆ afterburner_speed_factor

- (GLfloat) afterburner_speed_factor
protected

Definition at line 292 of file ShipEntity.h.

◆ aftWeaponOffset

- (NSArray *) aftWeaponOffset
protected

Definition at line 394 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ aim_tolerance

- (GLfloat) aim_tolerance
protected

Definition at line 375 of file ShipEntity.h.

◆ aiScript

- (OOJSScript*) aiScript
protected

Definition at line 223 of file ShipEntity.h.

◆ aiScriptWakeTime

- (OOTimeAbsolute) aiScriptWakeTime
protected

Definition at line 224 of file ShipEntity.h.

◆ behaviour

- (OOBehaviour) behaviour

Definition at line 211 of file ShipEntity.h.

Referenced by AI(OOAIDebugInspectorModule)::debugInspectorModules.

◆ being_fined

- (unsigned) being_fined
protected

Definition at line 259 of file ShipEntity.h.

◆ being_mined

- (unsigned) being_mined
protected

Definition at line 257 of file ShipEntity.h.

◆ bounty

- (OOCreditsQuantity) bounty
protected

Definition at line 300 of file ShipEntity.h.

◆ canFragment

- (unsigned) canFragment
protected

Definition at line 268 of file ShipEntity.h.

◆ cargo

- (NSMutableArray *) cargo
protected

Definition at line 361 of file ShipEntity.h.

◆ cargo_dump_time

- (OOTimeAbsolute) cargo_dump_time
protected

Definition at line 358 of file ShipEntity.h.

◆ cargo_flag

- (OOCargoFlag) cargo_flag
protected

Definition at line 299 of file ShipEntity.h.

◆ cargo_type

- (OOCargoType) cargo_type
protected

Definition at line 298 of file ShipEntity.h.

◆ cloakAutomatic

- (unsigned) cloakAutomatic
protected

Definition at line 267 of file ShipEntity.h.

◆ cloaking_device_active

- (unsigned) cloaking_device_active
protected

Definition at line 265 of file ShipEntity.h.

◆ cloakPassive

- (BOOL) cloakPassive
protected

Provided by category ShipEntity(Private).

Definition at line 266 of file ShipEntity.h.

◆ closeContactsInfo

- (NSMutableDictionary*) closeContactsInfo
protected

Definition at line 402 of file ShipEntity.h.

◆ collision_vector

- (Vector) collision_vector
protected

Definition at line 386 of file ShipEntity.h.

◆ commodity_amount

- (OOCargoQuantity) commodity_amount
protected

Definition at line 364 of file ShipEntity.h.

◆ commodity_type

- (OOCommodityType) commodity_type
protected

Definition at line 363 of file ShipEntity.h.

◆ coordinates

- (HPVector) coordinates
protected

Definition at line 339 of file ShipEntity.h.

◆ crew

- (NSArray *) crew
protected

Definition at line 399 of file ShipEntity.h.

◆ cruiseSpeed

- (double) cruiseSpeed
protected

Definition at line 243 of file ShipEntity.h.

◆ currentWeaponFacing

- (OOWeaponFacing) currentWeaponFacing
protected

◆ debugLastBehaviour

- (OOBehaviour) debugLastBehaviour
protected

Definition at line 427 of file ShipEntity.h.

◆ default_laser_color

- (OOColor*) default_laser_color
protected

Definition at line 230 of file ShipEntity.h.

◆ demoRate

- (OOScalar) demoRate
private

Definition at line 494 of file ShipEntity.h.

◆ demoStartOrientation

- (Quaternion) demoStartOrientation
private

Definition at line 496 of file ShipEntity.h.

◆ demoStartTime

- (OOTimeAbsolute) demoStartTime
private

Definition at line 495 of file ShipEntity.h.

◆ desired_range

- (GLfloat) desired_range

Definition at line 205 of file ShipEntity.h.

◆ desired_speed

- (GLfloat) desired_speed

Definition at line 206 of file ShipEntity.h.

◆ destination_system

- (OOSystemID) destination_system
protected

Definition at line 380 of file ShipEntity.h.

◆ displayName

- (NSString *) displayName
protected

Definition at line 330 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ distance2_scanned_ships

- (GLfloat distance2_scanned_ships[MAX_SCAN_NUMBER+1])
protected

Definition at line 414 of file ShipEntity.h.

◆ docking_match_rotation

- (unsigned) docking_match_rotation
protected

Definition at line 251 of file ShipEntity.h.

◆ dockingInstructions

- (NSDictionary *) dockingInstructions
protected

Definition at line 227 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ energy_recharge_rate

- (GLfloat) energy_recharge_rate
protected

Definition at line 302 of file ShipEntity.h.

◆ entity_personality

- (uint16_t) entity_personality
protected

Definition at line 430 of file ShipEntity.h.

◆ equipment_weight

- (OOCargoQuantity) equipment_weight
protected

Definition at line 297 of file ShipEntity.h.

◆ exhaust_emissive_color

- (OOColor*) exhaust_emissive_color
protected

Definition at line 231 of file ShipEntity.h.

◆ explosionType

- (NSArray*) explosionType
protected

Definition at line 335 of file ShipEntity.h.

◆ extra_cargo

- (OOCargoQuantity) extra_cargo
protected

Definition at line 296 of file ShipEntity.h.

◆ flightPitch

- (GLfloat) flightPitch
protected

Definition at line 370 of file ShipEntity.h.

Referenced by PlayerShipSetProperty().

◆ flightRoll

- (GLfloat) flightRoll
protected

Definition at line 369 of file ShipEntity.h.

Referenced by PlayerShipSetProperty().

◆ flightSpeed

- (GLfloat) flightSpeed
protected

Definition at line 368 of file ShipEntity.h.

◆ flightYaw

- (GLfloat) flightYaw
protected

Definition at line 371 of file ShipEntity.h.

Referenced by PlayerShipSetProperty().

◆ forward_weapon_temp

- (GLfloat) forward_weapon_temp
protected

Definition at line 315 of file ShipEntity.h.

◆ forward_weapon_type

- (OOWeaponType) forward_weapon_type
protected

Definition at line 305 of file ShipEntity.h.

◆ forwardWeaponOffset

- (NSArray *) forwardWeaponOffset
protected

Definition at line 393 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ frustration

- (double) frustration
protected

Definition at line 348 of file ShipEntity.h.

Referenced by AI(OOAIDebugInspectorModule)::debugInspectorModules.

◆ fuel

- (OOFuelQuantity) fuel
protected

Definition at line 288 of file ShipEntity.h.

◆ fuel_accumulator

- (GLfloat) fuel_accumulator
protected

Definition at line 289 of file ShipEntity.h.

◆ hasScoopMessage

- (unsigned) hasScoopMessage
protected

Definition at line 275 of file ShipEntity.h.

◆ haveExecutedSpawnAction

- (unsigned) haveExecutedSpawnAction
protected

Definition at line 279 of file ShipEntity.h.

◆ haveStartedJSAI

- (unsigned) haveStartedJSAI
protected

Definition at line 280 of file ShipEntity.h.

◆ home_system

- (OOSystemID) home_system
protected

Definition at line 379 of file ShipEntity.h.

◆ hyperspaceMotorSpinTime

- (float) hyperspaceMotorSpinTime
protected

Definition at line 247 of file ShipEntity.h.

◆ isDemoShip

- (BOOL) isDemoShip
private

Definition at line 493 of file ShipEntity.h.

◆ isFrangible

- (BOOL) isFrangible
protected

Definition at line 264 of file ShipEntity.h.

◆ isHulk

- (BOOL) isHulk
protected

Definition at line 261 of file ShipEntity.h.

◆ isMissile

- (BOOL) isMissile
protected

Definition at line 273 of file ShipEntity.h.

◆ isNearPlanetSurface

- (unsigned) isNearPlanetSurface
protected

Definition at line 263 of file ShipEntity.h.

◆ isWreckage

- (unsigned) isWreckage
protected

Definition at line 269 of file ShipEntity.h.

◆ jink

- (Vector) jink
protected

Definition at line 338 of file ShipEntity.h.

◆ laser_color

- (OOColor*) laser_color
protected

Definition at line 229 of file ShipEntity.h.

◆ last_shot_time

- (OOTimeAbsolute) last_shot_time
protected

Definition at line 359 of file ShipEntity.h.

◆ lastRadioMessage

- (NSString*) lastRadioMessage
protected

Definition at line 404 of file ShipEntity.h.

◆ launch_delay

- (double) launch_delay
protected

Definition at line 345 of file ShipEntity.h.

◆ launch_time

- (double) launch_time
protected

Definition at line 344 of file ShipEntity.h.

◆ likely_cargo

- (OOCargoQuantity) likely_cargo
protected

Definition at line 294 of file ShipEntity.h.

◆ max_cargo

- (OOCargoQuantity) max_cargo
protected

Definition at line 295 of file ShipEntity.h.

◆ max_flight_pitch

- (GLfloat) max_flight_pitch
protected

Definition at line 241 of file ShipEntity.h.

◆ max_flight_roll

- (GLfloat) max_flight_roll
protected

Definition at line 240 of file ShipEntity.h.

◆ max_flight_yaw

- (GLfloat) max_flight_yaw
protected

Definition at line 242 of file ShipEntity.h.

◆ max_missiles

- (unsigned) max_missiles
protected

Definition at line 320 of file ShipEntity.h.

◆ max_thrust

- (GLfloat) max_thrust
protected

Definition at line 245 of file ShipEntity.h.

◆ maxFlightSpeed

- (GLfloat) maxFlightSpeed
protected

Definition at line 239 of file ShipEntity.h.

Referenced by OOShipLibrarySpeed().

◆ messageTime

- (double) messageTime
protected

Definition at line 382 of file ShipEntity.h.

◆ military_jammer_active

- (unsigned) military_jammer_active
protected

Definition at line 249 of file ShipEntity.h.

◆ missile_launch_time

- (OOTimeAbsolute) missile_launch_time
protected

Definition at line 323 of file ShipEntity.h.

◆ missile_list

- (OOEquipmentType* missile_list[SHIPENTITY_MAX_MISSILES])
protected

Definition at line 434 of file ShipEntity.h.

◆ missile_load_time

- (OOTimeDelta) missile_load_time
protected

Definition at line 322 of file ShipEntity.h.

◆ missiles

- (unsigned) missiles
protected

Definition at line 319 of file ShipEntity.h.

◆ n_scanned_ships

- (unsigned) n_scanned_ships
protected

Definition at line 415 of file ShipEntity.h.

◆ name

- (NSString *) name
protected

Definition at line 327 of file ShipEntity.h.

Referenced by ShipGetProperty(), and ShipRunLegacyScriptActions().

◆ navpoints

- (HPVector navpoints[32])
protected

Definition at line 418 of file ShipEntity.h.

◆ next_navpoint_index

- (unsigned) next_navpoint_index
protected

Definition at line 419 of file ShipEntity.h.

◆ next_spark_time

- (double) next_spark_time
protected

Definition at line 384 of file ShipEntity.h.

◆ noRocks

- (unsigned) noRocks
protected

Definition at line 281 of file ShipEntity.h.

◆ number_of_navpoints

- (unsigned) number_of_navpoints
protected

Definition at line 420 of file ShipEntity.h.

◆ octree

- (Octree *) octree
protected

Definition at line 423 of file ShipEntity.h.

Referenced by absoluteIJKForSubentity.

◆ patrol_counter

- (int) patrol_counter
protected

Definition at line 351 of file ShipEntity.h.

◆ pitch_tolerance

- (GLfloat) pitch_tolerance
protected

Definition at line 374 of file ShipEntity.h.

◆ pitching_over

- (unsigned) pitching_over
protected

Definition at line 253 of file ShipEntity.h.

◆ planetForLanding

- (OOUniversalID) planetForLanding
protected

Definition at line 346 of file ShipEntity.h.

◆ port_weapon_temp

- (GLfloat) port_weapon_temp
protected

Definition at line 315 of file ShipEntity.h.

◆ port_weapon_type

- (OOWeaponType) port_weapon_type
protected

Definition at line 307 of file ShipEntity.h.

◆ portWeaponOffset

- (NSArray *) portWeaponOffset
protected

Definition at line 395 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ previousCondition

- (NSMutableDictionary*) previousCondition
protected

Definition at line 353 of file ShipEntity.h.

◆ primaryRole

- (NSString *) primaryRole
protected

Definition at line 333 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ reactionTime

- (float) reactionTime
protected

Definition at line 449 of file ShipEntity.h.

◆ reference

- (Vector) reference
protected

Definition at line 340 of file ShipEntity.h.

◆ reportAIMessages

- (BOOL) reportAIMessages
protected

Definition at line 255 of file ShipEntity.h.

◆ roleSet

- (OORoleSet *) roleSet
protected

Definition at line 332 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ rolling_over

- (unsigned) rolling_over
protected

Definition at line 254 of file ShipEntity.h.

◆ scan_description

- (NSString*) scan_description
protected

Definition at line 331 of file ShipEntity.h.

◆ scanned_ships

- (ShipEntity* scanned_ships[MAX_SCAN_NUMBER+1])
protected

Definition at line 413 of file ShipEntity.h.

◆ scanner_display_color1

- (OOColor*) scanner_display_color1
protected

Definition at line 232 of file ShipEntity.h.

◆ scanner_display_color2

- (OOColor*) scanner_display_color2
protected

Definition at line 233 of file ShipEntity.h.

◆ scanner_display_color_hostile1

- (OOColor*) scanner_display_color_hostile1
protected

Definition at line 234 of file ShipEntity.h.

◆ scanner_display_color_hostile2

- (OOColor*) scanner_display_color_hostile2
protected

Definition at line 235 of file ShipEntity.h.

◆ scannerRange

- (GLfloat) scannerRange
protected

Definition at line 317 of file ShipEntity.h.

◆ script

- (OOJSScript *) script
protected

Definition at line 222 of file ShipEntity.h.

◆ scripted_misjump

- (unsigned) scripted_misjump
protected

Definition at line 278 of file ShipEntity.h.

◆ scriptInfo

- (NSDictionary *) scriptInfo
protected

Definition at line 431 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ ship_temperature

- (float) ship_temperature
protected

Definition at line 410 of file ShipEntity.h.

◆ shipAI

- (AI*) shipAI
protected

Definition at line 325 of file ShipEntity.h.

◆ shipClassName

- (NSString *) shipClassName
protected

Definition at line 329 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ shipinfoDictionary

- (NSDictionary*) shipinfoDictionary
protected

Definition at line 217 of file ShipEntity.h.

◆ shipUniqueName

- (NSString *) shipUniqueName
protected

Definition at line 328 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ shot_counter

- (int) shot_counter
protected

Definition at line 357 of file ShipEntity.h.

◆ shot_time

- (OOTimeDelta) shot_time

Definition at line 197 of file ShipEntity.h.

◆ starboard_weapon_temp

- (GLfloat) starboard_weapon_temp
protected

Definition at line 315 of file ShipEntity.h.

◆ starboard_weapon_type

- (OOWeaponType) starboard_weapon_type
protected

Definition at line 308 of file ShipEntity.h.

◆ starboardWeaponOffset

- (NSArray *) starboardWeaponOffset
protected

Definition at line 396 of file ShipEntity.h.

Referenced by ShipGetProperty().

◆ stick_pitch

- (GLfloat) stick_pitch

Definition at line 209 of file ShipEntity.h.

◆ stick_roll

- (GLfloat) stick_roll

Definition at line 208 of file ShipEntity.h.

◆ stick_yaw

- (GLfloat) stick_yaw

Definition at line 210 of file ShipEntity.h.

◆ subEntities

- (NSArray *) subEntities
protected

Definition at line 433 of file ShipEntity.h.

Referenced by absoluteIJKForSubentity.

◆ subentityRotationalVelocity

- (Quaternion) subentityRotationalVelocity
protected

Definition at line 219 of file ShipEntity.h.

◆ success_factor

- (GLfloat) success_factor
protected

Definition at line 349 of file ShipEntity.h.

◆ sunGlareFilter

- (GLfloat) sunGlareFilter
protected

Definition at line 286 of file ShipEntity.h.

◆ suppressAegisMessages

- (unsigned) suppressAegisMessages
protected

Definition at line 272 of file ShipEntity.h.

◆ suppressExplosion

- (unsigned) suppressExplosion
protected

Definition at line 271 of file ShipEntity.h.

◆ thrust

- (float) thrust
protected

Definition at line 246 of file ShipEntity.h.

◆ totalBoundingBox

- (BoundingBox) totalBoundingBox

Definition at line 213 of file ShipEntity.h.

Referenced by OOShipLibrarySize(), and ShipGetProperty().

◆ trackCloseContacts

- (BOOL) trackCloseContacts
protected

Definition at line 262 of file ShipEntity.h.

◆ trackingCurveCoeffs

- (HPVector trackingCurveCoeffs[3])
protected

Definition at line 452 of file ShipEntity.h.

◆ trackingCurvePositions

- (HPVector trackingCurvePositions[4])
protected

Definition at line 450 of file ShipEntity.h.

◆ trackingCurveTimes

- (OOTimeAbsolute trackingCurveTimes[4])
protected

Definition at line 451 of file ShipEntity.h.

◆ tractor_position

- (Vector) tractor_position
protected

Definition at line 407 of file ShipEntity.h.

◆ v_forward

- (Vector) v_forward

Definition at line 200 of file ShipEntity.h.

◆ v_right

- (Vector) v_right

Definition at line 200 of file ShipEntity.h.

◆ v_up

- (Vector) v_up

Definition at line 200 of file ShipEntity.h.

◆ weapon_damage

- (GLfloat) weapon_damage
protected

Definition at line 309 of file ShipEntity.h.

◆ weapon_damage_override

- (GLfloat) weapon_damage_override
protected

Definition at line 310 of file ShipEntity.h.

◆ weapon_energy_use

- (GLfloat) weapon_energy_use
protected

Definition at line 314 of file ShipEntity.h.

◆ weapon_facings

- (OOWeaponFacingSet) weapon_facings
protected

Definition at line 304 of file ShipEntity.h.

◆ weapon_recharge_rate

- (float) weapon_recharge_rate
protected

Definition at line 356 of file ShipEntity.h.

◆ weapon_shot_temperature

- (GLfloat) weapon_shot_temperature
protected

Definition at line 314 of file ShipEntity.h.

◆ weapon_temp

- (GLfloat) weapon_temp
protected

Definition at line 314 of file ShipEntity.h.

◆ weaponRange

- (GLfloat) weaponRange
protected

Definition at line 311 of file ShipEntity.h.

Referenced by OOLaserShotEntity::dealloc.


The documentation for this class was generated from the following files: