More work on explosions and wreckage

shipdata.plist gets show_damage property to control if sparks, etc. are shown
default to no if energy recharge is zero, yes otherwise, to mimic existing
behaviour.
Set hermit explicitly.
This commit is contained in:
cim 2015-04-03 14:42:47 +01:00
parent 9a42498ab2
commit d483a2a18b
7 changed files with 237 additions and 52 deletions

View File

@ -1,4 +1,5 @@
{
// main ship explosion
"oolite-default-ship-explosion" = {
"alpha" = 0.85;
"color_order" = "rgb";
@ -9,13 +10,24 @@
"texture" = "oolite-particle-cloud2.png";
};
// slower clouds from fragment explosions
"oolite-wreckage-explosion" = {
"alpha" = 0.85;
"color_order" = "rgb";
"count" = 10;
"duration" = 4.5;
"growth_rate" = 0.6;
"size" = 2.5;
"texture" = "oolite-particle-cloud2.png";
};
"oolite-fragment-explosion" = {
"alpha" = 0.25;
"color_order" = "rgb";
"count" = 5;
"duration" = 1.2;
"growth_rate" = 14;
"duration" = 1.85;
"growth_rate" = 7;
"spread" = 0.3;
"size" = 1.0;
"texture" = "oolite-particle-fragments.png";
};
@ -24,13 +36,68 @@
"alpha" = 0.25;
"color_order" = "rgb";
"count" = 5;
"duration" = 1.2;
"growth_rate" = 14;
"duration" = 1.75;
"growth_rate" = 5;
"size" = 1.0;
"texture" = "oolite-particle-fragments2.png";
};
// spark effects as ships badly hit
"oolite-wreckage-chunk" = {
"alpha" = 0.85;
"color_order" = "rgb";
"count" = 10;
"duration" = 1.2;
"growth_rate" = 2.6;
"size" = 2.5;
"texture" = "oolite-particle-cloud2.png";
};
"oolite-wreckage-chunk-fragment" = {
"alpha" = 0.25;
"color_order" = "rgb";
"count" = 5;
"duration" = 0.3;
"growth_rate" = 18;
"spread" = 0.3;
"size" = 1.0;
"texture" = "oolite-particle-fragments.png";
};
"oolite-wreckage-chunk-fragment-b" = {
"alpha" = 0.25;
"color_order" = "rgb";
"count" = 5;
"duration" = 0.4;
"growth_rate" = 12;
"size" = 1.0;
"texture" = "oolite-particle-fragments2.png";
};
"oolite-hull-spark" = {
"alpha" = 0.65;
"color_order" = "bgr";
"count" = 5;
"duration" = 0.22;
"growth_rate" = 3;
"spread" = 0.5;
"size" = 0.12;
"texture" = "oolite-particle-fragments.png";
};
"oolite-hull-spark-b" = {
"alpha" = 0.85;
"color_order" = "white";
"count" = 5;
"duration" = 0.25;
"growth_rate" = 3;
"spread" = 0.5;
"size" = 0.15;
"texture" = "oolite-particle-fragments2.png";
};
// explosion for rocky bodies
"oolite-default-asteroid-explosion" = {
"alpha" = 0.85;
"color_order" = "white";

View File

@ -3108,6 +3108,7 @@
rotating = yes;
requires_docking_clearance = no;
scan_class = "CLASS_ROCK";
show_damage = no;
smooth = yes;
station_roll = "0.06"; // 0.5G at rim
subentities =
@ -3957,13 +3958,13 @@
ai_type = "nullAI.plist";
cargo_type = "CARGO_NOT_CARGO";
energy_recharge_rate = 0;
explosion_type = ("oolite-default-ship-explosion","oolite-fragment-explosion"); // no flash
explosion_type = ("oolite-wreckage-explosion","oolite-fragment-explosion"); // no flash
forward_weapon_type = "WEAPON_NONE";
fragment_chance = 0.0;
is_template = 1;
max_energy = 2000;
max_flight_pitch = 2;
max_flight_roll = 2;
max_energy = 20000;
max_flight_pitch = 0.2;
max_flight_roll = 0.2;
max_flight_speed = 500;
model = "wreck1.dat";
name = "Wreckage";
@ -3973,6 +3974,13 @@
counts_as_kill = false;
};
"oolite_template_wreckage-chunk" =
{
like_ship = "oolite_template_wreckage-component";
explosion_type = ("oolite-wreckage-chunk-explosion");
roles = "oolite-wreckage-chunk";
};
/* Begin entity definitions. Graphics-modifying OXPs should
* generally extend or copy these entries. OXPs should like_ship
* these entries if they want their variant to look like
@ -4282,13 +4290,13 @@
"more-wreckage2" =
{
like_ship = "oolite_template_wreckage-component";
explosion_type = ("oolite-default-ship-explosion","oolite-fragment-explosion-b");
explosion_type = ("oolite-wreckage-explosion","oolite-fragment-explosion-b");
model = "wreck2.dat";
};
"more-wreckage3" =
{
like_ship = "oolite_template_wreckage-component";
explosion_type = ("oolite-default-ship-explosion");
explosion_type = ("oolite-wreckage-explosion");
model = "wreck3.dat";
};
"more-wreckage4" =
@ -4303,6 +4311,21 @@
explosion_type = ("oolite-fragment-explosion-b");
model = "wreck5.dat";
};
"wreckage-chunk" =
{
like_ship = "oolite_template_wreckage-chunk";
};
"wreckage-chunk2" =
{
like_ship = "oolite_template_wreckage-chunk";
explosion_type = ("oolite-wreckage-chunk-fragment");
};
"wreckage-chunk3" =
{
like_ship = "oolite_template_wreckage-chunk";
explosion_type = ("oolite-wreckage-chunk-fragment-b");
};
/* Begin definitions for entities used in the tutorial */

