Merge pull request #112 from OoliteProject/customisable-laser-properties

Customisable laser properties
This commit is contained in:
cim 2014-10-03 21:44:51 +01:00
commit 5d07437a55
13 changed files with 416 additions and 380 deletions

View File

@ -97,6 +97,23 @@
available_to_all = true;
}
),
(
3, 0, "Remove Laser",
"EQ_WEAPON_NONE",
"Remove laser weapon from selected mounting.",
{
condition_script = "oolite-conditions.js";
available_to_all = true;
weapon_info = {
range = 32000;
energy = 0.0;
damage = 0.0;
recharge_rate = 100.0;
shot_temperature = 0.0;
threat_assessment = -1.0;
};
}
),
(
3, 4000, "Pulse Laser",
"EQ_WEAPON_PULSE_LASER",
@ -104,6 +121,15 @@
{
condition_script = "oolite-conditions.js";
available_to_all = true;
weapon_info = {
range = 12500;
energy = 0.8;
damage = 15.0;
recharge_rate = 0.5;
shot_temperature = 7.0;
color = "redColor";
threat_assessment = 0.0;
};
}
),
(
@ -113,6 +139,16 @@
{
condition_script = "oolite-conditions.js";
available_to_all = true;
weapon_info = {
range = 15000;
energy = 0.5;
damage = 6.0;
recharge_rate = 0.1;
shot_temperature = 3.2;
color = "yellowColor";
threat_assessment = 0.5;
};
}
),
(
@ -122,6 +158,16 @@
{
condition_script = "oolite-conditions.js";
available_to_all = true;
weapon_info = {
range = 12500;
energy = 1.4;
damage = 50.0;
recharge_rate = 2.5;
shot_temperature = 10.0;
color = "blueColor";
is_mining_laser = 1;
threat_assessment = -0.5;
};
}
),
(
@ -131,6 +177,15 @@
{
condition_script = "oolite-conditions.js";
available_to_all = true;
weapon_info = {
range = 30000;
energy = 1.1;
damage = 12.0;
recharge_rate = 0.1;
shot_temperature = 4.25;
color = "magentaColor";
threat_assessment = 1.0;
};
}
),
/* condition script blocks this one from appearing normally */
@ -287,6 +342,16 @@
"Captured Thargoid weapon, self-aiming.",
{
available_to_player = false;
weapon_info = {
range = 17500;
energy = 1.1;
damage = 12.5;
recharge_rate = 1.0;
shot_temperature = 8.0;
color = "greenColor";
is_turret_laser = true;
threat_assessment = 1.0;
};
}
),
(
@ -318,12 +383,12 @@
condition_script = "oolite-conditions.js";
}
),
/* next item was a test item */
(
2, 2000, "Twin Plasma Cannon",
"EQ_WEAPON_TWIN_PLASMA_CANNON",
"Basic cannon delivering charged plasma bursts at sublight speed."
),
/* next item was a test item, no longer supported */
// (
// 2, 2000, "Twin Plasma Cannon",
// "EQ_WEAPON_TWIN_PLASMA_CANNON",
// "Basic cannon delivering charged plasma bursts at sublight speed."
// ),
/* new items */
(
4, 15000, "External Heat Shielding",

View File

@ -447,7 +447,6 @@ typedef enum
GLfloat forward_shield, aft_shield;
OOTimeDelta forward_shot_time, aft_shot_time, port_shot_time, starboard_shot_time;
GLfloat weapon_energy_use, weapon_reload_time;
OOWeaponFacing chosen_weapon_facing; // for purchasing weapons

View File

@ -718,10 +718,10 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
[result oo_setBool:[self weaponsOnline] forKey:@"weapons_online"];
[result oo_setInteger:forward_weapon_type forKey:@"forward_weapon"];
[result oo_setInteger:aft_weapon_type forKey:@"aft_weapon"];
[result oo_setInteger:port_weapon_type forKey:@"port_weapon"];
[result oo_setInteger:starboard_weapon_type forKey:@"starboard_weapon"];
[result setObject:[forward_weapon_type identifier] forKey:@"forward_weapon"];
[result setObject:[aft_weapon_type identifier] forKey:@"aft_weapon"];
[result setObject:[port_weapon_type identifier] forKey:@"port_weapon"];
[result setObject:[starboard_weapon_type identifier] forKey:@"starboard_weapon"];
[result setObject:[self serializeShipSubEntities] forKey:@"subentities_status"];
if (hud != nil && [hud nonlinearScanner])
{
@ -1248,24 +1248,27 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
OOWeaponFacingSet available_facings = [shipyard_info oo_unsignedIntForKey:KEY_WEAPON_FACINGS defaultValue:[self weaponFacings]];
if (available_facings & WEAPON_FACING_FORWARD)
forward_weapon_type = [dict oo_intForKey:@"forward_weapon"];
forward_weapon_type = OOWeaponTypeFromEquipmentIdentifierLegacy([dict oo_stringForKey:@"forward_weapon"]);
else
forward_weapon_type = WEAPON_NONE;
forward_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_NONE");
if (available_facings & WEAPON_FACING_AFT)
aft_weapon_type = [dict oo_intForKey:@"aft_weapon"];
aft_weapon_type = OOWeaponTypeFromEquipmentIdentifierLegacy([dict oo_stringForKey:@"aft_weapon"]);
else
aft_weapon_type = WEAPON_NONE;
aft_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_NONE");
if (available_facings & WEAPON_FACING_PORT)
port_weapon_type = [dict oo_intForKey:@"port_weapon"];
port_weapon_type = OOWeaponTypeFromEquipmentIdentifierLegacy([dict oo_stringForKey:@"port_weapon"]);
else
port_weapon_type = WEAPON_NONE;
port_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_NONE");
if (available_facings & WEAPON_FACING_STARBOARD)
starboard_weapon_type = [dict oo_intForKey:@"starboard_weapon"];
starboard_weapon_type = OOWeaponTypeFromEquipmentIdentifierLegacy([dict oo_stringForKey:@"starboard_weapon"]);
else
starboard_weapon_type = WEAPON_NONE;
starboard_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_NONE");
[self setWeaponDataFromType:forward_weapon_type];
if (hud != nil && [hud nonlinearScanner])
{
[hud setScannerZoom: [dict oo_floatForKey:@"ship_scanner_zoom" defaultValue: 1.0]];
@ -1769,10 +1772,11 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
fuel_leak_rate = 0.0f;
galaxy_number = 0;
forward_weapon_type = WEAPON_PULSE_LASER;
aft_weapon_type = WEAPON_NONE;
port_weapon_type = WEAPON_NONE;
starboard_weapon_type = WEAPON_NONE;
// will load real weapon data later
forward_weapon_type = nil;
aft_weapon_type = nil;
port_weapon_type = nil;
starboard_weapon_type = nil;
scannerRange = (float)SCANNER_MAX_RANGE;
weapons_online = YES;
@ -5424,42 +5428,6 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
// Basic stats: weapon_damage & weaponRange (weapon_recharge_rate is not used by the player)
[self setWeaponDataFromType:currentWeapon];
// Advanced stats: all the other stats used by the player!
switch (currentWeapon)
{
case WEAPON_PLASMA_CANNON:
weapon_energy_use = 6.0f;
weapon_reload_time = 0.25f;
break;
case WEAPON_PULSE_LASER:
weapon_energy_use = 0.8f;
weapon_reload_time = 0.5f;
break;
case WEAPON_BEAM_LASER:
weapon_energy_use = 1.0f;
weapon_reload_time = 0.1f;
break;
case WEAPON_MINING_LASER:
weapon_energy_use = 1.4f;
weapon_reload_time = 2.5f;
break;
case WEAPON_THARGOID_LASER:
case WEAPON_MILITARY_LASER:
weapon_energy_use = 1.2f;
weapon_reload_time = 0.1f;
break;
case WEAPON_NONE:
case WEAPON_UNDEFINED:
weapon_energy_use = 0.0f;
weapon_reload_time = 0.1f;
break;
}
}
@ -5484,7 +5452,7 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
- (BOOL) fireMainWeapon
{
int weapon_to_be_fired = [self currentWeapon];
OOWeaponType weapon_to_be_fired = [self currentWeapon];
if (![self weaponsOnline])
{
@ -5498,7 +5466,7 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
return NO;
}
if (weapon_to_be_fired == WEAPON_NONE)
if (isWeaponNone(weapon_to_be_fired))
{
return NO;
}
@ -5511,7 +5479,7 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
return NO;
}
using_mining_laser = (weapon_to_be_fired == WEAPON_MINING_LASER);
using_mining_laser = [weapon_to_be_fired isMiningLaser];
energy -= weapon_energy_use;
@ -5542,23 +5510,17 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
}
BOOL weaponFired = NO;
switch (weapon_to_be_fired)
if (!isWeaponNone(weapon_to_be_fired))
{
case WEAPON_PLASMA_CANNON:
[self firePlasmaShotAtOffset:10.0 speed:PLAYER_PLASMA_SPEED color:[OOColor greenColor]];
weaponFired = YES;
break;
case WEAPON_PULSE_LASER:
case WEAPON_BEAM_LASER:
case WEAPON_MINING_LASER:
case WEAPON_MILITARY_LASER:
if (![weapon_to_be_fired isTurretLaser])
{
[self fireLaserShotInDirection:currentWeaponFacing];
weaponFired = YES;
break;
case WEAPON_THARGOID_LASER:
break;
}
else
{
// nothing: compatible with previous versions
}
}
if (weaponFired && cloaking_device_active && cloakPassive)
@ -5589,7 +5551,7 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
case WEAPON_FACING_NONE:
break;
}
return WEAPON_NONE;
return nil;
}
@ -7325,24 +7287,24 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
[quip2 addObject:[NSArray arrayWithObjects:desc, [NSNumber numberWithBool:YES], nil]];
}
if (forward_weapon_type > WEAPON_NONE)
if (!isWeaponNone(forward_weapon_type))
{
desc = [NSString stringWithFormat:DESC(@"equipment-fwd-weapon-@"),[[OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(forward_weapon_type)] name]];
desc = [NSString stringWithFormat:DESC(@"equipment-fwd-weapon-@"),[forward_weapon_type name]];
[quip2 addObject:[NSArray arrayWithObjects:desc, [NSNumber numberWithBool:YES], nil]];
}
if (aft_weapon_type > WEAPON_NONE)
if (!isWeaponNone(aft_weapon_type))
{
desc = [NSString stringWithFormat:DESC(@"equipment-aft-weapon-@"),[[OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(aft_weapon_type)] name]];
desc = [NSString stringWithFormat:DESC(@"equipment-aft-weapon-@"),[aft_weapon_type name]];
[quip2 addObject:[NSArray arrayWithObjects:desc, [NSNumber numberWithBool:YES], nil]];
}
if (port_weapon_type > WEAPON_NONE)
if (!isWeaponNone(port_weapon_type))
{
desc = [NSString stringWithFormat:DESC(@"equipment-port-weapon-@"),[[OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(port_weapon_type)] name]];
desc = [NSString stringWithFormat:DESC(@"equipment-port-weapon-@"),[port_weapon_type name]];
[quip2 addObject:[NSArray arrayWithObjects:desc, [NSNumber numberWithBool:YES], nil]];
}
if (starboard_weapon_type > WEAPON_NONE)
if (!isWeaponNone(starboard_weapon_type))
{
desc = [NSString stringWithFormat:DESC(@"equipment-stb-weapon-@"),[[OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(starboard_weapon_type)] name]];
desc = [NSString stringWithFormat:DESC(@"equipment-stb-weapon-@"),[starboard_weapon_type name]];
[quip2 addObject:[NSArray arrayWithObjects:desc, [NSNumber numberWithBool:YES], nil]];
}
@ -7425,7 +7387,7 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
- (OOEquipmentType *) weaponTypeForFacing:(OOWeaponFacing)facing strict:(BOOL)strict
{
OOWeaponType weaponType = WEAPON_NONE;
OOWeaponType weaponType = nil;
switch (facing)
{
@ -7449,7 +7411,7 @@ NSComparisonResult marketSorterByMassUnit(id a, id b, void *market);
break;
}
return [OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(weaponType)];
return weaponType;
}
@ -8449,25 +8411,25 @@ static NSString *last_outfitting_key=nil;
case 1:
displayRow = available_facings & WEAPON_FACING_FORWARD;
desc = FORWARD_FACING_STRING;
weaponMounted = forward_weapon_type > WEAPON_NONE;
weaponMounted = !isWeaponNone(forward_weapon_type);
break;
case 2:
displayRow = available_facings & WEAPON_FACING_AFT;
desc = AFT_FACING_STRING;
weaponMounted = aft_weapon_type > WEAPON_NONE;
weaponMounted = !isWeaponNone(aft_weapon_type);
break;
case 3:
displayRow = available_facings & WEAPON_FACING_PORT;
desc = PORT_FACING_STRING;
weaponMounted = port_weapon_type > WEAPON_NONE;
weaponMounted = !isWeaponNone(port_weapon_type);
break;
case 4:
displayRow = available_facings & WEAPON_FACING_STARBOARD;
desc = STARBOARD_FACING_STRING;
weaponMounted = starboard_weapon_type > WEAPON_NONE;
weaponMounted = !isWeaponNone(starboard_weapon_type);
break;
}
@ -9281,7 +9243,7 @@ static NSString *last_outfitting_key=nil;
}
OOWeaponType chosen_weapon = OOWeaponTypeFromEquipmentIdentifierStrict(eqKey);
OOWeaponType current_weapon = WEAPON_NONE;
OOWeaponType current_weapon = nil;
switch (chosen_weapon_facing)
{
@ -9312,7 +9274,7 @@ static NSString *last_outfitting_key=nil;
credits -= price;
// Refund current_weapon
if (current_weapon != WEAPON_NONE)
if (current_weapon != nil)
{
tradeIn = [UNIVERSE getEquipmentPriceForKey:OOEquipmentIdentifierFromWeaponType(current_weapon)];
}
@ -9477,7 +9439,7 @@ static NSString *last_outfitting_key=nil;
}
// sets WEAPON_NONE if not recognised
int chosen_weapon = OOWeaponTypeFromEquipmentIdentifierStrict(eqKey);
OOWeaponType chosen_weapon = OOWeaponTypeFromEquipmentIdentifierStrict(eqKey);
switch (facing)
{
@ -10485,8 +10447,13 @@ static NSString *last_outfitting_key=nil;
- (BOOL) hasPrimaryWeapon:(OOWeaponType)weaponType
{
if (forward_weapon_type == weaponType || aft_weapon_type == weaponType) return YES;
if (port_weapon_type == weaponType || starboard_weapon_type == weaponType) return YES;
if ([[forward_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
[[aft_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
[[port_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
[[starboard_weapon_type identifier] isEqualToString:[weaponType identifier]])
{
return YES;
}
return [super hasPrimaryWeapon:weaponType];
}

View File

@ -1868,25 +1868,26 @@ static NSMutableDictionary *currentShipyard = nil;
int base_facings = [shipDict oo_unsignedIntForKey:KEY_WEAPON_FACINGS defaultValue:15];
int available_facings = [ship_info oo_unsignedIntForKey:KEY_WEAPON_FACINGS defaultValue:base_facings];
// not retained - weapon types are references to the objects in OOEquipmentType's cache
if (available_facings & WEAPON_FACING_AFT)
aft_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy([shipDict oo_stringForKey:@"aft_weapon_type"]);
else
aft_weapon_type = WEAPON_NONE;
aft_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_NONE");
if (available_facings & WEAPON_FACING_PORT)
port_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy([shipDict oo_stringForKey:@"port_weapon_type"]);
else
port_weapon_type = WEAPON_NONE;
port_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_NONE");
if (available_facings & WEAPON_FACING_STARBOARD)
starboard_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy([shipDict oo_stringForKey:@"starboard_weapon_type"]);
else
starboard_weapon_type = WEAPON_NONE;
starboard_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_NONE");
if (available_facings & WEAPON_FACING_FORWARD)
forward_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy([shipDict oo_stringForKey:@"forward_weapon_type"]);
else
forward_weapon_type = WEAPON_NONE;
forward_weapon_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_NONE");
// new ships start with weapons online
weapons_online = 1;

View File

@ -950,7 +950,7 @@ static NSTimeInterval time_last_frame;
exceptionContext = @"shoot";
// shoot 'a'
if ((([gameView isDown:key_fire_lasers])||((mouse_control_on)&&([gameView isDown:gvMouseLeftButton]))||joyButtonState[BUTTON_FIRE])&&(shot_time > weapon_reload_time))
if ((([gameView isDown:key_fire_lasers])||((mouse_control_on)&&([gameView isDown:gvMouseLeftButton]))||joyButtonState[BUTTON_FIRE])&&(shot_time > weapon_recharge_rate))
{
if ([self fireMainWeapon])
{
@ -2105,18 +2105,18 @@ static NSTimeInterval time_last_frame;
if ([self handleGUIUpDownArrowKeys])
{
NSString *itemText = [gui selectedRowText];
OOWeaponType weaponType = WEAPON_UNDEFINED;
OOWeaponType weaponType = nil;
if ([itemText isEqual:FORWARD_FACING_STRING]) weaponType = forward_weapon_type;
if ([itemText isEqual:AFT_FACING_STRING]) weaponType = aft_weapon_type;
if ([itemText isEqual:PORT_FACING_STRING]) weaponType = port_weapon_type;
if ([itemText isEqual:STARBOARD_FACING_STRING]) weaponType = starboard_weapon_type;
if (weaponType != WEAPON_UNDEFINED)
if (weaponType != nil)
{
BOOL sameAs = OOWeaponTypeFromEquipmentIdentifierSloppy([gui selectedRowKey]) == weaponType;
// override showInformation _completely_ with itemText
if (weaponType == WEAPON_NONE) itemText = DESC(@"no-weapon-enter-to-install");
if ([[weaponType identifier] isEqualToString:@"EQ_WEAPON_NONE"]) itemText = DESC(@"no-weapon-enter-to-install");
else
{
NSString *weaponName = [[OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(weaponType)] name];

View File

@ -149,7 +149,7 @@ typedef enum OOBehaviour
#undef ENTRY
typedef enum
/*typedef enum
{
WEAPON_NONE = 0U,
WEAPON_PLASMA_CANNON = 1,
@ -159,7 +159,8 @@ typedef enum
WEAPON_MILITARY_LASER = 5,
WEAPON_THARGOID_LASER = 10,
WEAPON_UNDEFINED
} OOWeaponType;
} OOWeaponType; */
typedef OOEquipmentType* OOWeaponType;
typedef enum
@ -220,6 +221,7 @@ typedef enum
NSDictionary *dockingInstructions;
OOColor *laser_color;
OOColor *default_laser_color;
OOColor *exhaust_emissive_color;
OOColor *scanner_display_color1;
OOColor *scanner_display_color2;
@ -296,7 +298,7 @@ typedef enum
GLfloat weaponRange; // range of the weapon (in meters)
OOWeaponFacing currentWeaponFacing; // not necessarily the same as view for the player
GLfloat weapon_temp, weapon_shot_temperature; // active weapon temp, delta-temp
GLfloat weapon_energy_use, weapon_temp, weapon_shot_temperature; // active weapon temp, delta-temp
GLfloat forward_weapon_temp, aft_weapon_temp, port_weapon_temp, starboard_weapon_temp; // current weapon temperatures
GLfloat scannerRange; // typically 25600
@ -1235,23 +1237,22 @@ NSDictionary *OODefaultShipShaderMacros(void);
GLfloat getWeaponRangeFromType(OOWeaponType weapon_type);
// Stuff implemented in OOConstToString.m
enum
{
// Values used for unknown strings.
kOOWeaponTypeDefault = WEAPON_NONE
};
// Defined in OOConstToString.m
NSString *OOStringFromBehaviour(OOBehaviour behaviour) CONST_FUNC;
// Weapon strings prefixed with EQ_, used in shipyard.plist.
NSString *OOEquipmentIdentifierFromWeaponType(OOWeaponType weapon) CONST_FUNC;
OOWeaponType OOWeaponTypeFromEquipmentIdentifierSloppy(NSString *string) PURE_FUNC; // Uses suffix match for backwards compatibility.
OOWeaponType OOWeaponTypeFromEquipmentIdentifierStrict(NSString *string) PURE_FUNC;
OOWeaponType OOWeaponTypeFromEquipmentIdentifierLegacy(NSString *string);
NSString *OOStringFromWeaponType(OOWeaponType weapon) CONST_FUNC;
OOWeaponType OOWeaponTypeFromString(NSString *string) PURE_FUNC;
BOOL isWeaponNone(OOWeaponType weapon);
NSString *OODisplayStringFromAlertCondition(OOAlertCondition alertCondition);
NSString *OOStringFromShipDamageType(OOShipDamageType type) CONST_FUNC;

View File

@ -279,13 +279,13 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
weapon_facings = [shipDict oo_intForKey:@"weapon_facings" defaultValue:VALID_WEAPON_FACINGS] & VALID_WEAPON_FACINGS;
if (weapon_facings & WEAPON_FACING_FORWARD)
forward_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"forward_weapon_type" defaultValue:@"WEAPON_NONE"]);
forward_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"forward_weapon_type" defaultValue:@"EQ_WEAPON_NONE"]);
if (weapon_facings & WEAPON_FACING_AFT)
aft_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"aft_weapon_type" defaultValue:@"WEAPON_NONE"]);
aft_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"aft_weapon_type" defaultValue:@"EQ_WEAPON_NONE"]);
if (weapon_facings & WEAPON_FACING_PORT)
port_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"port_weapon_type" defaultValue:@"WEAPON_NONE"]);
port_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"port_weapon_type" defaultValue:@"EQ_WEAPON_NONE"]);
if (weapon_facings & WEAPON_FACING_STARBOARD)
starboard_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"starboard_weapon_type" defaultValue:@"WEAPON_NONE"]);
starboard_weapon_type = OOWeaponTypeFromString([shipDict oo_stringForKey:@"starboard_weapon_type" defaultValue:@"EQ_WEAPON_NONE"]);
cloaking_device_active = NO;
military_jammer_active = NO;
@ -374,18 +374,24 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
float density = [shipDict oo_floatForKey:@"density" defaultValue:1.0f];
if (octree) mass = (GLfloat)(density * 20.0 * [octree volume]);
OOColor *color = [OOColor brightColorWithDescription:[shipDict objectForKey:@"laser_color"]];
if (color == nil) color = [OOColor redColor];
[self setLaserColor:color];
DESTROY(default_laser_color);
default_laser_color = [[OOColor brightColorWithDescription:[shipDict objectForKey:@"laser_color"]] retain];
if (default_laser_color == nil)
{
[self setLaserColor:[OOColor redColor]];
}
else
{
[self setLaserColor:default_laser_color];
}
// exhaust emissive color
OORGBAComponents defaultExhaustEmissiveColorComponents; // pale blue is exhaust default color
defaultExhaustEmissiveColorComponents.r = 0.7f;
defaultExhaustEmissiveColorComponents.g = 0.9f;
defaultExhaustEmissiveColorComponents.b = 1.0f;
defaultExhaustEmissiveColorComponents.a = 0.9f;
color = [OOColor brightColorWithDescription:[shipDict objectForKey:@"exhaust_emissive_color"]];
OOColor *color = [OOColor brightColorWithDescription:[shipDict objectForKey:@"exhaust_emissive_color"]];
if (color == nil) color = [OOColor colorWithRGBAComponents:defaultExhaustEmissiveColorComponents];
[self setExhaustEmissiveColor:color];
@ -393,13 +399,13 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
[self setUpSubEntities];
// correctly initialise weaponRange, etc. (must be after subentity setup)
if (forward_weapon_type == WEAPON_NONE)
if (isWeaponNone(forward_weapon_type))
{
OOWeaponType weapon_type = WEAPON_NONE;
OOWeaponType weapon_type = nil;
BOOL hasTurrets = NO;
NSEnumerator *subEnum = [self shipSubEntityEnumerator];
ShipEntity *se = nil;
while (weapon_type == WEAPON_NONE && (se = [subEnum nextObject]))
while (isWeaponNone(weapon_type) && (se = [subEnum nextObject]))
{
weapon_type = se->forward_weapon_type;
if (se->behaviour == BEHAVIOUR_TRACK_AS_TURRET)
@ -407,11 +413,14 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
hasTurrets = YES;
}
}
if (weapon_type == WEAPON_NONE && hasTurrets)
if (isWeaponNone(weapon_type) && hasTurrets)
{ // safety for ships only equipped with turrets
weapon_type = WEAPON_PLASMA_CANNON;
weaponRange = 10000.0;
}
else
{
[self setWeaponDataFromType:weapon_type];
}
[self setWeaponDataFromType:weapon_type];
}
else
{
@ -492,11 +501,11 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
// no weapon_damage? It's a missile: set weapon_damage from shipdata!
if (weapon_damage == 0.0)
{
weapon_damage_override = weapon_damage = [shipDict oo_floatForKey:@"weapon_energy"]; // any damage value for missiles/bombs
weapon_damage_override = weapon_damage = [shipDict oo_floatForKey:@"weapon_energy" defaultValue:0]; // any damage value for missiles/bombs
}
else
{
weapon_damage_override = OOClamp_0_max_f([shipinfoDictionary oo_floatForKey:@"weapon_energy" defaultValue:weapon_damage],50.0); // front laser damage can be modified, within limits!
{
weapon_damage_override = 0;
}
scannerRange = [shipDict oo_floatForKey:@"scanner_range" defaultValue:(float)SCANNER_MAX_RANGE];
@ -999,6 +1008,7 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
DESTROY(roleSet);
DESTROY(primaryRole);
DESTROY(laser_color);
DESTROY(default_laser_color);
DESTROY(exhaust_emissive_color);
DESTROY(scanner_display_color1);
DESTROY(scanner_display_color2);
@ -2864,7 +2874,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{
// Check for primary weapon
OOWeaponType weaponType = OOWeaponTypeFromEquipmentIdentifierStrict(itemKey);
if (weaponType != WEAPON_NONE)
if (!isWeaponNone(weaponType))
{
if ([self hasPrimaryWeapon:weaponType]) return YES;
}
@ -2903,8 +2913,14 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
NSEnumerator *subEntEnum = nil;
ShipEntity *subEntity = nil;
if (forward_weapon_type == weaponType || aft_weapon_type == weaponType || port_weapon_type == weaponType || starboard_weapon_type == weaponType) return YES;
if ([[forward_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
[[aft_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
[[port_weapon_type identifier] isEqualToString:[weaponType identifier]] ||
[[starboard_weapon_type identifier] isEqualToString:[weaponType identifier]])
{
return YES;
}
for (subEntEnum = [self shipSubEntityEnumerator]; (subEntity = [subEntEnum nextObject]); )
{
if ([subEntity hasPrimaryWeapon:weaponType]) return YES;
@ -3010,7 +3026,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
- (OOWeaponType) weaponTypeIDForFacing:(OOWeaponFacing)facing strict:(BOOL)strict
{
OOWeaponType weaponType = WEAPON_NONE;
OOWeaponType weaponType = nil;
if (facing & weapon_facings)
{
@ -3019,11 +3035,11 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
case WEAPON_FACING_FORWARD:
weaponType = forward_weapon_type;
// if no forward weapon, and not carrying out a strict check, see if subentities have forward weapons, return the first one found.
if (weaponType == WEAPON_NONE && !strict)
if (isWeaponNone(weaponType) && !strict)
{
NSEnumerator *subEntEnum = [self shipSubEntityEnumerator];
ShipEntity *subEntity = nil;
while (weaponType == WEAPON_NONE && (subEntity = [subEntEnum nextObject]))
while (isWeaponNone(weaponType) && (subEntity = [subEntEnum nextObject]))
{
weaponType = subEntity->forward_weapon_type;
}
@ -3051,9 +3067,9 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
- (OOEquipmentType *) weaponTypeForFacing:(OOWeaponFacing)facing strict:(BOOL)strict
{
OOWeaponType weaponType = [self weaponTypeIDForFacing:facing strict:strict];
return [OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(weaponType)];
// OOWeaponType weaponType = [self weaponTypeIDForFacing:facing strict:strict];
// return [OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(weaponType)];
return [self weaponTypeIDForFacing:facing strict:strict];
}
@ -4244,12 +4260,12 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
GLfloat forward_weapon_real_temp = forward_weapon_temp;
// if forward weapon is actually on a subent
if (forward_weapon_real_type == WEAPON_NONE)
if (isWeaponNone(forward_weapon_real_type))
{
BOOL hasTurrets = NO;
NSEnumerator *subEnum = [self shipSubEntityEnumerator];
ShipEntity *se = nil;
while (forward_weapon_real_type == WEAPON_NONE && (se = [subEnum nextObject]))
while (isWeaponNone(forward_weapon_real_type) && (se = [subEnum nextObject]))
{
forward_weapon_real_type = se->forward_weapon_type;
forward_weapon_real_temp = se->forward_weapon_temp;
@ -4258,14 +4274,14 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
hasTurrets = YES;
}
}
if (forward_weapon_real_type == WEAPON_NONE && hasTurrets)
if (isWeaponNone(forward_weapon_real_type) && hasTurrets)
{ // safety for ships only equipped with turrets
forward_weapon_real_type = WEAPON_PLASMA_CANNON;
forward_weapon_real_type = OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_PULSE_LASER");
forward_weapon_real_temp = COMBAT_AI_WEAPON_TEMP_USABLE * 0.9;
}
}
if (forward_weapon_real_type == WEAPON_THARGOID_LASER)
if ([forward_weapon_real_type isTurretLaser])
{
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
}
@ -4273,19 +4289,19 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{
BOOL in_good_range = aim_tolerance*range < COMBAT_AI_CONFIDENCE_FACTOR;
BOOL aft_weapon_ready = (aft_weapon_type != WEAPON_NONE) && (aft_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
BOOL forward_weapon_ready = (forward_weapon_real_type != WEAPON_NONE) && (forward_weapon_real_temp < COMBAT_AI_WEAPON_TEMP_READY); // does not require in_good_range
BOOL port_weapon_ready = (port_weapon_type != WEAPON_NONE) && (port_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
BOOL starboard_weapon_ready = (starboard_weapon_type != WEAPON_NONE) && (starboard_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
BOOL aft_weapon_ready = !isWeaponNone(aft_weapon_type) && (aft_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
BOOL forward_weapon_ready = !isWeaponNone(forward_weapon_real_type) && (forward_weapon_real_temp < COMBAT_AI_WEAPON_TEMP_READY); // does not require in_good_range
BOOL port_weapon_ready = !isWeaponNone(port_weapon_type) && (port_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
BOOL starboard_weapon_ready = !isWeaponNone(starboard_weapon_type) && (starboard_weapon_temp < COMBAT_AI_WEAPON_TEMP_READY) && in_good_range;
// if no weapons cool enough to be good choices, be less picky
BOOL weapons_heating = NO;
if (!forward_weapon_ready && !aft_weapon_ready && !port_weapon_ready && !starboard_weapon_ready)
{
weapons_heating = YES;
aft_weapon_ready = (aft_weapon_type != WEAPON_NONE) && (aft_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
forward_weapon_ready = (forward_weapon_real_type != WEAPON_NONE) && (forward_weapon_real_temp < COMBAT_AI_WEAPON_TEMP_USABLE); // does not require in_good_range
port_weapon_ready = (port_weapon_type != WEAPON_NONE) && (port_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
starboard_weapon_ready = (starboard_weapon_type != WEAPON_NONE) && (starboard_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
aft_weapon_ready = !isWeaponNone(aft_weapon_type) && (aft_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
forward_weapon_ready = !isWeaponNone(forward_weapon_real_type) && (forward_weapon_real_temp < COMBAT_AI_WEAPON_TEMP_USABLE); // does not require in_good_range
port_weapon_ready = !isWeaponNone(port_weapon_type) && (port_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
starboard_weapon_ready = !isWeaponNone(starboard_weapon_type) && (starboard_weapon_temp < COMBAT_AI_WEAPON_TEMP_USABLE) && in_good_range;
}
ShipEntity* target = [self primaryTarget];
@ -4295,7 +4311,10 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{ // no usable weapons! Either not fitted or overheated
// if unarmed
if (forward_weapon_real_type == WEAPON_NONE && aft_weapon_type == WEAPON_NONE && port_weapon_type == WEAPON_NONE && starboard_weapon_type == WEAPON_NONE)
if (isWeaponNone(forward_weapon_real_type) &&
isWeaponNone(aft_weapon_type) &&
isWeaponNone(port_weapon_type) &&
isWeaponNone(starboard_weapon_type))
{
behaviour = BEHAVIOUR_ATTACK_FLY_FROM_TARGET;
}
@ -4382,7 +4401,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
jink = kZeroVector; // almost all behaviours
// TODO: good pilots use behaviour_attack_sniper sometimes
if (getWeaponRangeFromType(forward_weapon_real_type) > getWeaponRangeFromType(WEAPON_PULSE_LASER) && range > getWeaponRangeFromType(WEAPON_PULSE_LASER))
if (getWeaponRangeFromType(forward_weapon_real_type) > 12500 && range > 12500)
{
behaviour = BEHAVIOUR_ATTACK_SNIPER;
}
@ -4447,7 +4466,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{
if (port_weapon_temp < starboard_weapon_temp)
{
if (port_weapon_type == WEAPON_NONE)
if (isWeaponNone(port_weapon_type))
{
behaviour = BEHAVIOUR_ATTACK_BROADSIDE_RIGHT;
[self setWeaponDataFromType:starboard_weapon_type];
@ -4460,7 +4479,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
}
else
{
if (starboard_weapon_type != WEAPON_NONE)
if (isWeaponNone(starboard_weapon_type))
{
behaviour = BEHAVIOUR_ATTACK_BROADSIDE_RIGHT;
[self setWeaponDataFromType:starboard_weapon_type];
@ -4556,7 +4575,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
{ // will probably have more luck with the other laser or picking a different attack method
if (leftside)
{
if (starboard_weapon_type != WEAPON_NONE)
if (!isWeaponNone(starboard_weapon_type))
{
behaviour = BEHAVIOUR_ATTACK_BROADSIDE_RIGHT;
}
@ -4567,7 +4586,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
}
else
{
if (port_weapon_type != WEAPON_NONE)
if (!isWeaponNone(port_weapon_type))
{
behaviour = BEHAVIOUR_ATTACK_BROADSIDE_LEFT;
}
@ -4644,7 +4663,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
[self behaviour_fly_to_target_six:delta_t];
if (port_weapon_type != WEAPON_NONE)
if (!isWeaponNone(port_weapon_type))
{
[self setWeaponDataFromType:port_weapon_type];
}
@ -4712,7 +4731,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self noteLostTargetAndGoIdle];
return;
}
else if (range < getWeaponRangeFromType(WEAPON_PULSE_LASER))
else if (range < 15000)
{
behaviour = BEHAVIOUR_ATTACK_TARGET;
}
@ -4848,9 +4867,10 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
// target-twelve
if (behaviour == BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE)
{
if (forward_weapon_type == WEAPON_THARGOID_LASER)
if ([forward_weapon_type isTurretLaser])
{
// head for a point near the target, avoiding common Galcop weapon mount locations
// head for a point near the target, avoiding common Galcop weapon mount locations
// TODO: this should account for weapon ranges
GLfloat offset = 1000.0;
GLfloat spacing = 2000.0;
if (accuracy > 0.0)
@ -4878,7 +4898,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
else if(frustration > 0.0) frustration -= delta_t * 0.75;
double aspect = [self approachAspectToPrimaryTarget];
if(forward_weapon_type != WEAPON_THARGOID_LASER && (frustration > 10 || aspect > 0.75))
if(![forward_weapon_type isTurretLaser] && (frustration > 10 || aspect > 0.75))
{
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET;
}
@ -5061,7 +5081,10 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
// don't do this if the target is fleeing and the front laser is
// the only weapon, or if we're too far away to use non-front
// lasers effectively
if (aspect < 0 || aft_weapon_type != WEAPON_NONE || port_weapon_type != WEAPON_NONE || starboard_weapon_type != WEAPON_NONE)
if (aspect < 0 ||
!isWeaponNone(aft_weapon_type) ||
!isWeaponNone(port_weapon_type) ||
!isWeaponNone(starboard_weapon_type))
{
frustration = 0.0;
behaviour = BEHAVIOUR_ATTACK_TARGET;
@ -5073,7 +5096,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
// need to dodge sooner if in aft sights
if ([target behaviour] != BEHAVIOUR_FLEE_TARGET && [target behaviour] != BEHAVIOUR_FLEE_EVASIVE_ACTION)
{
if ((aspect > 0.99999 && [target weaponTypeForFacing:WEAPON_FACING_FORWARD strict:NO] != WEAPON_NONE) || (aspect < -0.999 && [target weaponTypeForFacing:WEAPON_FACING_AFT strict:NO] != WEAPON_NONE))
if ((aspect > 0.99999 && !isWeaponNone([target weaponTypeForFacing:WEAPON_FACING_FORWARD strict:NO])) || (aspect < -0.999 && !isWeaponNone([target weaponTypeForFacing:WEAPON_FACING_AFT strict:NO])))
{
frustration = 0.0;
behaviour = BEHAVIOUR_EVASIVE_ACTION;
@ -5180,14 +5203,14 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
if (range > weaponRange || range > 0.8 * scannerRange || range == 0)
{
behaviour = BEHAVIOUR_CLOSE_WITH_TARGET;
if (forward_weapon_type == WEAPON_THARGOID_LASER)
if ([forward_weapon_type isTurretLaser])
{
behaviour = BEHAVIOUR_ATTACK_FLY_TO_TARGET_TWELVE;
}
frustration = 0.0;
}
[self trackPrimaryTarget:delta_t:YES];
if (forward_weapon_type == WEAPON_THARGOID_LASER)
if ([forward_weapon_type isTurretLaser])
{
// most Thargoids will only have the forward weapon
[self fireMainWeapon:range];
@ -5268,7 +5291,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
}
// thargoids won't normally be fleeing, but if they do, they can still shoot
if (forward_weapon_type == WEAPON_THARGOID_LASER)
if ([forward_weapon_type isTurretLaser])
{
[self fireMainWeapon:range];
}
@ -6943,65 +6966,20 @@ static BOOL IsBehaviourHostile(OOBehaviour behaviour)
- (void) setWeaponDataFromType: (OOWeaponType) weapon_type
{
weaponRange = getWeaponRangeFromType(weapon_type);
switch (weapon_type)
weapon_energy_use = [weapon_type weaponEnergyUse];
weapon_recharge_rate = [weapon_type weaponRechargeRate];
weapon_shot_temperature = [weapon_type weaponShotTemperature];
weapon_damage = [weapon_type weaponDamage];
if (default_laser_color == nil)
{
case WEAPON_PLASMA_CANNON:
weapon_damage = 6.0;
weapon_recharge_rate = 0.25;
weapon_shot_temperature = 8.0f;
break;
case WEAPON_PULSE_LASER:
#ifdef DEBUG_LASER_TYPES
[self setLaserColor:[OOColor redColor]];
#endif
weapon_damage = 15.0;
// weapon_recharge_rate = 0.33;
weapon_recharge_rate = 0.5;
weapon_shot_temperature = 7.0f;
break;
case WEAPON_BEAM_LASER:
#ifdef DEBUG_LASER_TYPES
[self setLaserColor:[OOColor yellowColor]];
#endif
weapon_damage = 15.0;
// weapon_recharge_rate = 0.25;
weapon_recharge_rate = 0.1;
weapon_shot_temperature = 8.0f;
break;
case WEAPON_MINING_LASER:
#ifdef DEBUG_LASER_TYPES
[self setLaserColor:[OOColor blueColor]];
#endif
weapon_damage = 50.0;
weapon_recharge_rate = 2.5;
weapon_shot_temperature = 10.0f;
break;
case WEAPON_THARGOID_LASER: // omni directional lasers FRIGHTENING!
weapon_damage = 12.5;
// changing weapon_recharge_rate to accompany change to onTarget - CIM 20120502
// weapon_recharge_rate = 0.5;
// old behaviour gave range of 0.7-1.3 between 25 and 100 FPS
// so duplicate this range
// weapon_recharge_rate = 0.7+(0.6*[self entityPersonality]);
weapon_recharge_rate = 0.7+(0.04*(10-accuracy));
weapon_shot_temperature = 8.0f;
break;
case WEAPON_MILITARY_LASER:
#ifdef DEBUG_LASER_TYPES
[self setLaserColor:[OOColor magentaColor]];
#endif
weapon_damage = 23.0;
// weapon_recharge_rate = 0.20;
weapon_recharge_rate = 0.10;
weapon_shot_temperature = 8.0f;
break;
case WEAPON_NONE:
case WEAPON_UNDEFINED:
weapon_damage = 0.0; // indicating no weapon!
weapon_recharge_rate = 0.20; // maximum rate
weapon_shot_temperature = 0.0f;
break;
OOColor *wcol = [weapon_type weaponColor];
if (wcol != nil)
{
[self setLaserColor:wcol];
}
}
}
@ -9101,14 +9079,14 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
- (GLfloat)laserHeatLevelForward
{
GLfloat result = forward_weapon_temp / NPC_MAX_WEAPON_TEMP;
if (forward_weapon_type == WEAPON_NONE)
if (isWeaponNone(forward_weapon_type))
{ // must check subents
OOWeaponType forward_weapon_real_type = WEAPON_NONE;
OOWeaponType forward_weapon_real_type = nil;
NSEnumerator *subEnum = [self shipSubEntityEnumerator];
ShipEntity *se = nil;
while (forward_weapon_real_type == WEAPON_NONE && (se = [subEnum nextObject]))
while (isWeaponNone(forward_weapon_real_type) && (se = [subEnum nextObject]))
{
if (se->forward_weapon_type != WEAPON_NONE)
if (!isWeaponNone(se->forward_weapon_type))
{
forward_weapon_real_type = se->forward_weapon_type;
result = se->forward_weapon_temp / NPC_MAX_WEAPON_TEMP;
@ -10661,11 +10639,8 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
GLfloat dq = -1.0f;
GLfloat d2, radius, astq;
Vector rel_pos, urp;
if (weapon_type == WEAPON_THARGOID_LASER)
if ([weapon_type isTurretLaser])
{
/* this gives a frame rate dependency. Modified weapon_recharge_time
* elsewhere to give a similar effect - CIM 20120502 */
// if (randf() < 0.05) return YES; // one in twenty shots on target
return YES;
}
@ -10744,8 +10719,9 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
}
if (weapon_temp / NPC_MAX_WEAPON_TEMP >= WEAPON_COOLING_CUTOUT) return NO;
if (energy <= weapon_energy_use) return NO;
if ([self shotTime] < weapon_recharge_rate) return NO;
if (weapon_type != WEAPON_THARGOID_LASER)
if (![weapon_type isTurretLaser])
{ // thargoid laser may just pick secondary target in this case
if (range > randf() * weaponRange * (accuracy+7.5)) return NO;
if (range > weaponRange) return NO;
@ -10753,34 +10729,23 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
if (![self onTarget:direction withWeapon:weapon_type]) return NO;
BOOL fired = NO;
switch (weapon_type)
if (!isWeaponNone(weapon_type))
{
case WEAPON_PLASMA_CANNON:
[self firePlasmaShotAtOffset:0.0 speed:NPC_PLASMA_SPEED color:[OOColor yellowColor] direction:direction];
fired = YES;
break;
case WEAPON_PULSE_LASER:
case WEAPON_BEAM_LASER:
case WEAPON_MINING_LASER:
case WEAPON_MILITARY_LASER:
[self fireLaserShotInDirection:direction];
fired = YES;
break;
case WEAPON_THARGOID_LASER:
if ([weapon_type isTurretLaser])
{
[self fireDirectLaserShot:range];
fired = YES;
break;
case WEAPON_NONE:
case WEAPON_UNDEFINED:
// Do nothing
break;
}
else
{
[self fireLaserShotInDirection:direction];
fired = YES;
}
}
if (fired)
{
energy -= weapon_energy_use;
switch (direction)
{
case WEAPON_FACING_FORWARD:
@ -10831,18 +10796,19 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
currentWeaponFacing = WEAPON_FACING_FORWARD;
[self setWeaponDataFromType:forward_weapon_type];
weapon_damage = weapon_damage_override;
// weapon damage override no longer effective
// weapon_damage = weapon_damage_override;
BOOL result = [self fireWeapon:forward_weapon_type direction:WEAPON_FACING_FORWARD range:range];
if (forward_weapon_type == WEAPON_NONE)
if (isWeaponNone(forward_weapon_type))
{
// need to check subentities to avoid AI oddities
// will already have fired them by now, though
NSEnumerator *subEnum = [self shipSubEntityEnumerator];
ShipEntity *se = nil;
OOWeaponType weapon_type = WEAPON_NONE;
OOWeaponType weapon_type = nil;
BOOL hasTurrets = NO;
while (weapon_type == WEAPON_NONE && (se = [subEnum nextObject]))
while (isWeaponNone(weapon_type) && (se = [subEnum nextObject]))
{
weapon_type = se->forward_weapon_type;
weapon_temp = se->forward_weapon_temp;
@ -10851,9 +10817,9 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
hasTurrets = YES;
}
}
if (weapon_type == WEAPON_NONE && hasTurrets)
if (isWeaponNone(weapon_type) && hasTurrets)
{ // no forward weapon but has turrets, so set up range calculations accordingly
[self setWeaponDataFromType:WEAPON_PLASMA_CANNON];
weaponRange = 10000.0;
}
else
{
@ -10988,18 +10954,21 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
{
[self setShipHitByLaser:nil];
if (forward_weapon_type == WEAPON_NONE) return NO;
if (isWeaponNone(forward_weapon_type)) return NO;
[self setWeaponDataFromType:forward_weapon_type];
ShipEntity *parent = [self owner];
NSAssert([parent isShipWithSubEntityShip:self], @"-fireSubentityLaserShot: called on ship which is not a subentity.");
// subentity lasers still draw power from the main entity
if ([parent energy] <= weapon_energy_use) return NO;
if ([self shotTime] < weapon_recharge_rate) return NO;
if (forward_weapon_temp > WEAPON_COOLING_CUTOUT * NPC_MAX_WEAPON_TEMP) return NO;
if (range > weaponRange) return NO;
forward_weapon_temp += weapon_shot_temperature;
[parent setEnergy:([parent energy] - weapon_energy_use)];
GLfloat hitAtRange = weaponRange;
OOWeaponFacing direction = WEAPON_FACING_FORWARD;
ShipEntity *victim = [UNIVERSE firstShipHitByLaserFromShip:self inDirection:direction offset:kZeroVector gettingRangeFound:&hitAtRange];
@ -11165,12 +11134,6 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
[self resetShotTime];
// random laser over-heating for AI ships
/* if ((!isPlayer)&&((ranrot_rand() & 255) < weapon_damage)&&(![self isMining]))
{
shot_time -= (randf() * weapon_damage);
} */
return YES;
}
@ -13521,7 +13484,7 @@ static BOOL AuthorityPredicate(Entity *entity, void *parameter)
- (BOOL) isMining
{
return ((behaviour == BEHAVIOUR_ATTACK_MINING_TARGET)&&(forward_weapon_type == WEAPON_MINING_LASER));
return ((behaviour == BEHAVIOUR_ATTACK_MINING_TARGET)&&([forward_weapon_type isMiningLaser]));
}
@ -14152,24 +14115,11 @@ BOOL OOUniformBindingPermitted(NSString *propertyName, id bindingTarget)
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;
return [weapon_type weaponRange];
}
BOOL isWeaponNone(OOWeaponType weapon)
{
return weapon == nil || [[weapon identifier] isEqualToString:@"EQ_WEAPON_NONE"];
}

View File

@ -254,6 +254,8 @@ OOINLINE void GLColorWithOverallAlpha(const GLfloat *color, GLfloat alpha)
_compassActive = isCompassToBeDrawn;
_lastWeaponType = nil;
NSArray *legends = [hudinfo oo_arrayForKey:LEGENDS_KEY];
for (i = 0; i < [legends count]; i++)
{
@ -886,6 +888,7 @@ OOINLINE void GLColorWithOverallAlpha(const GLfloat *color, GLfloat alpha)
- (NSArray *) crosshairDefinitionForWeaponType:(OOWeaponType)weapon
{
NSString *weaponName = nil;
NSString *weaponName2 = nil;
static NSDictionary *crosshairDefs = nil;
NSArray *result = nil;
@ -897,7 +900,12 @@ OOINLINE void GLColorWithOverallAlpha(const GLfloat *color, GLfloat alpha)
*/
weaponName = OOStringFromWeaponType(weapon);
weaponName2 = [weaponName substringFromIndex:3]; // strip "EQ_"
result = [_crosshairOverrides oo_arrayForKey:weaponName];
if (result == nil)
{
result = [_crosshairOverrides oo_arrayForKey:weaponName2];
}
if (result == nil) result = [_crosshairOverrides oo_arrayForKey:@"OTHER"];
if (result == nil)
{
@ -910,6 +918,10 @@ OOINLINE void GLColorWithOverallAlpha(const GLfloat *color, GLfloat alpha)
}
result = [crosshairDefs oo_arrayForKey:weaponName];
if (result == nil)
{
result = [crosshairDefs oo_arrayForKey:weaponName2];
}
if (result == nil) result = [crosshairDefs oo_arrayForKey:@"OTHER"];
}

View File

@ -28,7 +28,7 @@ MA );-);, USA.
#import "Universe.h"
#import "PlayerEntity.h"
#import "OOEquipmentType.h"
#define CASE(foo) case foo: return @#foo;
#define REVERSE_CASE(foo) if ([string isEqualToString:@#foo]) return foo;
@ -247,85 +247,71 @@ NSString *JSTypeToString(int /* JSType */ type)
NSString *OOStringFromWeaponType(OOWeaponType weapon)
{
switch (weapon)
{
CASE(WEAPON_NONE);
CASE(WEAPON_PLASMA_CANNON);
CASE(WEAPON_PULSE_LASER);
CASE(WEAPON_BEAM_LASER);
CASE(WEAPON_MINING_LASER);
CASE(WEAPON_MILITARY_LASER);
CASE(WEAPON_THARGOID_LASER);
CASE(WEAPON_UNDEFINED);
}
return @"Unknown weapon";
return [weapon identifier];
}
OOWeaponType OOWeaponTypeFromString(NSString *string)
{
REVERSE_CASE(WEAPON_PLASMA_CANNON);
REVERSE_CASE(WEAPON_PULSE_LASER);
REVERSE_CASE(WEAPON_BEAM_LASER);
REVERSE_CASE(WEAPON_MINING_LASER);
REVERSE_CASE(WEAPON_MILITARY_LASER);
REVERSE_CASE(WEAPON_THARGOID_LASER);
return kOOWeaponTypeDefault;
return OOWeaponTypeFromEquipmentIdentifierSloppy(string);
}
NSString *OOEquipmentIdentifierFromWeaponType(OOWeaponType weapon)
{
#define EQ_CASE(foo) case foo: return @"EQ_"#foo;
switch (weapon)
{
// EQ_CASE(WEAPON_PLASMA_CANNON);
case WEAPON_PLASMA_CANNON: return @"EQ_WEAPON_TWIN_PLASMA_CANNON";
EQ_CASE(WEAPON_PULSE_LASER);
EQ_CASE(WEAPON_BEAM_LASER);
EQ_CASE(WEAPON_MINING_LASER);
EQ_CASE(WEAPON_MILITARY_LASER);
EQ_CASE(WEAPON_THARGOID_LASER);
case WEAPON_NONE:
case WEAPON_UNDEFINED:
break;
}
return nil;
#undef EQ_CASE
return [weapon identifier];
}
OOWeaponType OOWeaponTypeFromEquipmentIdentifierSloppy(NSString *string)
{
#define EQ_REVERSE_CASE(foo) if ([string hasSuffix:@#foo]) return WEAPON_##foo;
EQ_REVERSE_CASE(PLASMA_CANNON); // required in playerEntityControls (case GUI_SCREEN_EQUIP_SHIP)
EQ_REVERSE_CASE(PULSE_LASER);
EQ_REVERSE_CASE(BEAM_LASER);
EQ_REVERSE_CASE(MINING_LASER);
EQ_REVERSE_CASE(MILITARY_LASER);
EQ_REVERSE_CASE(THARGOID_LASER);
return kOOWeaponTypeDefault;
#undef EQ_REVERSE_CASE
OOWeaponType w = [OOEquipmentType equipmentTypeWithIdentifier:string];
if (w == nil)
{
if (![string hasPrefix:@"EQ_"])
{
w = [OOEquipmentType equipmentTypeWithIdentifier:[NSString stringWithFormat:@"EQ_%@",string]];
if (w != nil)
{
return w;
}
}
return [OOEquipmentType equipmentTypeWithIdentifier:@"EQ_WEAPON_NONE"];
}
return w;
}
/* Previous save games will have weapon types stored as ints to the
* various weapon types */
OOWeaponType OOWeaponTypeFromEquipmentIdentifierLegacy(NSString *string)
{
if ([string intValue] > 0)
{
switch ([string intValue])
{
case 2:
return OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_PULSE_LASER");
case 3:
return OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_BEAM_LASER");
case 4:
return OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_MINING_LASER");
case 5:
return OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_MILITARY_LASER");
case 10:
return OOWeaponTypeFromEquipmentIdentifierSloppy(@"EQ_WEAPON_THARGOID_LASER");
default:
return OOWeaponTypeFromEquipmentIdentifierSloppy(string);
}
}
return OOWeaponTypeFromEquipmentIdentifierSloppy(string);
}
OOWeaponType OOWeaponTypeFromEquipmentIdentifierStrict(NSString *string)
{
#define EQ_REVERSE_CASE(foo) if ([string isEqualToString:@"EQ_WEAPON_" #foo]) return WEAPON_##foo;
// EQ_REVERSE_CASE(PLASMA_CANNON);
if ([string isEqual:@"EQ_WEAPON_TWIN_PLASMA_CANNON"]) return WEAPON_PLASMA_CANNON;
EQ_REVERSE_CASE(PULSE_LASER);
EQ_REVERSE_CASE(BEAM_LASER);
EQ_REVERSE_CASE(MINING_LASER);
EQ_REVERSE_CASE(MILITARY_LASER);
EQ_REVERSE_CASE(THARGOID_LASER);
return kOOWeaponTypeDefault;
#undef EQ_REVERSE_CASE
// there is no difference between the two any more
return OOWeaponTypeFromEquipmentIdentifierSloppy(string);
}

View File

@ -66,6 +66,7 @@ SOFTWARE.
NSSet *_incompatibleEquipment;
NSArray *_conditions;
NSDictionary *_scriptInfo;
NSDictionary *_weaponInfo;
NSString *_script;
NSString *_condition_script;
@ -130,6 +131,16 @@ SOFTWARE.
- (NSUInteger) installTime;
- (NSUInteger) repairTime;
- (BOOL) isTurretLaser;
- (BOOL) isMiningLaser;
- (GLfloat) weaponRange;
- (GLfloat) weaponEnergyUse;
- (GLfloat) weaponDamage;
- (GLfloat) weaponRechargeRate;
- (GLfloat) weaponShotTemperature;
- (GLfloat) weaponThreatAssessment;
- (OOColor *) weaponColor;
@end

View File

@ -231,6 +231,8 @@ static NSDictionary *sMissilesRegistry = nil;
_installTime = [extra oo_unsignedIntForKey:@"installation_time" defaultValue:0];
_repairTime = [extra oo_unsignedIntForKey:@"repair_time" defaultValue:0];
_weaponInfo = [[extra oo_dictionaryForKey:@"weapon_info" defaultValue:[NSDictionary dictionary]] retain];
_damageProbability = [extra oo_floatForKey:@"damage_probability" defaultValue:(_isMissileOrMine?0.0:1.0)];
id object = [extra objectForKey:@"requires_equipment"];
@ -325,6 +327,7 @@ static NSDictionary *sMissilesRegistry = nil;
DESTROY(_incompatibleEquipment);
DESTROY(_conditions);
DESTROY(_condition_script);
DESTROY(_weaponInfo);
DESTROY(_scriptInfo);
DESTROY(_script);
@ -582,6 +585,60 @@ static NSDictionary *sMissilesRegistry = nil;
}
- (BOOL) isTurretLaser
{
return [_weaponInfo oo_boolForKey:@"is_turret_laser" defaultValue:NO];
}
- (BOOL) isMiningLaser
{
return [_weaponInfo oo_boolForKey:@"is_mining_laser" defaultValue:NO];
}
- (GLfloat) weaponRange
{
return [_weaponInfo oo_floatForKey:@"range" defaultValue:12500.0];
}
- (GLfloat) weaponEnergyUse
{
return [_weaponInfo oo_floatForKey:@"energy" defaultValue:0.8];
}
- (GLfloat) weaponDamage
{
return [_weaponInfo oo_floatForKey:@"damage" defaultValue:15.0];
}
- (GLfloat) weaponRechargeRate
{
return [_weaponInfo oo_floatForKey:@"recharge_rate" defaultValue:0.5];
}
- (GLfloat) weaponShotTemperature
{
return [_weaponInfo oo_floatForKey:@"shot_temperature" defaultValue:7.0];
}
- (GLfloat) weaponThreatAssessment
{
return [_weaponInfo oo_floatForKey:@"threat_assessment" defaultValue:1.0];
}
- (OOColor *) weaponColor
{
return [OOColor brightColorWithDescription:[_weaponInfo objectForKey:@"color"]];
}
/* This method exists purely to suppress Clang static analyzer warnings that
this ivar is unused (but may be used by categories, which it is).
FIXME: there must be a feature macro we can use to avoid actually building

View File

@ -3806,27 +3806,25 @@ static JSBool ShipThreatAssessment(JSContext *context, uintN argc, jsval *vp)
// check lasers
OOWeaponType wt = [thisEnt weaponTypeIDForFacing:WEAPON_FACING_FORWARD strict:NO];
if (wt == WEAPON_NONE)
assessment += ShipThreatAssessmentWeapon(wt);
if (isWeaponNone(wt))
{
assessment -= 2.5; // cancel base ship danger
}
else
{
assessment += ShipThreatAssessmentWeapon(wt);
assessment -= 1.5; // further penalty for ships with no forward laser
}
wt = [thisEnt weaponTypeIDForFacing:WEAPON_FACING_AFT strict:NO];
if (wt != WEAPON_NONE)
if (!isWeaponNone(wt))
{
assessment += 1 + ShipThreatAssessmentWeapon(wt);
}
// port and starboard weapons less important
wt = [thisEnt weaponTypeIDForFacing:WEAPON_FACING_PORT strict:NO];
if (wt != WEAPON_NONE)
if (!isWeaponNone(wt))
{
assessment += 0.2 + ShipThreatAssessmentWeapon(wt)/5.0;
}
wt = [thisEnt weaponTypeIDForFacing:WEAPON_FACING_STARBOARD strict:NO];
if (wt != WEAPON_NONE)
if (!isWeaponNone(wt))
{
assessment += 0.2 + ShipThreatAssessmentWeapon(wt)/5.0;
}
@ -3891,22 +3889,11 @@ static JSBool ShipThreatAssessment(JSContext *context, uintN argc, jsval *vp)
static double ShipThreatAssessmentWeapon(OOWeaponType wt)
{
switch (wt)
if (wt == nil)
{
case WEAPON_NONE:
return -1;
case WEAPON_PULSE_LASER:
return 0;
case WEAPON_BEAM_LASER:
return 0.5;
case WEAPON_MINING_LASER:
return -0.5;
case WEAPON_MILITARY_LASER:
case WEAPON_THARGOID_LASER:
return 1.0;
default:
return 0;
return -1.0;
}
return [wt weaponThreatAssessment];
}

View File

@ -9107,10 +9107,10 @@ static OOComparisonResult comparePrice(id dict1, id dict2, void *context)
OOCreditsQuantity scrap_value = 351; // translates to 250 cr.
OOWeaponType ship_fwd_weapon = [dict oo_unsignedIntForKey:@"forward_weapon"];
OOWeaponType ship_aft_weapon = [dict oo_unsignedIntForKey:@"aft_weapon"];
OOWeaponType ship_port_weapon = [dict oo_unsignedIntForKey:@"port_weapon"];
OOWeaponType ship_starboard_weapon = [dict oo_unsignedIntForKey:@"starboard_weapon"];
OOWeaponType ship_fwd_weapon = [OOEquipmentType equipmentTypeWithIdentifier:[dict oo_stringForKey:@"forward_weapon"]];
OOWeaponType ship_aft_weapon = [OOEquipmentType equipmentTypeWithIdentifier:[dict oo_stringForKey:@"aft_weapon"]];
OOWeaponType ship_port_weapon = [OOEquipmentType equipmentTypeWithIdentifier:[dict oo_stringForKey:@"port_weapon"]];
OOWeaponType ship_starboard_weapon = [OOEquipmentType equipmentTypeWithIdentifier:[dict oo_stringForKey:@"starboard_weapon"]];
unsigned ship_missiles = [dict oo_unsignedIntForKey:@"missiles"];
unsigned ship_max_passengers = [dict oo_unsignedIntForKey:@"max_passengers"];
NSMutableArray *ship_extra_equipment = [NSMutableArray arrayWithArray:[[dict oo_dictionaryForKey:@"extra_equipment"] allKeys]];