More AI updates:
- NPCs with multiple weapons will account for overheated lasers - Refactor attack style selection routine - Reserve three advanced attack styles for later implementation - Raise default missile load time for non-awful pilots (shipdata can override) - Make NPCs slightly less accurate with aft and a bit more less accurate with side lasers Balancing seems vaguely right for core ships, but needs more testing git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@4975 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
parent
d52c90e646
commit
b0be15eeb3
@ -4034,7 +4034,7 @@ static GLfloat sBaseMass = 0.0;
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weapon_temp / PLAYER_MAX_WEAPON_TEMP >= 0.85)
|
if (weapon_temp / PLAYER_MAX_WEAPON_TEMP >= WEAPON_COOLING_CUTOUT)
|
||||||
{
|
{
|
||||||
[self playWeaponOverheated];
|
[self playWeaponOverheated];
|
||||||
[UNIVERSE addMessage:DESC(@"weapon-overheat") forCount:3.0];
|
[UNIVERSE addMessage:DESC(@"weapon-overheat") forCount:3.0];
|
||||||
|
@ -61,14 +61,12 @@ OOJSScript, OORoleSet, OOShipGroup, OOEquipmentType;
|
|||||||
#define MILITARY_JAMMER_MIN_ENERGY 128
|
#define MILITARY_JAMMER_MIN_ENERGY 128
|
||||||
|
|
||||||
#define COMBAT_IN_RANGE_FACTOR 0.035f
|
#define COMBAT_IN_RANGE_FACTOR 0.035f
|
||||||
|
#define COMBAT_BROADSIDE_IN_RANGE_FACTOR 0.020f
|
||||||
#define COMBAT_OUT_RANGE_FACTOR 0.500f
|
#define COMBAT_OUT_RANGE_FACTOR 0.500f
|
||||||
#define COMBAT_BROADSIDE_RANGE_FACTOR 0.900f
|
#define COMBAT_BROADSIDE_RANGE_FACTOR 0.900f
|
||||||
#define COMBAT_WEAPON_RANGE_FACTOR 1.200f
|
#define COMBAT_WEAPON_RANGE_FACTOR 1.200f
|
||||||
#define COMBAT_JINK_OFFSET 500.0f
|
#define COMBAT_JINK_OFFSET 500.0f
|
||||||
|
|
||||||
#define COMBAT_AI_IS_SMART 5.0f
|
|
||||||
#define COMBAT_AI_TRACKS_CLOSER 7.5f
|
|
||||||
|
|
||||||
#define SHIP_COOLING_FACTOR 1.0f
|
#define SHIP_COOLING_FACTOR 1.0f
|
||||||
#define SHIP_INSULATION_FACTOR 0.00175f
|
#define SHIP_INSULATION_FACTOR 0.00175f
|
||||||
#define SHIP_MAX_CABIN_TEMP 256.0f
|
#define SHIP_MAX_CABIN_TEMP 256.0f
|
||||||
@ -120,6 +118,14 @@ OOJSScript, OORoleSet, OOShipGroup, OOEquipmentType;
|
|||||||
|
|
||||||
#define WEAPON_COOLING_FACTOR 6.0f
|
#define WEAPON_COOLING_FACTOR 6.0f
|
||||||
#define NPC_MAX_WEAPON_TEMP 256.0f
|
#define NPC_MAX_WEAPON_TEMP 256.0f
|
||||||
|
#define WEAPON_COOLING_CUTOUT 0.85f
|
||||||
|
|
||||||
|
#define COMBAT_AI_WEAPON_TEMP_READY 0.25f * NPC_MAX_WEAPON_TEMP
|
||||||
|
#define COMBAT_AI_WEAPON_TEMP_USABLE WEAPON_COOLING_CUTOUT * NPC_MAX_WEAPON_TEMP
|
||||||
|
#define COMBAT_AI_ISNT_AWFUL 0.0f
|
||||||
|
#define COMBAT_AI_IS_SMART 5.0f
|
||||||
|
#define COMBAT_AI_TRACKS_CLOSER 7.5f
|
||||||
|
|
||||||
|
|
||||||
#define MAX_LANDING_SPEED 50.0
|
#define MAX_LANDING_SPEED 50.0
|
||||||
#define MAX_LANDING_SPEED2 (MAX_LANDING_SPEED * MAX_LANDING_SPEED)
|
#define MAX_LANDING_SPEED2 (MAX_LANDING_SPEED * MAX_LANDING_SPEED)
|
||||||
@ -906,6 +912,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
|
|
||||||
//return 0.0 if there is no primary target
|
//return 0.0 if there is no primary target
|
||||||
- (double) rangeToPrimaryTarget;
|
- (double) rangeToPrimaryTarget;
|
||||||
|
- (double) approachAspectToPrimaryTarget;
|
||||||
- (double) rangeToSecondaryTarget:(Entity *)target;
|
- (double) rangeToSecondaryTarget:(Entity *)target;
|
||||||
- (BOOL) onTarget:(OOViewID) direction withWeapon:(OOWeaponType)weapon;
|
- (BOOL) onTarget:(OOViewID) direction withWeapon:(OOWeaponType)weapon;
|
||||||
|
|
||||||
@ -1088,6 +1095,7 @@ uintN argc = sizeof argv / sizeof *argv; \
|
|||||||
|
|
||||||
NSDictionary *OODefaultShipShaderMacros(void);
|
NSDictionary *OODefaultShipShaderMacros(void);
|
||||||
|
|
||||||
|
GLfloat getWeaponRangeFromType(OOWeaponType weapon_type);
|
||||||
|
|
||||||
// Stuff implemented in OOConstToString.m
|
// Stuff implemented in OOConstToString.m
|
||||||
enum
|
enum
|
||||||
|
@ -568,7 +568,10 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
|
|||||||
accuracy = OOClamp_0_max_f(accuracy, 10.0f);
|
accuracy = OOClamp_0_max_f(accuracy, 10.0f);
|
||||||
}
|
}
|
||||||
[self setAccuracy:accuracy]; // set derived variables
|
[self setAccuracy:accuracy]; // set derived variables
|
||||||
|
if (accuracy >= COMBAT_AI_ISNT_AWFUL && missile_load_time < 0.1)
|
||||||
|
{
|
||||||
|
missile_load_time = 2.0; // smart enough not to waste all missiles on 1 ECM!
|
||||||
|
}
|
||||||
|
|
||||||
// escorts
|
// escorts
|
||||||
_maxEscortCount = MIN([shipDict oo_unsignedCharForKey:@"escorts" defaultValue:0], (uint8_t)MAX_ESCORTS);
|
_maxEscortCount = MIN([shipDict oo_unsignedCharForKey:@"escorts" defaultValue:0], (uint8_t)MAX_ESCORTS);
|
||||||
@ -3446,66 +3449,101 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
float max_available_speed = maxFlightSpeed;
|
float max_available_speed = maxFlightSpeed;
|
||||||
double range = [self rangeToPrimaryTarget];
|
double range = [self rangeToPrimaryTarget];
|
||||||
if (canBurn) max_available_speed *= [self afterburnerFactor];
|
if (canBurn) max_available_speed *= [self afterburnerFactor];
|
||||||
|
desired_speed = max_available_speed;
|
||||||
|
|
||||||
if (cloakAutomatic) [self activateCloakingDevice];
|
if (cloakAutomatic) [self activateCloakingDevice];
|
||||||
|
|
||||||
desired_speed = max_available_speed;
|
if (forward_weapon_type == WEAPON_THARGOID_LASER)
|
||||||
if (range < COMBAT_IN_RANGE_FACTOR * weaponRange)
|
|
||||||
{
|
{
|
||||||
if (aft_weapon_type == WEAPON_NONE)
|
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOL aft_weapon_ready = (aft_weapon_type != WEAPON_NONE) && (aft_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY);
|
||||||
|
BOOL forward_weapon_ready = (forward_weapon_type != WEAPON_NONE) && (forward_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY);
|
||||||
|
BOOL port_weapon_ready = (port_weapon_type != WEAPON_NONE) && (port_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY);
|
||||||
|
BOOL starboard_weapon_ready = (starboard_weapon_type != WEAPON_NONE) && (starboard_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY);
|
||||||
|
// if no weapons cool enough to be good choices, be less picky
|
||||||
|
if (!forward_weapon_ready && !aft_weapon_ready && !port_weapon_ready && !starboard_weapon_ready)
|
||||||
{
|
{
|
||||||
if (!pitching_over) // don't change jink in the middle of a sharp turn.
|
aft_weapon_ready = (aft_weapon_type != WEAPON_NONE) && (aft_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE);
|
||||||
{
|
forward_weapon_ready = (forward_weapon_type != WEAPON_NONE) && (forward_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE);
|
||||||
/*
|
port_weapon_ready = (port_weapon_type != WEAPON_NONE) && (port_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE);
|
||||||
For most AIs, is behaviour_attack_target called as starting behaviour on every hit.
|
starboard_weapon_ready = (starboard_weapon_type != WEAPON_NONE) && (starboard_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE);
|
||||||
Target can both fly towards or away from ourselves here. Both situations
|
}
|
||||||
need a different jink.z for optimal collision avoidance at high speed approach and low speed dogfighting.
|
if (!forward_weapon_ready && !aft_weapon_ready && !port_weapon_ready && !starboard_weapon_ready)
|
||||||
The COMBAT_JINK_OFFSET intentionally over-compensates the range for collision radii to send ships towards
|
{ // no usable weapons! Either not fitted or overheated
|
||||||
the target at low speeds.
|
// TODO: good pilots use behaviour_evasive_action instead
|
||||||
*/
|
|
||||||
ShipEntity* target = [UNIVERSE entityForUniversalID:primaryTarget];
|
|
||||||
float relativeSpeed = magnitude(vector_subtract([self velocity], [target velocity]));
|
|
||||||
jink.x = (ranrot_rand() % 256) - 128.0;
|
|
||||||
jink.y = (ranrot_rand() % 256) - 128.0;
|
|
||||||
jink.z = range + COMBAT_JINK_OFFSET - relativeSpeed / max_flight_pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
|
behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
jink = kZeroVector;
|
BOOL nearby = range < COMBAT_IN_RANGE_FACTOR * getWeaponRangeFromType(forward_weapon_type);
|
||||||
behaviour = BEHAVIOUR_RUNNING_DEFENSE;
|
|
||||||
}
|
if (nearby && aft_weapon_ready)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (forward_weapon_type == WEAPON_THARGOID_LASER)
|
|
||||||
{
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
|
|
||||||
}
|
|
||||||
else if ((port_weapon_type != WEAPON_NONE || starboard_weapon_type != WEAPON_NONE) && randf() < 0.67)
|
|
||||||
// anyone with a side laser fitted presumably knows how to use it
|
|
||||||
{
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_BROADSIDE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if (universalID & 1) // 50% of ships are smart S.M.R.T. smart!
|
|
||||||
if (accuracy > 0.0) // may as well make it the 50% who can shoot straight
|
|
||||||
{
|
{
|
||||||
if (randf() < 0.75)
|
jink = kZeroVector; // almost all behaviours
|
||||||
|
behaviour = BEHAVIOUR_RUNNING_DEFENSE;
|
||||||
|
}
|
||||||
|
else if (nearby && (port_weapon_ready || starboard_weapon_ready))
|
||||||
|
{
|
||||||
|
jink = kZeroVector; // almost all behaviours
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_BROADSIDE;
|
||||||
|
}
|
||||||
|
else if (nearby)
|
||||||
|
{
|
||||||
|
if (!pitching_over) // don't change jink in the middle of a sharp turn.
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
For most AIs, is behaviour_attack_target called as starting behaviour on every hit.
|
||||||
|
Target can both fly towards or away from ourselves here. Both situations
|
||||||
|
need a different jink.z for optimal collision avoidance at high speed approach and low speed dogfighting.
|
||||||
|
The COMBAT_JINK_OFFSET intentionally over-compensates the range for collision radii to send ships towards
|
||||||
|
the target at low speeds.
|
||||||
|
*/
|
||||||
|
ShipEntity* target = [UNIVERSE entityForUniversalID:primaryTarget];
|
||||||
|
float relativeSpeed = magnitude(vector_subtract([self velocity], [target velocity]));
|
||||||
|
jink.x = (ranrot_rand() % 256) - 128.0;
|
||||||
|
jink.y = (ranrot_rand() % 256) - 128.0;
|
||||||
|
jink.z = range + COMBAT_JINK_OFFSET - relativeSpeed / max_flight_pitch;
|
||||||
|
}
|
||||||
|
// TODO: good pilots use behaviour_break_off_target instead
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (forward_weapon_ready)
|
||||||
|
{
|
||||||
|
jink = kZeroVector; // almost all behaviours
|
||||||
|
|
||||||
|
// TODO: good pilots use behaviour_attack_sniper sometimes
|
||||||
|
|
||||||
|
double aspect = [self approachAspectToPrimaryTarget];
|
||||||
|
if (accuracy >= COMBAT_AI_ISNT_AWFUL && aspect < 0)
|
||||||
|
{
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX;
|
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX;
|
||||||
else
|
}
|
||||||
|
else if (accuracy >= COMBAT_AI_ISNT_AWFUL && canBurn)
|
||||||
|
{
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
|
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (port_weapon_ready || starboard_weapon_ready)
|
||||||
{
|
{
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
|
jink = kZeroVector; // almost all behaviours
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_BROADSIDE;
|
||||||
|
}
|
||||||
|
else if (aft_weapon_ready)
|
||||||
|
{
|
||||||
|
jink = kZeroVector; // almost all behaviours
|
||||||
|
behaviour = BEHAVIOUR_RUNNING_DEFENSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jink = kZeroVector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frustration = 0.0; // behaviour changed, so reset frustration
|
frustration = 0.0; // behaviour changed, so reset frustration
|
||||||
flightYaw = 0.0;
|
flightYaw = 0.0;
|
||||||
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
|
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
|
||||||
@ -3523,37 +3561,13 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
if (cloakAutomatic) [self activateCloakingDevice];
|
if (cloakAutomatic) [self activateCloakingDevice];
|
||||||
|
|
||||||
desired_speed = max_available_speed;
|
desired_speed = max_available_speed;
|
||||||
if (range < COMBAT_IN_RANGE_FACTOR * weaponRange)
|
if (range < COMBAT_BROADSIDE_IN_RANGE_FACTOR * weaponRange)
|
||||||
{
|
{
|
||||||
if (aft_weapon_type == WEAPON_NONE)
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
{
|
|
||||||
if (!pitching_over) // don't change jink in the middle of a sharp turn.
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
For most AIs, is behaviour_attack_target called as starting behaviour on every hit.
|
|
||||||
Target can both fly towards or away from ourselves here. Both situations
|
|
||||||
need a different jink.z for optimal collision avoidance at high speed approach and low speed dogfighting.
|
|
||||||
The COMBAT_JINK_OFFSET intentionally over-compensates the range for collision radii to send ships towards
|
|
||||||
the target at low speeds.
|
|
||||||
*/
|
|
||||||
ShipEntity* target = [UNIVERSE entityForUniversalID:primaryTarget];
|
|
||||||
float relativeSpeed = magnitude(vector_subtract([self velocity], [target velocity]));
|
|
||||||
jink.x = (ranrot_rand() % 256) - 128.0;
|
|
||||||
jink.y = (ranrot_rand() % 256) - 128.0;
|
|
||||||
jink.z = range + COMBAT_JINK_OFFSET - relativeSpeed / max_flight_pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
jink = kZeroVector;
|
|
||||||
behaviour = BEHAVIOUR_RUNNING_DEFENSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (randf() < 0.5)
|
if (port_weapon_temp < starboard_weapon_temp)
|
||||||
{
|
{
|
||||||
if (port_weapon_type == WEAPON_NONE)
|
if (port_weapon_type == WEAPON_NONE)
|
||||||
{
|
{
|
||||||
@ -3620,7 +3634,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
[self noteLostTargetAndGoIdle];
|
[self noteLostTargetAndGoIdle];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (range > COMBAT_BROADSIDE_RANGE_FACTOR * weaponRange)
|
GLfloat currentWeaponRange = getWeaponRangeFromType(leftside?port_weapon_type:starboard_weapon_type);
|
||||||
|
if (range > COMBAT_BROADSIDE_RANGE_FACTOR * currentWeaponRange)
|
||||||
{
|
{
|
||||||
behaviour = BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE;
|
behaviour = BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE;
|
||||||
[self applyRoll:delta_t*flightRoll climb:delta_t*flightPitch andYaw:delta_t*flightYaw];
|
[self applyRoll:delta_t*flightRoll climb:delta_t*flightPitch andYaw:delta_t*flightYaw];
|
||||||
@ -3628,35 +3643,13 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShipEntity* target = [UNIVERSE entityForUniversalID:primaryTarget];
|
|
||||||
// can get closer on broadsides since there's less risk of a collision
|
|
||||||
if ((range*2.0 < COMBAT_IN_RANGE_FACTOR * weaponRange)||(proximity_alert != NO_TARGET))
|
|
||||||
{
|
|
||||||
/* FIXME: this next block is shared with behaviour_attack_target; rationalise to function */
|
|
||||||
|
|
||||||
|
// can get closer on broadsides since there's less risk of a collision
|
||||||
|
if ((range < COMBAT_BROADSIDE_IN_RANGE_FACTOR * currentWeaponRange)||(proximity_alert != NO_TARGET))
|
||||||
|
{
|
||||||
if (proximity_alert == NO_TARGET || proximity_alert == primaryTarget)
|
if (proximity_alert == NO_TARGET || proximity_alert == primaryTarget)
|
||||||
{
|
{
|
||||||
if (aft_weapon_type == WEAPON_NONE)
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
{
|
|
||||||
/*
|
|
||||||
jink.z has a great influence on the dogfight expecience at close range. Strongest jink behaviour for a frontal approaching
|
|
||||||
ship is achieved with a z-distance at the size of the actual distance. However, to allow fast flying ships avoiding collisions,
|
|
||||||
the jink point should be defined closer to the ship itself.
|
|
||||||
*/
|
|
||||||
float relativeSpeed = magnitude(vector_subtract([self velocity], [target velocity]));
|
|
||||||
jink.x = (ranrot_rand() % 256) - 128.0;
|
|
||||||
jink.y = (ranrot_rand() % 256) - 128.0;
|
|
||||||
jink.z = range + COMBAT_JINK_OFFSET - relativeSpeed / max_flight_pitch; // range= ~440 for pulse weapon and ~1050 for military laser.
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
|
|
||||||
frustration = 0.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// entering running defense mode
|
|
||||||
jink = kZeroVector;
|
|
||||||
behaviour = BEHAVIOUR_RUNNING_DEFENSE;
|
|
||||||
frustration = 0.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3675,7 +3668,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
// control speed
|
// control speed
|
||||||
//
|
//
|
||||||
BOOL isUsingAfterburner = canBurn && (flightSpeed > maxFlightSpeed);
|
BOOL isUsingAfterburner = canBurn && (flightSpeed > maxFlightSpeed);
|
||||||
double slow_down_range = weaponRange * COMBAT_WEAPON_RANGE_FACTOR * ((isUsingAfterburner)? 3.0 * [self afterburnerFactor] : 1.0);
|
double slow_down_range = currentWeaponRange * COMBAT_WEAPON_RANGE_FACTOR * ((isUsingAfterburner)? 3.0 * [self afterburnerFactor] : 1.0);
|
||||||
// double target_speed = [target speed];
|
// double target_speed = [target speed];
|
||||||
if (range <= slow_down_range)
|
if (range <= slow_down_range)
|
||||||
desired_speed = fmin(0.8 * maxFlightSpeed, fmax((2.0-frustration)*maxFlightSpeed, 0.1 * maxFlightSpeed)); // within the weapon's range slow down to aim
|
desired_speed = fmin(0.8 * maxFlightSpeed, fmax((2.0-frustration)*maxFlightSpeed, 0.1 * maxFlightSpeed)); // within the weapon's range slow down to aim
|
||||||
@ -3684,7 +3677,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
|
|
||||||
double last_success_factor = success_factor;
|
double last_success_factor = success_factor;
|
||||||
success_factor = [self trackSideTarget:delta_t:leftside]; // do the actual piloting
|
success_factor = [self trackSideTarget:delta_t:leftside]; // do the actual piloting
|
||||||
if (success_factor < -0.9)
|
if (weapon_temp > COMBAT_AI_WEAPON_TEMP_USABLE)
|
||||||
{ // will probably have more luck with the other laser or picking a different attack method
|
{ // will probably have more luck with the other laser or picking a different attack method
|
||||||
if (leftside)
|
if (leftside)
|
||||||
{
|
{
|
||||||
@ -3754,7 +3747,10 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
[self applyRoll:delta_t*flightRoll climb:delta_t*flightPitch andYaw:delta_t*flightYaw];
|
[self applyRoll:delta_t*flightRoll climb:delta_t*flightPitch andYaw:delta_t*flightYaw];
|
||||||
[self applyThrust:delta_t];
|
[self applyThrust:delta_t];
|
||||||
|
|
||||||
|
if (weapon_temp > COMBAT_AI_WEAPON_TEMP_USABLE)
|
||||||
|
{
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3838,7 +3834,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
double distance = [self rangeToDestination];
|
double distance = [self rangeToDestination];
|
||||||
success_factor = distance;
|
success_factor = distance;
|
||||||
|
|
||||||
if (range < slow_down_range)
|
if (range < slow_down_range && (behaviour == BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX))
|
||||||
{
|
{
|
||||||
if (range < back_off_range)
|
if (range < back_off_range)
|
||||||
{
|
{
|
||||||
@ -3907,23 +3903,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
else if(frustration > 0.0) frustration -= delta_t * 0.75;
|
else if(frustration > 0.0) frustration -= delta_t * 0.75;
|
||||||
if(frustration > 10)
|
if(frustration > 10)
|
||||||
{
|
{
|
||||||
frustration = 0.0;
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
if (randf() < 0.4)
|
|
||||||
{
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (randf() < 0.5)
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX;
|
|
||||||
else
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
|
|
||||||
}
|
|
||||||
if (forward_weapon_type == WEAPON_THARGOID_LASER)
|
|
||||||
{
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// use weaponry
|
// use weaponry
|
||||||
@ -3941,6 +3921,11 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
flightYaw = 0.0;
|
flightYaw = 0.0;
|
||||||
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
|
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
|
||||||
[self applyThrust:delta_t];
|
[self applyThrust:delta_t];
|
||||||
|
|
||||||
|
if (weapon_temp > COMBAT_AI_WEAPON_TEMP_USABLE)
|
||||||
|
{
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3994,27 +3979,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
{
|
{
|
||||||
if (proximity_alert == NO_TARGET || proximity_alert == primaryTarget)
|
if (proximity_alert == NO_TARGET || proximity_alert == primaryTarget)
|
||||||
{
|
{
|
||||||
if (aft_weapon_type == WEAPON_NONE)
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
{
|
|
||||||
/*
|
|
||||||
jink.z has a great influence on the dogfight expecience at close range. Strongest jink behaviour for a frontal approaching
|
|
||||||
ship is achieved with a z-distance at the size of the actual distance. However, to allow fast flying ships avoiding collisions,
|
|
||||||
the jink point should be defined closer to the ship itself.
|
|
||||||
*/
|
|
||||||
float relativeSpeed = magnitude(vector_subtract([self velocity], [target velocity]));
|
|
||||||
jink.x = (ranrot_rand() % 256) - 128.0;
|
|
||||||
jink.y = (ranrot_rand() % 256) - 128.0;
|
|
||||||
jink.z = range + COMBAT_JINK_OFFSET - relativeSpeed / max_flight_pitch; // range= ~440 for pulse weapon and ~1050 for military laser.
|
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
|
|
||||||
frustration = 0.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// entering running defense mode
|
|
||||||
jink = kZeroVector;
|
|
||||||
behaviour = BEHAVIOUR_RUNNING_DEFENSE;
|
|
||||||
frustration = 0.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -4070,7 +4035,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
jink.x = (ranrot_rand() % 256) - 128.0;
|
jink.x = (ranrot_rand() % 256) - 128.0;
|
||||||
jink.y = (ranrot_rand() % 256) - 128.0;
|
jink.y = (ranrot_rand() % 256) - 128.0;
|
||||||
jink.z = 1000.0;
|
jink.z = 1000.0;
|
||||||
behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
frustration = 0.0;
|
frustration = 0.0;
|
||||||
desired_speed = maxFlightSpeed;
|
desired_speed = maxFlightSpeed;
|
||||||
}
|
}
|
||||||
@ -4090,6 +4055,11 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
flightYaw = 0.0;
|
flightYaw = 0.0;
|
||||||
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
|
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
|
||||||
[self applyThrust:delta_t];
|
[self applyThrust:delta_t];
|
||||||
|
|
||||||
|
if (weapon_temp > COMBAT_AI_WEAPON_TEMP_USABLE)
|
||||||
|
{
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4107,20 +4077,30 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
if (last_success_factor > success_factor) // our target is closing in.
|
if (last_success_factor > success_factor) // our target is closing in.
|
||||||
{
|
{
|
||||||
frustration += delta_t;
|
frustration += delta_t;
|
||||||
if (frustration > 10.0)
|
}
|
||||||
{
|
else
|
||||||
if (randf() < 0.3) desired_speed = maxFlightSpeed * (([self hasFuelInjection] && (fuel > MIN_FUEL)) ? [self afterburnerFactor] : 1);
|
{ // not getting away fast enough?
|
||||||
else if (range > COMBAT_IN_RANGE_FACTOR * weaponRange && randf() < 0.3) behaviour = BEHAVIOUR_ATTACK_TARGET;
|
frustration += delta_t / 4.0 ;
|
||||||
|
}
|
||||||
|
|
||||||
jink.x = (ranrot_rand() % 256) - 128.0;
|
if (frustration > 10.0 - accuracy/2.0)
|
||||||
jink.y = (ranrot_rand() % 256) - 128.0;
|
{
|
||||||
if (randf() < 0.3)
|
if (randf() < 0.3) {
|
||||||
{
|
desired_speed = maxFlightSpeed * (([self hasFuelInjection] && (fuel > MIN_FUEL)) ? [self afterburnerFactor] : 1);
|
||||||
jink.z /= 2; // move the z-offset closer to the target to let him fly away from the target.
|
|
||||||
desired_speed = flightSpeed * 2; // increase speed a bit.
|
|
||||||
}
|
|
||||||
frustration = 0.0;
|
|
||||||
}
|
}
|
||||||
|
else if (range > COMBAT_IN_RANGE_FACTOR * weaponRange && randf() < 0.3)
|
||||||
|
{
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
|
}
|
||||||
|
|
||||||
|
jink.x = (ranrot_rand() % 256) - 128.0;
|
||||||
|
jink.y = (ranrot_rand() % 256) - 128.0;
|
||||||
|
if (randf() < 0.3)
|
||||||
|
{
|
||||||
|
jink.z /= 2; // move the z-offset closer to the target to let him fly away from the target.
|
||||||
|
desired_speed = flightSpeed * 2; // increase speed a bit.
|
||||||
|
}
|
||||||
|
frustration /= 2.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (range > COMBAT_OUT_RANGE_FACTOR * weaponRange + 15.0 * jink.x || flightSpeed > (scannerRange - range) * max_flight_pitch / 6.28)
|
if (range > COMBAT_OUT_RANGE_FACTOR * weaponRange + 15.0 * jink.x || flightSpeed > (scannerRange - range) * max_flight_pitch / 6.28)
|
||||||
@ -4178,6 +4158,11 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
|
|||||||
flightYaw = 0.0;
|
flightYaw = 0.0;
|
||||||
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
|
[self applyRoll:delta_t*flightRoll andClimb:delta_t*flightPitch];
|
||||||
[self applyThrust:delta_t];
|
[self applyThrust:delta_t];
|
||||||
|
|
||||||
|
if (weapon_temp > COMBAT_AI_WEAPON_TEMP_USABLE)
|
||||||
|
{
|
||||||
|
behaviour = BEHAVIOUR_ATTACK_TARGET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -5553,31 +5538,28 @@ static BOOL IsBehaviourHostile(OOBehaviour behaviour)
|
|||||||
|
|
||||||
- (void) setWeaponDataFromType: (OOWeaponType) weapon_type
|
- (void) setWeaponDataFromType: (OOWeaponType) weapon_type
|
||||||
{
|
{
|
||||||
|
weaponRange = getWeaponRangeFromType(weapon_type);
|
||||||
switch (weapon_type)
|
switch (weapon_type)
|
||||||
{
|
{
|
||||||
case WEAPON_PLASMA_CANNON:
|
case WEAPON_PLASMA_CANNON:
|
||||||
weapon_damage = 6.0;
|
weapon_damage = 6.0;
|
||||||
weapon_recharge_rate = 0.25;
|
weapon_recharge_rate = 0.25;
|
||||||
weaponRange = 5000;
|
|
||||||
weapon_shot_temperature = 8.0f;
|
weapon_shot_temperature = 8.0f;
|
||||||
break;
|
break;
|
||||||
case WEAPON_PULSE_LASER:
|
case WEAPON_PULSE_LASER:
|
||||||
weapon_damage = 15.0;
|
weapon_damage = 15.0;
|
||||||
weapon_recharge_rate = 0.33;
|
weapon_recharge_rate = 0.33;
|
||||||
weaponRange = 12500;
|
|
||||||
weapon_shot_temperature = 7.0f;
|
weapon_shot_temperature = 7.0f;
|
||||||
break;
|
break;
|
||||||
case WEAPON_BEAM_LASER:
|
case WEAPON_BEAM_LASER:
|
||||||
weapon_damage = 15.0;
|
weapon_damage = 15.0;
|
||||||
weapon_recharge_rate = 0.25;
|
weapon_recharge_rate = 0.25;
|
||||||
weaponRange = 15000;
|
|
||||||
weapon_shot_temperature = 8.0f;
|
weapon_shot_temperature = 8.0f;
|
||||||
break;
|
break;
|
||||||
case WEAPON_MINING_LASER:
|
case WEAPON_MINING_LASER:
|
||||||
weapon_damage = 50.0;
|
weapon_damage = 50.0;
|
||||||
weapon_recharge_rate = 0.5;
|
weapon_recharge_rate = 0.5;
|
||||||
weapon_shot_temperature = 10.0f;
|
weapon_shot_temperature = 10.0f;
|
||||||
weaponRange = 12500;
|
|
||||||
break;
|
break;
|
||||||
case WEAPON_THARGOID_LASER: // omni directional lasers FRIGHTENING!
|
case WEAPON_THARGOID_LASER: // omni directional lasers FRIGHTENING!
|
||||||
weapon_damage = 12.5;
|
weapon_damage = 12.5;
|
||||||
@ -5587,20 +5569,17 @@ static BOOL IsBehaviourHostile(OOBehaviour behaviour)
|
|||||||
// so duplicate this range
|
// so duplicate this range
|
||||||
// weapon_recharge_rate = 0.7+(0.6*[self entityPersonality]);
|
// weapon_recharge_rate = 0.7+(0.6*[self entityPersonality]);
|
||||||
weapon_recharge_rate = 0.7+(0.04*(10-accuracy));
|
weapon_recharge_rate = 0.7+(0.04*(10-accuracy));
|
||||||
weaponRange = 17500;
|
|
||||||
weapon_shot_temperature = 8.0f;
|
weapon_shot_temperature = 8.0f;
|
||||||
break;
|
break;
|
||||||
case WEAPON_MILITARY_LASER:
|
case WEAPON_MILITARY_LASER:
|
||||||
weapon_damage = 23.0;
|
weapon_damage = 23.0;
|
||||||
weapon_recharge_rate = 0.20;
|
weapon_recharge_rate = 0.20;
|
||||||
weaponRange = 30000;
|
|
||||||
weapon_shot_temperature = 8.0f;
|
weapon_shot_temperature = 8.0f;
|
||||||
break;
|
break;
|
||||||
case WEAPON_NONE:
|
case WEAPON_NONE:
|
||||||
case WEAPON_UNDEFINED:
|
case WEAPON_UNDEFINED:
|
||||||
weapon_damage = 0.0; // indicating no weapon!
|
weapon_damage = 0.0; // indicating no weapon!
|
||||||
weapon_recharge_rate = 0.20; // maximum rate
|
weapon_recharge_rate = 0.20; // maximum rate
|
||||||
weaponRange = 32000;
|
|
||||||
weapon_shot_temperature = 0.0f;
|
weapon_shot_temperature = 0.0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -7774,10 +7753,15 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
|
|
||||||
double targetRadius = (1.5 - pitch_tolerance) * target->collision_radius;
|
double targetRadius = (1.5 - pitch_tolerance) * target->collision_radius;
|
||||||
|
|
||||||
if (accuracy > COMBAT_AI_TRACKS_CLOSER)
|
if (accuracy >= COMBAT_AI_TRACKS_CLOSER)
|
||||||
{
|
{
|
||||||
targetRadius /= 5.0;
|
targetRadius /= 5.0;
|
||||||
}
|
}
|
||||||
|
else if (retreat && accuracy < COMBAT_AI_ISNT_AWFUL)
|
||||||
|
{
|
||||||
|
targetRadius *= 1.3; // bad pilots worse with aft laser
|
||||||
|
}
|
||||||
|
|
||||||
double max_cos = sqrt(1 - targetRadius*targetRadius/range2);
|
double max_cos = sqrt(1 - targetRadius*targetRadius/range2);
|
||||||
|
|
||||||
double rate2 = 4.0 * delta_t;
|
double rate2 = 4.0 * delta_t;
|
||||||
@ -7789,7 +7773,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
double reverse = (retreat)? -1.0: 1.0;
|
double reverse = (retreat)? -1.0: 1.0;
|
||||||
|
|
||||||
double min_d = 0.004;
|
double min_d = 0.004;
|
||||||
if (accuracy > COMBAT_AI_TRACKS_CLOSER)
|
if (accuracy >= COMBAT_AI_TRACKS_CLOSER)
|
||||||
{
|
{
|
||||||
min_d = 0.002;
|
min_d = 0.002;
|
||||||
}
|
}
|
||||||
@ -7939,7 +7923,18 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
if (!vector_equal(relPos, kZeroVector)) relPos = vector_normal(relPos);
|
if (!vector_equal(relPos, kZeroVector)) relPos = vector_normal(relPos);
|
||||||
else relPos.z = 1.0;
|
else relPos.z = 1.0;
|
||||||
|
|
||||||
double targetRadius = (1.6-pitch_tolerance) * target->collision_radius;
|
// worse shots with side lasers than fore/aft, in general
|
||||||
|
double targetRadius = (1.7-pitch_tolerance) * target->collision_radius;
|
||||||
|
|
||||||
|
if (accuracy >= COMBAT_AI_TRACKS_CLOSER)
|
||||||
|
{
|
||||||
|
targetRadius /= 5.0;
|
||||||
|
}
|
||||||
|
else if (accuracy < COMBAT_AI_ISNT_AWFUL)
|
||||||
|
{
|
||||||
|
targetRadius *= 1+randf(); // probably misses with side lasers
|
||||||
|
// really shouldn't fit them to this bad a shot - CIM
|
||||||
|
}
|
||||||
|
|
||||||
double max_cos = sqrt(1 - targetRadius*targetRadius/range2);
|
double max_cos = sqrt(1 - targetRadius*targetRadius/range2);
|
||||||
|
|
||||||
@ -7954,6 +7949,10 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
double reverse = (leftside)? -1.0: 1.0;
|
double reverse = (leftside)? -1.0: 1.0;
|
||||||
|
|
||||||
double min_d = 0.004;
|
double min_d = 0.004;
|
||||||
|
if (accuracy >= COMBAT_AI_TRACKS_CLOSER)
|
||||||
|
{
|
||||||
|
min_d = 0.002;
|
||||||
|
}
|
||||||
int max_factor = 8;
|
int max_factor = 8;
|
||||||
double r_max_factor = 0.125;
|
double r_max_factor = 0.125;
|
||||||
|
|
||||||
@ -8455,6 +8454,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
return dist;
|
return dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (double) rangeToSecondaryTarget:(Entity *)target
|
- (double) rangeToSecondaryTarget:(Entity *)target
|
||||||
{
|
{
|
||||||
double dist;
|
double dist;
|
||||||
@ -8469,6 +8469,22 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (double) approachAspectToPrimaryTarget
|
||||||
|
{
|
||||||
|
Vector delta;
|
||||||
|
Entity *target = [self primaryTarget];
|
||||||
|
if (target == nil || ![target isShip]) // leave now!
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
ShipEntity *ship_target = (ShipEntity *)target;
|
||||||
|
|
||||||
|
delta = vector_subtract(position, target->position);
|
||||||
|
|
||||||
|
return dot_product(vector_normal(delta), ship_target->v_forward);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL) onTarget:(OOViewID) direction withWeapon:(OOWeaponType)weapon_type
|
- (BOOL) onTarget:(OOViewID) direction withWeapon:(OOWeaponType)weapon_type
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -8554,7 +8570,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
|
|||||||
break;
|
break;
|
||||||
// no default
|
// no default
|
||||||
}
|
}
|
||||||
if (weapon_temp / NPC_MAX_WEAPON_TEMP >= 0.85) return NO;
|
if (weapon_temp / NPC_MAX_WEAPON_TEMP >= WEAPON_COOLING_CUTOUT) return NO;
|
||||||
|
|
||||||
if ([self shotTime] < weapon_recharge_rate) return NO;
|
if ([self shotTime] < weapon_recharge_rate) return NO;
|
||||||
if (weapon_type != WEAPON_THARGOID_LASER)
|
if (weapon_type != WEAPON_THARGOID_LASER)
|
||||||
@ -11584,3 +11600,27 @@ BOOL OOUniformBindingPermitted(NSString *propertyName, id bindingTarget)
|
|||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLfloat getWeaponRangeFromType(OOWeaponType weapon_type)
|
||||||
|
{
|
||||||
|
switch (weapon_type)
|
||||||
|
{
|
||||||
|
case WEAPON_PLASMA_CANNON:
|
||||||
|
return 5000.0;
|
||||||
|
case WEAPON_PULSE_LASER:
|
||||||
|
case WEAPON_MINING_LASER:
|
||||||
|
return 12500.0;
|
||||||
|
case WEAPON_BEAM_LASER:
|
||||||
|
return 15000.0;
|
||||||
|
case WEAPON_THARGOID_LASER:
|
||||||
|
return 17500.0;
|
||||||
|
case WEAPON_MILITARY_LASER:
|
||||||
|
return 30000.0;
|
||||||
|
case WEAPON_NONE:
|
||||||
|
case WEAPON_UNDEFINED:
|
||||||
|
return 32000.0;
|
||||||
|
}
|
||||||
|
// never reached
|
||||||
|
return 32000.0;
|
||||||
|
}
|
||||||
|
@ -17,15 +17,21 @@ ENTRY(BEHAVIOUR_FLEE_TARGET, 105)
|
|||||||
ENTRY(BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX, 106)
|
ENTRY(BEHAVIOUR_ATTACK_FLY_TO_TARGET_SIX, 106)
|
||||||
ENTRY(BEHAVIOUR_ATTACK_MINING_TARGET, 107)
|
ENTRY(BEHAVIOUR_ATTACK_MINING_TARGET, 107)
|
||||||
|
|
||||||
|
// ENTRY(BEHAVIOUR_EVASIVE_ACTION, 108)
|
||||||
|
// ENTRY(BEHAVIOUR_ATTACK_BREAK_OFF_TARGET, 109)
|
||||||
|
|
||||||
// further advanced combat...
|
// further advanced combat...
|
||||||
ENTRY(BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE,112)
|
ENTRY(BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE,112)
|
||||||
|
|
||||||
|
// ENTRY(BEHAVIOUR_ATTACK_SNIPER, 113)
|
||||||
|
|
||||||
// side weapon combat...
|
// side weapon combat...
|
||||||
ENTRY(BEHAVIOUR_ATTACK_BROADSIDE,115)
|
ENTRY(BEHAVIOUR_ATTACK_BROADSIDE,115)
|
||||||
ENTRY(BEHAVIOUR_ATTACK_BROADSIDE_LEFT,116)
|
ENTRY(BEHAVIOUR_ATTACK_BROADSIDE_LEFT,116)
|
||||||
ENTRY(BEHAVIOUR_ATTACK_BROADSIDE_RIGHT,117)
|
ENTRY(BEHAVIOUR_ATTACK_BROADSIDE_RIGHT,117)
|
||||||
ENTRY(BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE,118)
|
ENTRY(BEHAVIOUR_CLOSE_TO_BROADSIDE_RANGE,118)
|
||||||
|
|
||||||
|
|
||||||
ENTRY(BEHAVIOUR_AVOID_COLLISION, 130)
|
ENTRY(BEHAVIOUR_AVOID_COLLISION, 130)
|
||||||
|
|
||||||
ENTRY(BEHAVIOUR_TRACK_AS_TURRET, 150)
|
ENTRY(BEHAVIOUR_TRACK_AS_TURRET, 150)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user