View File

@ -43,6 +43,7 @@ static NSString * const kExplosionCount = @"count";
static NSString * const kExplosionDuration = @"duration";
static NSString * const kExplosionGrowth = @"growth_rate";
static NSString * const kExplosionSize = @"size";
static NSString * const kExplosionSpread = @"spread";
static NSString * const kExplosionTexture = @"texture";
@ -78,6 +79,8 @@ static NSString * const kExplosionTexture = @"texture";
_alpha = [_settings oo_floatForKey:kExplosionAlpha defaultValue:kExplosionCloudAlpha];
_cloudDuration = [_settings oo_floatForKey:kExplosionDuration defaultValue:kExplosionCloudDuration];
GLfloat spread = [_settings oo_floatForKey:kExplosionSpread defaultValue:1.0];
NSString *textureFile = [_settings oo_stringForKey:kExplosionTexture defaultValue:@"oolite-particle-cloud2.png"];
_texture = [[OOTexture textureWithName:textureFile
@ -99,7 +102,7 @@ static NSString * const kExplosionTexture = @"texture";
vel = vector_multiply_scalar(vector_normal(vel),1000);
}
if ((self = [super initWithPosition:pos velocity:vel count:count minSpeed:size*0.8 maxSpeed:size*1.2 duration:_cloudDuration baseColor:baseColor]))
if ((self = [super initWithPosition:pos velocity:vel count:count minSpeed:size*0.8*spread maxSpeed:size*1.2*spread duration:_cloudDuration baseColor:baseColor]))
{
NSString *color_order = [_settings oo_stringForKey:kExplosionColors defaultValue:@"rgb"];

View File

@ -265,6 +265,8 @@ typedef enum
cloakPassive: 1, // cloak deactivates when main weapons or missiles are fired
cloakAutomatic: 1, // cloak activates itself automatic during attack
canFragment: 1, // Can it break into wreckage?
isWreckage: 1, // Is it wreckage?
_showDamage: 1, // Show damage?
suppressExplosion: 1, // Avoid exploding on death (script hook)
suppressAegisMessages: 1, // No script/AI messages sent by -checkForAegis,
isMissile: 1, // Whether this was launched by fireMissile (used to track submunitions).
@ -976,6 +978,8 @@ typedef enum
- (void) becomeLargeExplosion:(double) factor;
- (void) becomeEnergyBlast;
- (void) broadcastEnergyBlastImminent;
- (void) setIsWreckage:(BOOL)isw;
- (BOOL) showDamage;
- (Vector) positionOffsetForAlignment:(NSString*) align;
Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q, NSString* align);

View File

@ -298,6 +298,7 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
maxEnergy = [shipDict oo_floatForKey:@"max_energy" defaultValue:200.0f];
energy_recharge_rate = [shipDict oo_floatForKey:@"energy_recharge_rate" defaultValue:1.0f];
_showDamage = [shipDict oo_boolForKey:@"show_damage" defaultValue:(energy_recharge_rate > 0)];
// Each new ship should start in seemingly good operating condition, unless specifically told not to - this does not affect the ship's energy levels
[self setThrowSparks:[shipDict oo_boolForKey:@"throw_sparks" defaultValue:NO]];
@ -359,6 +360,8 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
// can it be 'mined' for alloys?
canFragment = [shipDict oo_fuzzyBooleanForKey:@"fragment_chance" defaultValue:0.9];
isWreckage = NO;
// can subentities be destroyed separately?
isFrangible = [shipDict oo_boolForKey:@"frangible" defaultValue:YES];
@ -2007,6 +2010,12 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
{
return NO;
}
if (isWreckage)
{
// wreckage won't collide
return NO;
}
if (isMissile && [self shotTime] < 0.25) // not yet fused
{
@ -2430,7 +2439,7 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
[self takeHeatDamage: delta_t * ship_temperature];
// are we burning due to low energy
if ((energy < maxEnergy * 0.20)&&(energy_recharge_rate > 0.0)) // prevents asteroid etc. from burning
if ((energy < maxEnergy * 0.20)&&_showDamage) // prevents asteroid etc. from burning
throw_sparks = YES;
// burning effects
@ -8796,9 +8805,9 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context)
double ecr = [e2 collisionRadius];
double d2 = magnitude2(p2) - ecr * ecr;
// limit momentum transfer to relatively sensible levels
if (d2 < 1.0)
if (d2 < 0.1)
{
d2 = 1.0;
d2 = 0.1;
}
double moment = amount*desired_range/d2;
[e2 addImpactMoment:vector_normal(p2) fraction:moment];
@ -8893,9 +8902,26 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context)
- (void) rescaleBy:(GLfloat)factor
{
// rescale mesh (and collision detection stuff)
[self setMesh:[[self mesh] meshRescaledBy:factor]];
_scaleFactor *= factor;
OOMesh *mesh = nil;
NSDictionary *shipDict = [self shipInfoDictionary];
NSString *modelName = [shipDict oo_stringForKey:@"model"];
if (modelName != nil)
{
mesh = [OOMesh meshWithName:modelName
cacheKey:[NSString stringWithFormat:@"%@-%.3f",_shipKey,_scaleFactor]
materialDictionary:[shipDict oo_dictionaryForKey:@"materials"]
shadersDictionary:[shipDict oo_dictionaryForKey:@"shaders"]
smooth:[shipDict oo_boolForKey:@"smooth" defaultValue:NO]
shaderMacros:OODefaultShipShaderMacros()
shaderBindingTarget:self
scaleFactor:factor];
if (mesh == nil) return;
[self setMesh:mesh];
}
// rescale subentities
Entity<OOSubEntity> *se = nil;
foreach (se, [self subEntities])
@ -8981,6 +9007,19 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context)
}
- (void) setIsWreckage:(BOOL)isw
{
isWreckage = isw;
}
- (BOOL) showDamage
{
return _showDamage;
}
- (void) becomeExplosion
{
@ -9010,6 +9049,7 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context)
int speed_low = 200;
GLfloat n_alloys = sqrtf(sqrtf(mass / 6000.0f));
NSUInteger numAlloys = 0;
BOOL canReleaseSubWreckage = isWreckage && ([UNIVERSE detailLevel] >= DETAIL_LEVEL_EXTRAS);
if ([self status] == STATUS_DEAD)
{
@ -9024,7 +9064,7 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context)
if (!suppressExplosion)
{
if (mass > 500000.0f && randf() < 0.25f) // big!
if (!isWreckage && mass > 500000.0f && randf() < 0.25f) // big!
{
// draw an expanding ring
OORingEffectEntity *ring = [OORingEffectEntity ringFromEntity:self];
@ -9164,7 +9204,7 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context)
// throw out burning chunks of wreckage
//
if (n_alloys && canFragment)
if ((n_alloys && canFragment) || canReleaseSubWreckage)
{
NSUInteger n_wreckage = 0;
@ -9173,42 +9213,27 @@ NSComparisonResult ComparePlanetsBySurfaceDistance(id i1, id i2, void* context)
// Create wreckage only when UNIVERSE is less than half full.
// (condition set in r906 - was < 0.75 before) --Kaks 2011.10.17
NSUInteger maxWrecks = 3;
// if it can cope with extra detail, allow more wreckage
if ([UNIVERSE detailLevel] >= DETAIL_LEVEL_EXTRAS)
if (n_alloys == 0)
{
maxWrecks = 8;
// must be sub-wreckage here
n_wreckage = (mass > 600.0 && randf() < 0.2)?2:0;
}
else
{
n_wreckage = (n_alloys < maxWrecks)? floorf(randf()*(n_alloys+2)) : maxWrecks;
}
n_wreckage = (n_alloys < maxWrecks)? floorf(n_alloys) : maxWrecks;
}
for (i = 0; i < n_wreckage; i++)
{
ShipEntity* wreck = [UNIVERSE newShipWithRole:@"wreckage"]; // retain count = 1
if (wreck)
{
GLfloat expected_mass = 0.1f * mass * (0.75 + 0.5 * randf());
GLfloat wreck_mass = [wreck mass];
GLfloat scale_factor = powf(expected_mass / wreck_mass, 0.33333333f); // cube root of volume ratio
[wreck rescaleBy: scale_factor];
Vector r1 = [octree randomPoint];
HPVector rpos = HPvector_add(vectorToHPVector(quaternion_rotate_vector([self normalOrientation], r1)), xposition);
[wreck setPosition:rpos];
[wreck setVelocity:[self velocity]];
Vector r1 = [octree randomPoint];
Vector dir = quaternion_rotate_vector([self normalOrientation], r1);
HPVector rpos = HPvector_add(vectorToHPVector(dir), xposition);
GLfloat lifetime = 750.0 * randf() + 250.0 * i + 100.0;
ShipEntity *wreck = [UNIVERSE addWreckageFrom:self withRole:@"wreckage" at:rpos scale:1.0 lifetime:lifetime/2];
[wreck setVelocity:vector_add([wreck velocity],vector_multiply_scalar(vector_normal(dir),randf()*[wreck collisionRadius]))];
quaternion_set_random(&q);
[wreck setOrientation:q];
[wreck setTemperature: 1000.0]; // take 1000e heat damage per second
[wreck setHeatInsulation: 1.0e7]; // very large! so it won't cool down
[wreck setEnergy: 750.0 * randf() + 250.0 * i + 100.0]; // burn for 0.25s -> 1.25s
[UNIVERSE addEntity:wreck]; // STATUS_IN_FLIGHT, AI state GLOBAL
[wreck performTumble];
[wreck rescaleBy: 1.0/scale_factor];
[wreck release];
}
}
n_alloys = randf() * n_alloys;
}
@ -11575,7 +11600,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
[shot setRange:hitAtRange];
Vector vd = vector_forward_from_quaternion([shot orientation]);
HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hitAtRange)));
[UNIVERSE addEntity:[OOFlashEffectEntity laserFlashWithPosition:flash_pos velocity:[victim velocity] color:laser_color]];
[UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:weapon_damage color:laser_color];
}
}
else
@ -11700,7 +11725,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
[shot setRange:hit_at_range];
Vector vd = vector_forward_from_quaternion([shot orientation]);
HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hit_at_range)));
[UNIVERSE addEntity:[OOFlashEffectEntity laserFlashWithPosition:flash_pos velocity:[victim velocity] color:laser_color]];
[UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:weapon_damage color:laser_color];
}
}
@ -11787,7 +11812,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
[shot setRange:hit_at_range];
Vector vd = vector_forward_from_quaternion([shot orientation]);
HPVector flash_pos = HPvector_add([shot position], vectorToHPVector(vector_multiply_scalar(vd, hit_at_range)));
[UNIVERSE addEntity:[OOFlashEffectEntity laserFlashWithPosition:flash_pos velocity:[victim velocity] color:laser_color]];
[UNIVERSE addLaserHitEffectsAt:flash_pos against:victim damage:weapon_damage color:laser_color];
}
}
else

View File

@ -524,6 +524,8 @@ enum
- (Entity*) hazardOnRouteFromEntity:(Entity *) e1 toDistance:(double)dist fromPoint:(HPVector) p2;
- (HPVector) getSafeVectorFromEntity:(Entity *) e1 toDistance:(double)dist fromPoint:(HPVector) p2;
- (ShipEntity *) addWreckageFrom:(ShipEntity *)ship withRole:(NSString *)wreckRole at:(HPVector)rpos scale:(GLfloat)scale lifetime:(GLfloat)lifetime;
- (void) addLaserHitEffectsAt:(HPVector)pos against:(ShipEntity *)target damage:(float)damage color:(OOColor *)color;
- (ShipEntity *) firstShipHitByLaserFromShip:(ShipEntity *)srcEntity inDirection:(OOWeaponFacing)direction offset:(Vector)offset gettingRangeFound:(GLfloat*)range_ptr;
- (Entity *) firstEntityTargetedByPlayer;
- (Entity *) firstEntityTargetedByPlayerPrecisely;

View File

@ -5473,6 +5473,67 @@ static BOOL MaintainLinkedLists(Universe *uni)
}
- (ShipEntity*) addWreckageFrom:(ShipEntity *)ship withRole:(NSString *)wreckRole at:(HPVector)rpos scale:(GLfloat)scale lifetime:(GLfloat)lifetime
{
ShipEntity* wreck = [UNIVERSE newShipWithRole:wreckRole]; // retain count = 1
Quaternion q;
if (wreck)
{
GLfloat expected_mass = 0.1f * [ship mass] * (0.75 + 0.5 * randf());
GLfloat wreck_mass = [wreck mass];
GLfloat scale_factor = powf(expected_mass / wreck_mass, 0.33333333f) * scale; // cube root of volume ratio
[wreck rescaleBy: scale_factor];
[wreck setPosition:rpos];
[wreck setVelocity:[ship velocity]];
quaternion_set_random(&q);
[wreck setOrientation:q];
[wreck setTemperature: 1000.0]; // take 1000e heat damage per second
[wreck setHeatInsulation: 1.0e7]; // very large! so it won't cool down
[wreck setEnergy: lifetime];
[wreck setIsWreckage:YES];
[UNIVERSE addEntity:wreck]; // STATUS_IN_FLIGHT, AI state GLOBAL
[wreck performTumble];
// [wreck rescaleBy: 1.0/scale_factor];
[wreck release];
}
return wreck;
}
- (void) addLaserHitEffectsAt:(HPVector)pos against:(ShipEntity *)target damage:(float)damage color:(OOColor *)color
{
// low energy, start getting small surface explosions
if ([target showDamage] && [target energy] < [target maxEnergy]/2)
{
NSString *key = (randf() < 0.5) ? @"oolite-hull-spark" : @"oolite-hull-spark-b";
NSDictionary *settings = [UNIVERSE explosionSetting:key];
OOExplosionCloudEntity* burst = [OOExplosionCloudEntity explosionCloudFromEntity:target withSettings:settings];
[burst setPosition:pos];
[self addEntity: burst];
if ([target energy] * randf() < damage)
{
ShipEntity *wreck = [self addWreckageFrom:target withRole:@"oolite-wreckage-chunk" at:pos scale:0.05 lifetime:(125.0+(randf()*200.0))];
if (wreck)
{
Vector direction = HPVectorToVector(HPvector_normal(HPvector_subtract(pos,[target position])));
[wreck setVelocity:vector_add([wreck velocity],vector_multiply_scalar(direction,10+20*randf()))];
}
}
}
else
{
[self addEntity:[OOFlashEffectEntity laserFlashWithPosition:pos velocity:[target velocity] color:color]];
}
}
- (ShipEntity *) firstShipHitByLaserFromShip:(ShipEntity *)srcEntity inDirection:(OOWeaponFacing)direction offset:(Vector)offset gettingRangeFound:(GLfloat *)range_ptr
{
if (srcEntity == nil) return nil;